当前位置: 首页 > Web前端 > vue.js

封装一个自己的轮播组件(基于Vue)

时间:2023-04-01 10:58:28 vue.js

创建目录结构vue-swiper/├──src/│├──components///内置组件│├──indicator.vue//指标组件││└──item.vue//单个轮播容器组件│├──main.js//项目导出│└──main.vue//组件导出├──README.md├──package.json└───vue.config.js//组件打包配置文件项目结构分析我们知道轮播是由它的容器和内容组成的,这里先将整个轮播组件拆分为入口组件和要使用的组件子组件(指示器组件可以可以根据自己的项目维护方式自由拆分,这里单独分开,方便日后维护)。以往我们在使用第三方组件时,可能会看到组件是一个单独的入口,所有的属性输入和事件监听都放在一个大组件上。维护方便,使用时不易发现问题。为了让组件本身更加语义化,方便后期组件在开发过程中的调试和维护,我们将容器和内容分离成两个组件。这样,用户在模板中编写组件时,就可以像普通的HTML标签一样进行嵌套。前提以前我们在页面上开发轮播图的时候,可能会涉及到很多手工的DOM样式操作。这里的问题是,我们关心的视图变化和逻辑操作都混在一起了,焦点没有分开。这种方式无论从维护还是代码的可读性都不是最优的。现在我们基于Vue开发这个组件,这样我们就可以利用它的核心思想(数据驱动的视图变化)来完成这个组件的开发。数据驱动动画有了数据驱动的主要思想,我们就可以围绕它开发组件。首先,初始化轮播动画中可以使用的状态变量。//main.vuedata(){return{reversing:false,//控制动画播放到首尾无缝跳转的开关swiperItemCount:0,//初始化传入轮播数量index:0//控制轮播当前位置的索引}},computed:{scrollItemCount(){//content中实际存在的图片数量returnthis.swiperItemCount+2//Component初始化后,我们需要复制第一个和最后两张图片传入到指定位置,所以这里需要加2}}之所以定义变量reversing,是因为动画播放到第一个和最后一个端点的时候,需要瞬间跳转到对应的第一个和最后一个Position,然后可以改变这个变量的值来关闭相应的动画,从而达到用户视觉上无缝滚动的效果。至于索引,它的语义大概已经描述了它要做的事情,就是改变这个索引的值来驱动图片的位置移动,这样就会有视觉上的动画效果。相关代码如下watch:{index(newIndex,oldIndex){constendIndex=this.scrollItemCount-1if(newIndex===endIndex&&newIndex>oldIndex){setTimeout(()=>{this.reversing=truethis.index=1setTimeout(()=>{this.reversing=false},100)},this.duration)}elseif(newIndex===0&&newIndex{this.reversing=truethis.index=endIndex-1setTimeout(()=>{this.reversing=false},100)},this.duration)}},}这里通过观察动画播放当前位置的变量,我们将改变它的值来实现整个包装容器的瞬间移动,同时也产生图片播放的连续动画效果。相关技术点前提是单张图片的内容是以slot的形式接收的(相关Api在这里,本文不做介绍),我们知道当前组件的$slot属性存储的是vnode(如果你不了解vnode,看这里,也不过多介绍)。匿名槽内容筛选有了slot,组件可以接受外界所有的内容,而我们这里只需要组件定义的指定子组件即可,所以组件启动后,需要重新处理默认的匿名槽。使用,让我们看看代码created(){this.$slots.default=this.$slots.default.filter(vnode=>{return(vnode.componentOptions&&vnode.componentOptions.tag==='swiper-item')//swiper-item依赖于注册的指定组件名})this.swiperItemCount=this.$slots.default.length},了解Vue虚拟DOM渲染原理的同学应该知道,vnode的每一次更新都会导致页面组件渲染,代码通过过滤将需要的vnode重新分配给接收匿名slot的接口,这样Vue会通过内部检测vnode的变化将新的vnode渲染到组件视图,进而调整content节点的结构。如何从外界复制第一张和最后一张图片。vnode有一个tag属性,存储了它渲染的真实DOM的引用,这样我们就可以通过相关的DOM操作API来复制这些节点,从而达到我们的目的。相关代码片段在这里mounted(){constfirstItem=this.$slots.default[0].elmconstlastItem=this.$slots.default[this.$slots.default.length-1].elmthis.$refs.wrapper.appendChild(firstItem.cloneNode(true))this.$refs.wrapper.insertBefore(lastItem.cloneNode(true),firstItem)this.autoplay&&this.play()},组件效果展示总结文章通过引入Vue数据驱动的思想一些动画效果,当我们想封装一些其他组件的时候,我们也可以利用这个来满足各种需求。至于组件其他功能的具体实现过程,这里就不做介绍了。感兴趣的同学可以查看本项目的Github仓库:good-swiper备注:本文归原作者所有,转载请注明出处,谢谢!