[Vue音乐项目] 第四节 轮播图
既然上节已经获取到数据,那么本节将使用轮播图展示这些数据,轮播图属于常用组件,可以独立成一个公共组件。
- 打开cmd命令行安装better-scroll(借助插件实现轮播图,后面也会用到)
npm install better-scroll --save-dev
- 在src/base目录下(没有的话先创建)创建slider目录,并在目录下创建slider.vue文件
轮播图原理:首先定义一个轮播图容器,内含两个div,一个存放图片的容器(图片组容器),另一个存放滚动点的容器(滚动点容器)。一般来说,轮播图容器宽度为设置好的轮播图宽度,而图片组宽度为轮播图宽度 * (轮播图数量+2),多出来的两个宽度用于复制第一个及最后一个轮播图,使得轮播效果顺滑不突兀。轮播图的要点是,图片组容器必须比轮播图容器宽度长,这是使得轮播图能够轮播的真正要点。//slider.vue 先简写html文件 <template> //轮播图容器,宽度一般为:轮播图宽度(或自定义宽度) <div class="slider" ref="slider"> //第4步提前写[1] //图片组容器,宽度一般为:轮播图宽度 * (轮播图数量+2) <div class="slider-group ref="sliderGroup"> //第4步提前写[2] //Vue插槽,由父组件放置轮播图 <slot></slot> </div> //滚动点容器,显示当前图片的序号 <div class="slider-dots> //当前图片对应的点会放大,滚动点的数量为轮播图的数量 <span class="dot" :class="active: current == index" v-for="(item,index) in dots" :key="index"> </span> 第4步提前写[3] </div> </div> </template> <script> ... </script> <style scoped lang="stylus"> .slider /* 轮播图样式提前写好 */ position: relative /* 设置相对定位,使得滚动点能够定位 */ min-height: 1px .slider-group position: relative /* 设置相对定位,使得能够滚动图片位置 */ overflow: hidden white-space: nowrap .slider-item /* 这是插槽里单个轮播图的样式,需要动态添加 */ float: left box-sizing: border-box overflow: hidden text-align: center img display: block width: 100% .slider-dots display: absolute /* 绝对定位 */ left: 0 /* left + right 使得元素宽度为父元素宽度 */ right: 0 bottom: 12px text-align: center /* text-align + font-size 使得子元素能够水平居中 */ font-size: 0 .dot display: inline-block width: 8px height: 8px border-radius: 50% /* 宽高相等 + 50%圆角 = 圆点 */ background-color: $color-text-l &.active /* 轮播图对应的滚动点,添加点特别的样式 */ width: 20px; border-radius: 5px background-color: $color-text-ll </style>
- 打开src/componnents/recommend/index.vue文件,目前还没有图片显示,接下在父组件导入该组件并放置轮播图。
//index.vue <template> <div class="recommend"> <div class="content"> //第二步,使用轮播图组件 <slider v-if="recommends"> //这里编写的内容将放入轮播图的插槽里,也是.slider-item应用的元素 <div v-for="(item,index) in recommends" :key="index"> //遍历图片地址并放入img标签里 <img :src="item.picUrl" alt=""> </div> </slider> <div class="list"> <!-- <h1>热门歌单推荐</h1> --> </div> </div> </div> </template <script> //第一步,导入轮播图组件 import slider from 'base/slider' export default { data() { return { //存放的轮播图数据,由jsonp函数获得 recommend: null } } } </script> <style> .... <style>
- 返回src/base/slider/index.vue文件,完成数据的填充后,开始编写逻辑代码让轮播图东起。
//index.vue <template> ... </template> <script> //导入better-scroll插件 import Srcoll from 'better-scroll' export default { //选择在vue实例挂载后执行,避免宽度获取不到的问题 mounted() { //第一步 设置轮播图宽度 this._initSliderWidth() //第二步 初始化轮播点 this._initDots() //第三步 启动轮播器,并监听其变化 this._initSlider() //第四步 自动播放[2] if(this.slider) { this._play() } }, methods: { //1.初始化轮播图容器,图片组容器,轮播图的宽度,并给轮播图添加样式 _initSliderWidth() { //有轮播图的数组引用,用到第2步提前写的ref(reference,即引用,实际是dom对象) //第1步提前写[1] this.children = this.$refs.sliderGroup.children //图片组容器的宽度 var width = 0; //轮播图容器的宽度 第1步提前写[2] var sliderWidth = this.$refs.slider.clientWidth for(let i=0; i<this.children.length; i++) { //给每个轮播图添加样式 addClass(this.children[i],'slider-item') //设置轮播图的宽度为轮播图容器的宽度 this.children[i].style.width = sliderWidth + 'px' //计算图片组容器的宽度 width += sliderWidth } //循环播放的话,加上两个轮播图的宽度 if(this.loop) { width += 2*sliderWidth } //给轮播图容器设置长度 this.$ref.sliderGroup.style.width = width + 'px' } //2.初始化滚动点 _initDots() { this.dots = new Array(this.children.length) } //3.启动轮播图 _initSlider() { //3.1 实例化better-scroll this.slider = new Scroll(this.$refs.slider,{ scrollX: true, //滚动x轴 scrollY: false, momentum: false, snap: { loop: this.loop, threshold: 0.3, speed: 400 }, click: true }) //3.2 监听better-scroll,改变滚动点的样式 第1步提前写[3] this.slider.on('srcollEnd',function(){ //更新当前图片索引 thish.current = this.slider.getCurrentPage().scrollX //自动播放[3] if(this.autoplay) { clearTimeout(timer) this._play() } }) } 4. 自动播放[1] _play() { //获取下一张图片的索引 var next = (this.current + 1) > 4 ? 0 : this.current + 1 //设置定时器 ps:使用timeout而不是interval this.timer = setTimeout(()=>{ this.slider.goToPage(next,0,400) },this.interval) } }, destroyed() { //自动播放[4] : 组件销毁时,清楚定时器 clearTimeout(this.timer) } } </script> <style> ... </style>