Swiper 反应 | 如何使用 React refs 创建自定义导航/分页组件?

mae*_*tin 7 swiper reactjs

SwiperJS 文档指出导航 prevEl/nextEl 可以是“字符串”或“HTMLElement”类型。使用字符串选择器很容易,因为:

const MySwiper = (props) => (
  <Swiper
    navigation={{
      prevEl: '.prev',
      nextEl: '.next',
    }}
    {...props}
  >
    <SwiperSlide>slide 1</SwiperSlide>
    <SwiperSlide>slide 2</SwiperSlide>
    <div className="prev" />
    <div className="next" />
  </Swiper>
)
Run Code Online (Sandbox Code Playgroud)

但是,如何使用 React refs 正确实现?使用 HTML 节点而不是字符串选择器允许将导航 prevEl/nextEl 范围限定为MySwiper.

const App = () => (
  <div>
    <MySwiper className="mySwiper1" />
    <MySwiper className="mySwiper2" />
  </div>
)
Run Code Online (Sandbox Code Playgroud)

在APP上面的例子,导航prevEl / Nextel公司从.mySwiper2应该不会引发滑动.mySwiper1,这将与字符串选择发生什么。

我目前的悲伤和hacky解决方法:

const MySwiper = () => {
  const navigationPrevRef = React.useRef(null)
  const navigationNextRef = React.useRef(null)

  return (
    <Swiper
      navigation={{
        // Both prevEl & nextEl are null at render so this does not work
        prevEl: navigationPrevRef.current,
        nextEl: navigationNextRef.current,
      }}
      onSwiper={(swiper) => {
        // Delay execution for the refs to be defined
        setTimeout(() => {
          // Override prevEl & nextEl now that refs are defined
          swiper.params.navigation.prevEl = navigationPrevRef.current
          swiper.params.navigation.nextEl = navigationNextRef.current

          // Re-init navigation
          swiper.navigation.destroy()
          swiper.navigation.init()
          swiper.navigation.update()
        })
      }}
    >
      <SwiperSlide>slide 1</SwiperSlide>
      <SwiperSlide>slide 2</SwiperSlide>
      <div ref={navigationPrevRef} />
      <div ref={navigationNextRef} />
    </Swiper>
  )
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*per 27

虽然Pierrat 的回答最初确实为我解决了这个问题,但我遇到了一个错误,导航按钮在我暂停并重新启动 Swiper 之前不会执行任何操作。

为了解决这个问题,我创建了自己的函数来处理更新并使用它们。

const MyComponent = () => {
  const sliderRef = useRef(null);

  const handlePrev = useCallback(() => {
    if (!sliderRef.current) return;
    sliderRef.current.swiper.slidePrev();
  }, []);

  const handleNext = useCallback(() => {
    if (!sliderRef.current) return;
    sliderRef.current.swiper.slideNext();
  }, []);

  return (
    <div>
      <Swiper ref={sliderRef}>
        <SwiperSlide />
        ...slides
        <SwiperSlide />
      </Swiper>
      <div className="prev-arrow" onClick={handlePrev} />
      <div className="next-arrow" onClick={handleNext} />
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)


小智 22

请注意 Amine D 示例中 onBeforeInit 的小错误。

更正的代码:

const MySwiper = () => {
  const navigationPrevRef = React.useRef(null)
  const navigationNextRef = React.useRef(null)
  return (
    <Swiper
      navigation={{
        prevEl: navigationPrevRef.current,
        nextEl: navigationNextRef.current,
      }}
     onBeforeInit={(swiper) => {
          swiper.params.navigation.prevEl = navigationPrevRef.current;
          swiper.params.navigation.nextEl = navigationNextRef.current;
     }}
    >
      <SwiperSlide>slide 1</SwiperSlide>
      <SwiperSlide>slide 2</SwiperSlide>
      <div ref={navigationPrevRef} />
      <div ref={navigationNextRef} />
    </Swiper>
  )
}
Run Code Online (Sandbox Code Playgroud)


Yas*_*ani 20

重要更新:Swiper v8.4.4

这个问题的大多数答案都涉及 API v6,但是更高版本(在撰写本答案时是 v8.4.4)例如没有 a相反,您应该直接从 swiper 实例swiper.params.navigation.prevEl访问属性,例如navigation所以:swiper.navigation.prevEl

这是使用 React v18 + Swiper v8.4.4 的更新示例(不推荐)

import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation } from 'swiper';

import 'swiper/css';

const Carousel = () => {
  const navigationNextRef = useRef(null);
  const navigationPrevRef = useRef(null);

  return (
    <div>
      <Swiper
        modules={[Navigation]}
        navigation={{
          prevEl: navigationPrevRef.current,
          nextEl: navigationNextRef.current,
        }}
        onBeforeInit={(swiper) => {
          swiper.navigation.nextEl = navigationNextRef.current;
          swiper.navigation.prevEl = navigationPrevRef.current;
        }}
      >
        <SwiperSlide>
          Slide 1
        </SwiperSlide>

        <SwiperSlide>
          Slide 2
        </SwiperSlide>
      </Swiper>
      <div>
        <button ref={navigationNextRef}>Next</button>
        <button ref={navigationPrevRef}>Prev</button>
      </div>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

参考滑动器并从任何您想要的地方控制它!

尽管上面的示例有效,但有时引用没有获得正确的值,因此您可以引用 swiper 本身并使用 和 控制它,而不是创建两个用于导航的引用和/或使用 a分配setTimeout()正确的值,请参阅James Hooper 的答案,您可以省略上述答案中的使用,如下所示:slideNext()slidePrev()useCallback()

import { useRef } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation } from 'swiper';

import 'swiper/css';

const Carousel = () => {
  const swiperRef = useRef();

  return (
    <div>
      <Swiper
        modules={[Navigation]}
        onBeforeInit={(swiper) => {
          swiperRef.current = swiper;
        }}
      >
        <SwiperSlide>Slide 1</SwiperSlide>
        <SwiperSlide>Slide 2</SwiperSlide>
      </Swiper>
      <div>
        <button onClick={() => swiperRef.current?.slidePrev()}>Prev</button>
        <button onClick={() => swiperRef.current?.slideNext()}>Next</button>
      </div>
    </div>
  );
};

Run Code Online (Sandbox Code Playgroud)

打字稿:

这是上面使用 Typscript 的相同示例:

/* eslint-disable import/no-unresolved */

// The rule above to shut ESLint from complaining
// about unresolved Swiper's CSS imports
// Why? see: https://github.com/import-js/eslint-plugin-import/issues/2266


import { useRef } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Swiper as SwiperType, Navigation } from 'swiper';

import 'swiper/css';

const Carousel = () => {
  const swiperRef = useRef<SwiperType>();

  return (
    <div>
      <Swiper
        modules={[Navigation]}
        onBeforeInit={(swiper) => {
          swiperRef.current = swiper;
        }}
      >
        <SwiperSlide>Slide 1</SwiperSlide>
        <SwiperSlide>Slide 2</SwiperSlide>
      </Swiper>
      <div>
        <button onClick={() => swiperRef.current?.slidePrev()}>Prev</button>
        <button onClick={() => swiperRef.current?.slideNext()}>Next</button>
      </div>
    </div>
  );
};

Run Code Online (Sandbox Code Playgroud)


小智 6

我想我解决了这个问题,我也遇到了同样的问题,但最后,让我们开始吧

 1. import SwiperCore, { Navigation} from 'swiper'
 2. SwiperCore.use([Navigation])
 3. i will use your exmaple:     

    const MySwiper = () => {
      const navigationPrevRef = React.useRef(null)
      const navigationNextRef = React.useRef(null)
      return (
        <Swiper
          navigation={{
            prevEl: navigationPrevRef.current,
            nextEl: navigationNextRef.current,
          }}
         onBeforeInit={{
              swiper.params.navigation.prevEl = navigationPrevRef.current;
              swiper.params.navigation.nextEl = navigationNextRef.current;
         }}
        >
          <SwiperSlide>slide 1</SwiperSlide>
          <SwiperSlide>slide 2</SwiperSlide>
          <div ref={navigationPrevRef} />
          <div ref={navigationNextRef} />
        </Swiper>
      )
    }
Run Code Online (Sandbox Code Playgroud)

就是这样,所以如果您检查 Swiper duc 有一个仅适用于 API 的页面,您可以在其中找到讨论 swiper 提供的事件的部分,无论如何我希望这是有帮助的

  • 问题是询问分页和导航! (3认同)

mae*_*tin 5

在 Swiper v6.2.0 中直接传递 ref 显然是不可能的。

我还为任何最终到达这里并由库作者回答的人创建了一个 Github 问题。 https://github.com/nolimits4web/swiper/issues/3855