正文
最近的 react 项目需要使用轮播图, 自然而然的就想到了 swiper, 一直想通过 npm 安装的方式来使用, 但是网上找了很多, 资料很少, 于是就暂时通过在 index.html 里直接引用 swiper 的 js 和 CSS 文件的方式来加载, 下面来说一下具体的步骤和使用方法.
首先说一下我这里使用的是 swiper3x 系列. 接下来说具体的步骤:
在 index.html 中引入 js 和 css 文件
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <meta name="theme-color" content="#000000">
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" rel="external nofollow">
- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" rel="external nofollow">
- <link rel="stylesheet" type="text/css" href='%PUBLIC_URL%/static/css/swiper.min.css'>
- <title>React App</title>
- </head>
- <body>
- <div id="root"></div>
- <script src='%PUBLIC_URL%/static/js/swiper.min.js'></script>
- </body>
- </html>
当然, 我这个是将 js 和 css 文件下载到了本地, 你也可以使用 cdn 路径, 至此, 引入基本上算是引入完成了, 接下来就是如何在 react 组件中进行调用
在这里需要说一下, 引入的 js 文件在组件当中不能直接使用, 需要在最开始的位置声明一个变量, 后续的使用方法和普通的 html 写法就一致了, 区别就在于应该在哪个生命周期中写, 个人建议实在 componentDidUpdate 周期中进行写, 因为有时候数据是异步获取的, 刚刚完成时不一定数据获取完成, 数据获取完成以后更新 state, 此时会触发 update 周期.
- import React,{Component} from 'react'
- let Swiper = window.Swiper
- class About extends Component{
- constructor(props){
- super(props);
- this.state = {
- myName : "这里是 about 页面",
- }
- }
- componentWillUnmount() {
- if (this.swiper) { // 销毁 swiper
- this.swiper.destroy()
- }
- }
- componentDidUpdate(){
- if(this.swiper){
- this.swiper.slideTo(0, 0)
- this.swiper.destroy()
- this.swiper = null;
- }
- this.swiper = new Swiper(this.refs.lun, {
- loop:true,
- pagination: {
- el: '.swiper-pagination',
- clickable: true,
- },
- });
- }
- render(){
- return (
- <div>
- <div className="swiper-container" ref="lun">
- <div className="swiper-wrapper">
- <div className="swiper-slide" data-id="0">Slide 1</div>
- <div className="swiper-slide" data-id="1">Slide 2</div>
- <div className="swiper-slide" data-id="2">Slide 3</div>
- <div className="swiper-slide" data-id="3">Slide 4</div>
- <div className="swiper-slide" data-id="4">Slide 5</div>
- <div className="swiper-slide" data-id="5">Slide 6</div>
- <div className="swiper-slide" data-id="6">Slide 7</div>
- <div className="swiper-slide" data-id="7">Slide 8</div>
- <div className="swiper-slide" data-id="8">Slide 9</div>
- <div className="swiper-slide" data-id="9">Slide 10</div>
- </div>
- <div id="PgFather">
- <div className="swiper-pagination" id='body-left-pagination'></div>
- </div>
- </div>
- </div>
- )
- }
- }
- export default About
如此便完成了一个轮播的实现, 这里我写的 demo 只是将数据写死在了组件里, 一般情况应该是通过异步来进行获取数据.
其实, 这里还有一个问题, 就在于给 swiper-slide 添加点击事件, 一般来说是直接给 swiper-slide 这个 div 添加一个 onClick 事件, 但是问题就出现在了这里, 若这个轮播是可以循环轮播的话, swiper 会自动生成两个节点, 一个是第一个节点, 一个是最后一个节点, 分别放置于最后和最开始, 便于轮播联动. 然而他复制节点的时候, 无法复制其 onClick 的点击事件, 这就造成了当 swiper 初始化完成以后向左滑动第一个和向右滑动到最后一个再滑一次这两个节点是没有点击事件的. 于是我们就应该使用到 swiper 的回调函数了, 下面我们对构建 swiper 的方法进行改造一下.
- this.swiper = new Swiper(this.refs.lun, {
- loop:true,
- pagination: {
- el: '.swiper-pagination',
- clickable: true,
- onClick: function(swiper,e){
- var paginationContainer= document.getElementById('PgFather');
- var paginationFather = document.getElementById('body-left-pagination');
- // 这里是判断是否点击的轮播底部圆点, 因为方法在点击圆点的时候也会触发, 所以为了能保证点击圆点轮播效果, 应该将其屏蔽掉
- if(!this.isDOMContains(paginationFather,e.target,paginationContainer)){
- var se = document.querySelectorAll(".body-left-lunbo .swiper-slide");
- var nowNode = "";
- var index = swiper.activeIndex;
- if(index==0){
- index = se.length-3;
- }else if(index==se.length-1){
- index=0;
- }else{
- index = swiper.activeIndex-1;
- }
- if(self.state.swiperList.length===1){
- nowNode = se[0];
- }else{
- for(var i=0;i<se.length;i++){
- if(se[i].getAttribute('data-swiper-slide-index')==index){
- nowNode = se[i]
- }
- }
- }
- if(nowNode){
- var id= nowNode.getAttribute("data-id");
- var itemObj = {
- id:id
- }
- goDetail(itemObj,self.state.myName)
- return true
- }
- }else{
- return false
- }
- }
- },
- });
通过上面方法就可以实现了 swiper 的点击事件. 我上面的代码中补充了一种条件就是当 swiper 轮播节点只有一个的时候回出现点击无效的情况, 针对这一情况在方法里进行判断一下, 如果只有一个节点直接将节点 0 赋值给 nowNode 即可.
上面有一个判断是否点击的是底部圆的点判断我在下面贴出来供大家参考
- isDOMContains:function(parentEle,ele,container){
- console.log(parentEle)
- // 判断一个节点是否是其子节点
- //parentEle: 要判断节点的父级节点
- //ele: 要判断的子节点
- //container : 二者的父级节点
- // 如果 parentEle h 和 ele 传的值一样, 那么两个节点相同
- if(parentEle == ele){
- return true
- }
- if(!ele || !ele.nodeType || ele.nodeType != 1){
- return false;
- }
- // 如果浏览器支持 contains
- if(parentEle.contains){
- return parentEle.contains(ele)
- }
- // 火狐支持
- if(parentEle.compareDocumentPosition){
- return !!(parentEle.compareDocumentPosition(ele)&16);
- }
- // 获取 ele 的父节点
- var parEle = ele.parentNode;
- while(parEle && parEle != container){
- if(parEle == parentEle){
- return true;
- }
- parEle = parEle.parentNode;
- }
- return false;
- }
来源: http://www.jb51.net/article/140173.htm