Vue中使用swiper轮播图展示并可点击查看大图

原创
2017/07/25 14:57
阅读数 1.3K

最近一直使用vue开发,现需求是在首页展示轮播图,点击当前的轮播图可以展开相应的大图,大图要与点击的图片一致。

由于图片大小不一,在首页展示的图片定宽高,难免会出现图片拉抻或者显示不全,所以针对首页的轮播图使用背景图片进行设置,而点开的大图要求点击非图片区域才能关闭大图,所以大图需要使用img图片来进行设置;

由于图片的列表是后台,会出现三十张以上的图片的情况,为了性能问题,首次只加载三张,判断滑动防线,动态添加图片;

这里涉及到三个模块组件,引用轮播图的组件imageDemo.vue,轮播图组件tjImageViewer.vue,大图轮播图组件tjImageView.vue;目的是把轮播单独做成公共组件,需要的地方即可使用;

一下是对项目关键点的记录,方便以后swiper的开发使用;

  1. 安装swiper,引用swiper
    npm install swiper --save
    package.json中dependencies中会出现swiper以及其版本号 "swiper": "^3.4.2"

    swiper使用的地方并不是全局,不需要像网上的介绍,全局设置他,这样反倒会拖累整个项目性能,我们就是哪里需要他,就在那个模块里面引用他;
    直接在需要的模块这样引用即可  import swiper from 'swiper'
    这里需要注意一点,这样处理之后我发现页面中swiper的样式没有加载进来,如果你也在项目中发现swiper的样式并没有加载进来,可以去官网单独下载一个swiper-3.4.2.min.css,放到项目中,然后引用即可  import '@/assets/css/swiper-3.4.2.min.css'
     
  2. imageDemo.vue引用轮播图组件
    <template>
    
    	<div>
    		<tjImageView v-if="pictureList" :isShowImage=true :pictureList="pictureList"/>
    		<p>测试</p>
    	</div>
    	
    </template>
    
    <script>
    import tjImageView from '@/components/tjImageSwiper/tjImageViewer.vue'
    export default {
    	data(){
    		return{
    			"pictureList": [
    		      {
    		        "title": "图片1",
    		        "url": "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2934496992,3598063540&fm=11&gp=0.jpg",
    		        "albumUrl": "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2934496992,3598063540&fm=11&gp=0.jpg"
    		      },
    		      {
    		      	"title": "图片2",
    		        "url": "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2371473704,3551433037&fm=11&gp=0.jpg",
    		        "albumUrl": "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2371473704,3551433037&fm=11&gp=0.jpg"
    		      },
    		      {
    		      	"title": "图片3",
    		        "url": "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=18316473,2208919738&fm=26&gp=0.jpg",
    		        "albumUrl": "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=18316473,2208919738&fm=26&gp=0.jpg"
    		      },
    		      {
    		      	"title": "图片4",
    		        "url": "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2073957860,627365983&fm=26&gp=0.jpg",
    		        "albumUrl": "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2073957860,627365983&fm=26&gp=0.jpg"
    		      },
    		      {
    		      	"title": "图片5",
    		        "url": "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2426877307,3319849068&fm=26&gp=0.jpg",
    		        "albumUrl": "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2426877307,3319849068&fm=26&gp=0.jpg"
    		      }
        		]
    		}
    	},
    	components:{tjImageView},
    }
    </script>
    
    <style lang="scss" scoped>
    </style>
    注意:其中pictureList是轮播图片的数据,isShowImage来控制是否有点击查看大图的需要,只有这个字段为true时,点击小图才能查看大图,反之。。。。
     
  3. tjImageViewer.vue
    这里轮播图的大小为了适应各种分辨率的手机,保证宽高比例不变,使用css中的vw作为单位;用起来还是挺好用的,但是对于华为手机的默认的低版本浏览器还是差轻人意,这里处理的办法就是对轮播图的外框做了一个min-height的设置;
    由于在首页轮播,由于图片大小不一,只能使用背景图片的方式,取中间的一块;
    <template lang="html">
      <div >
      	<div class="index-image-box">
      		<!-- 头部轮播 -->
    
    	  	<div class="swiper-container">
              <div class="swiper-wrapper" >
                  <!-- <div class="swiper-slide" v-for="item in pictureList" :style="{backgroundImage:'url('+item.url+')'}" ref="swiperWrapper">
    
                  </div> -->
                  <template v-for="(item,n) in allPicList">
                  	<div :style="{backgroundImage:item.isLoadImage?'url('+item.url+')':''}" class="swiper-slide"></div>
                  </template>
              </div>
              <div class="swiper-pagination swiper-pagination-white"></div>
          	</div>
    
    	</div>
    
    	<!-- 显示大图 -->
    	<template v-if="isShowImage && nowShowImage">
    		<imageBigView :pictureList="pictureList" :initialIndex="initialIndex" @open="topen" :homeApiInfo="homeApiInfo" :preIndex="preIndex" :afterIndex="afterIndex"/>
    	</template>
    
      </div>
    </template>
    
    <script>
    
    import swiper from 'swiper'
    import '@/assets/css/swiper-3.4.2.min.css'
    import popupButton from '@/components/tjPopup/popupButton'
    import imageBigView from '@/components/tjImageSwiper/tjImageBigView'
    /**
     * isShowImage用来判断是否有显示大图的需求,如果有则true
     * nowShowImage用来判断当前动作是否要马上显示大图
     * 只有两者同时为true时,大图才会显示出来
     * pictureList图片信息
     * initialIndex展开的当前序号
     * homeApiInfo图片title标题信息,没有则不显示
     */
    export default {
    	name: 'carrousel',
    	props:['isShowImage',"pictureList"],
    
        data() {
          return {
          	options:{
    	        visible:false,	
    	      },
            nowShowImage:false,
            initialIndex:'',
            preIndex:'',
            afterIndex:'',
            homeApiInfo:[],
            picList:[],
            allPicList:[],
            len:'',
          }
        },
        created(){
        	let This = this;
        	This.len = This.pictureList.length-1;
        	This.pictureList.forEach(function(e,m){
        		if (m == 0 || m==1 || m == This.len) {
        			e.isLoadImage = true
        		}else{
        			e.isLoadImage = false
        		}
        		This.allPicList.push(e)
        	})
        },
        filters:{
        	filterUrl(data){
        		return ''
        	}
        },
        methods: {
        	topen(obj){
        		// 展示大图,控制前后图片同步
        		this.nowShowImage = obj;
        	},
        },
        components:{imageBigView},
        mounted() {
    
    		var swiper = new Swiper('.swiper-container', {
                pagination: '.swiper-pagination',
    	        loop: true,
    	        paginationType: 'fraction',
    	        initialSlide: 0,
    	        observer:true,
    	        observeParents:true,
    	        onClick: swiper => {
    	        	// isShowImage=true点击显示大图,如果false不显示
    	        	if (this.isShowImage) {
    		        	
    		        	let imgSum = swiper.slides.length-2;	//获取图片数量	
    		        	this.initialIndex = swiper.realIndex;	//显示大图展示,设置大图索引值
    		        	if (this.initialIndex == 0) {
    		        		this.preIndex = imgSum-1;
    		        		this.afterIndex = 1;
    		        	}else if (this.initialIndex == imgSum-1) {
    		        		this.preIndex = imgSum-2;
    		        		this.afterIndex = 0;
    		        	}else{
    		        		this.preIndex = this.initialIndex-1;
    		        		this.afterIndex = this.initialIndex+1;
    		        	}
    
    		        	// 判断是否有标题的字段,如果有,显示,如果无,不显示标题
    		        	let pictureData = this.pictureList; 
    		        	for (var i = 0; i < pictureData.length; i++) {
    		        		if (pictureData[i].title) {
    		        			this.homeApiInfo.push(pictureData[i].title)
    		        		}else{
    		        			this.homeApiInfo.push(" ");
    		        		}
    		        		
    		        	}
    					this.nowShowImage = true;
    		        }
    	        },
    	        onSlidePrevStart:swiper => {
    	        	let pre = 0;
    	        	if (swiper.activeIndex == 0 || swiper.activeIndex == 1 ) {
    	        		pre = this.len-1
    	        	}else{
    	        		pre = swiper.activeIndex -2
    	        	}
    
    	        	if (this.allPicList[pre].isLoadImage == true) {
    	        		return 
    	        	}else{
    	            	let obj = this.allPicList[pre];
    	            	obj.isLoadImage = true;
    	            	this.$set(this.allPicList,pre,obj)
    	        	}
    
    	        },
    	        onSlideNextStart:swiper =>{
    	        	let next = swiper.activeIndex+1>this.len?0:swiper.activeIndex+1;
    	        	if (this.allPicList[next].isLoadImage == true) {
    	        		return 
    	        	}else{
    	        		let obj = this.allPicList[next];
    	            	obj.isLoadImage = true;
    	            	this.$set(this.allPicList,next,obj)
    	        	}
    
    	        }
            });
        },
     }
    </script>
    
    <style lang="scss" scoped>
    .index-image-box{
    	width: 100vw;
    	height: 66.67vw;
    
    	.swiper-container{
    		width: 100%;
    		height: 100%;
    
    		.swiper-slide{
    			min-height: 250px;
    			background-size: cover;
    		    background-position: center;
    		    background-repeat: no-repeat;
    		}
    
    		.swiper-pagination{
    		    padding-right: 20px;
    		    text-align: right;
    		    color: #fff;
    		    bottom:10px;
    	        letter-spacing: -2px;
    		}
    	}
    }
    
    </style>
    

    注意:这里关于首先加载三张,然后左右滑动动态加载的做法:
    1.在组件渲染数据之前,对数据进行处理,也就是created中的方法,找出第一二张还有最后一张,如果第一次只显示一张图片的话,当滑动的过程中会出现空白的情况,所以第一次加载三张,滑动的时候去加载下一张的下一张就ok了;
    2.渲染图片的时候判断数据isLoadImage是否为true,如果为true则显示图片反之;
    3.至于Swiper中的用法,参考http://www.swiper.com.cn/api/即可;
    4.图片滑动的时候涉及到左滑右滑,这样就涉及到时加载哪张图片,具体看上面代码,自己在本子上划了一阵子感觉这么写是对的,当然 也没有测出bug啦;,比较恶心还是右滑动到最后一张,左滑动到第一张,汗!!!
    5.至于点开图片,进入到相应的大图,还是比较好处理的,swiper可以设置第一张图片的索引,即 initialSlide 属性;当触发swiper的onClick事件时候获取swiper.realIndex,然后传过去即可;
    6.这里还对大图的动态展示做了处理,也是需要默认展示三张,滑动动态添加,所以需要做一下计算,告诉大图,那三张是需要展示出来图片的;序号分别是 preIndex  initialIndex  afterIndex
    7.忽略标题那里的处理,有需求的话可以看一下
     

  4. tjImageView.vue
     

    <template lang="html">
    
    <transition name="modal" v-cloak id='myComponent'>
    
        <div class="big-image-box" v-if="bigImageList" @click="closeTip">
    
          <div class="modal-mask-background"></div>
    
          <div class="swiper-containerBig">
              <div class="swiper-wrapper">
                  <div class="swiper-slide" v-for="item in bigImageList" >
                    <img :src="item.albumUrl" v-if="item.isLoadImage">
                  </div>
              </div>
              <div class="swiper-pagination swiper-pagination-white"></div>
          </div>
    
          <!-- 图片房屋信息	 -->
      	 	<template v-if="homeApiInfo">
      	 		<div class="home-info z-bottomToTop">
      	  		<h3>{{homeInfo}}</h3>
      	  	</div>
        	</template>
        </div>
      </transition>
    
      
    </template>
    
    <script>
    
    import swiper from 'swiper'
    import '@/assets/css/swiper-3.4.2.min.css'
    import eventBus from '@/utils/eventBus'
    /**
     * pictureList 大图片列表
     * initialIndex 显示大图片索引值
     * homeApiInfo 标题数据
     */
    export default {
    	props:['pictureList',"initialIndex","homeApiInfo",'options','preIndex','afterIndex'],
        data() {
          return {
            isShowing:true,
            homeInfo:'',
            bigImageList:[]
          }
        },
        methods: {
    	    closeTip (e) {
            let nodeName = e.target.nodeName.toUpperCase();
            if (nodeName == 'IMG') {
              return false
            }else{
              // 禁止底部滚动
              eventBus.$emit('setPageDisableScroll',false)
              // 控制图片同步显示
              this.$emit('open', false)
            }
    	    },
    
        },
        mounted() {
            var swiper = new Swiper('.swiper-containerBig', {
                pagination: '.swiper-pagination',
                loop: true,
                paginationType: 'fraction',
                centeredSlides: true,
                spaceBetween: 30,
                initialSlide: this.initialIndex,
                observer:true,
                observeParents:true,
                centeredSlides: true,
                onTransitionStart: swiper => {
                  if (this.homeApiInfo) {
                    this.homeInfo = this.homeApiInfo[swiper.realIndex]
                  }
                },
                onSlidePrevStart:swiper => {
                  let pre = swiper.realIndex-2<0?swiper.realIndex+this.len-1:swiper.realIndex-2;
                  if (this.bigImageList[pre].isLoadImage == true) {
                    return 
                  }else{
                      let obj = this.bigImageList[pre];
                      obj.isLoadImage = true;
                      this.$set(this.bigImageList,pre,obj)
                  }
    
                },
                onSlideNextStart:swiper =>{
                  let next = swiper.realIndex+2>this.len?swiper.realIndex-this.len+1:swiper.realIndex+2;
                  if (this.bigImageList[next].isLoadImage == true) {
                    return 
                  }else{
                    let obj = this.bigImageList[next];
                      obj.isLoadImage = true;
                      this.$set(this.bigImageList,next,obj)
                  }
                  console.log(this.bigImageList[next].isLoadImage)
    
                }
            });
    
            eventBus.$emit('setPageDisableScroll',true)
        },
        created(){
    
          let This = this;
          This.len = This.pictureList.length-1;
          This.pictureList.forEach(function(e,m){
            if (m == This.initialIndex || m==This.preIndex || m ==This.afterIndex || m==This.preIndex-1 || m==0 || m==This.len) {
              e.isLoadImage = true
            }else{
              e.isLoadImage = false
            }
            This.bigImageList.push(e)
          })
        }
     }
    </script>
    
    <style lang="scss" scoped>
    
    .big-image-box{
      position: fixed;
      z-index: 9998;
      top: 0;
      left: 0;
      bottom:0;
      right: 0;
      transition: opacity .2s ease;
    }
    .image-content{
      width: 100%;
      height: 100%;
      margin: 0px auto;
      transition: opacity .3s ease;
    }
    
    .home-info{
    	position: absolute;
        bottom: 0;
        left: 0;
        color: #fff;
        z-index: 9;
        background-color: rgba(0,0,0,0.5);
        width: 100%;
        padding: 16px 20px;
        transition: opacity .2s ease;
    
        h3{font-size:16px;}
        p{margin-top:5px;font-size:13px;color:#999999}
    
    }
    
    .close{
    		position: absolute;
    	    right: 20px;
    	    z-index: 9;
    	    margin-top: 23px;
    }
    .modal-mask-background{
      position: absolute;
      width: 100%;
      height: 100%;
      transition: opacity .3s ease;
      background-color: rgba(0, 0, 0,.9);
    }
    .swiper-containerBig{
    	width: 100%;
    	height: 100%;
    
    	.swiper-slide{
    	    
          img{
            width: 100%;
            position: absolute;
            top:50%;
            transform: translateY(-50%);
            -ms-transform:translateY(-50%);   
            -moz-transform:translateY(-50%);  
            -webkit-transform:translateY(-50%); 
            -o-transform:translateY(-50%); 
          }
    	}
    
    	.swiper-pagination{
    	    color: #fff;
    	    position:fixed;
    		  top: 20px;
    		  display: flex;
    	    justify-content: center;
          height: 20px;
    	}
    }
    
    .swiper-slide:after{
          position: absolute;
          top: 0;
          left: 0;
          content: "";
          // background: url('../../assets/images/page-index/unit-background.png');
          z-index: 1;
          width: 100%;
          height: 20%;
          background-size: contain;
      }
    
    
    .modal-enter , .modal-leave-active{
      opacity: 1;
    }
    
    .modal-enter .modal-mask-background, .modal-leave-active .modal-mask-background{
      opacity: 0;
    }
    
    .modal-enter .z-bottomToTop,
    .modal-leave-active .z-bottomToTop {
      transform: translate3d(0,100%,0);
    }
    // .modal-enter .z-scale-transform,
    // .modal-leave-active .z-scale-transform {
    //   -webkit-transform: scale(1.1);
    //   transform: scale(1.1);
    // }
    </style>
    

    注意:处理过程差不多,也就那些,这里需要提到的是 大图展开的过程,使用了transition,为了展开时候有动画效果;具体百度吧;




    有问题,欢迎交流哈。。。。。
     

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部