轮播图组件
<template> <div class="slider" ref="slider"> <div class="slider-group" ref="sliderGroup"> //这里的<slot></slot>插槽表示里面的内容可以由引用这个轮播图组件的推荐组件来插入 只需要在<slider></slider>标签里面插入内容就可以把slot标签替换掉 <slot></slot> </div> <div class="dots"> </div> </div> </template>
推荐页面组件
<template> <div class="recommend"> <div class="recommend-content"> <!-- 因为我们的recommend是通过异步拿到的 可能会有延时 但是如果不加上v-if的话 我们可能在没有拿到数据的情况下就 把插槽插入进去了 那么slider.vue里面的mounted()也就执行了 --> <div class="slider-wrapper" v-if="recommend.length"> <slider> <!-- 填写插槽 --> <div v-for="(item,index) in recommend" :key="index"> <a :href="item.linkUrl"> <img :src="item.picUrl"> </a> </div> </slider> </div> <div class="recommend-list"> <h1 class="list-title">热门歌单推荐</h1> <ul></ul> </div> </div> </div> </template> <script> import Slider from '../../base/slider/slider.vue' import {getRecommend} from '../../api/recommend.js' import { ERR_OK } from '../../api/config.js' export default { data(){//为了将实例里面的轮播图数据与dom相关 要有一个data()方法 return { recommend:[] } }, created(){//一般在这个生命钩子里面加载数据 this._getRecommend() }, methods:{ _getRecommend(){ getRecommend().then((res)=>{//这个res就是我们抓取到的数据对象 因为getRecommend()方法返回的是一个promise对象 如果promise对象里面执行resolve()成功了 那么就会执行then里面的方法 if(res.code===ERR_OK){ // console.log(res.data.slider) this.recommend=res.data.slider } }) } }, components:{ //注册轮播图组件 Slider } } </script>
轮播图组件
<script> //引入better-scroll插件 import BScroll from 'better-scroll' //引入的这个方法是判断元素有没有传入该方法的类名 如果有的话就直接返回 如果没有的话就加上该类名 在轮播图组件中 添加的类名是.slider-item 这个类名的作用是让轮播图浮动 在一行显示 import {addClass} from '../../common/js/dom.js' export default { data(){ return { dots:[],//页面上的小点 将实例里面的dots数据与dom相关 需要有data方法 //定义当前是第几页 currentPageIndex:0 } }, props:{ loop:{ type:Boolean, default:true }, autoPlsy:{ type:Boolean, default:true }, interval:{//设置轮播时间间隔 type:Number, default:4000 } }, //什么时候初始化better-scroll呢? //如果better-scroll插件有问题可能是渲染时间(如数据还没加载完页面就渲染了)或者页面高度和宽度不对 //所以我们要在mouted()中调用获取轮播图 mounted(){ //知识点:通常我们要保证dom成功渲染的时候可以加个延时 //可以用this.nextstick() //也可以用setTineout() setTimeout(()=>{//可以延迟20ms 因为一般浏览器加载需要17ms this._setSliderWidth(); //设置轮播图的宽高等数据 // 这里要在前面渲染好 不然后面获取到的小圆点的数量就是已经经过better-scroll插件复制过的数目 this._initDots(); this._initSlider(); },20) //因为上面有个插槽slot在recommend.vue中插入数据 能够在slider.vue组件中渲染出来 //因为我们mouted()里面的方法是异步的 所以可能在操作dom的时候还没有渲染出来 浏览器就操作了 //所以我们在这里加个延时 就可避免此问题 //我们还要思考一个问题:就是我们mounted()的时候 slot里面的元素有没有 在推荐组件里面判断一下v-if="recommend.length"即可 }, methods:{ _setSliderWidth(){ //获取页面的dom元素的方法 this.$refs.名字 this.children=this.$refs.sliderGroup.children let width=0 let sliderWidth=this.$refs.slider.clientWidth console.log('sliderWidth',sliderWidth);//375 for(let i=0;i<this.children.length;i++){ let child=this.children[i]; //给每一个dom元素添加类名为slider-item addClass(child,'slider-item') //设置每一个child的宽度 每个child的宽度就等于总容器的宽度 child.style.width=sliderWidth+'px' //总的图片的宽度 这里后面一定不能加上'px'了 否则就是字符串的相加了 //就拿不到正确的数值了 width+=sliderWidth // console.log('width',width) } if(this.loop){//如果要做到无缝滚动的话 其实是在两侧加上了两张图片的宽度 //所以总的宽度就等于width+=2*sliderWidth 因为这里是用 //let 声明的child 考虑到作用域问题 所以在{}用2倍的sliderWidth比较合适 //sliderWidth就等于每张图片的宽度 width+=2*sliderWidth; } this.$refs.sliderGroup.style.width=width+'px' // console.log(this.$refs.sliderGroup) console.log('width....',width) }, //初始化轮播图 _initSlider(){ this.slider=new BScroll(this.$refs.slider,{ scrollX:true, scrollY:false, momentum:false, snap: { loop: this.loop, threshold: 0.3, speed: 400 } }) }, //初始化dots _initDots(){ this.dots=new Array(this.$refs.sliderGroup.children.length) } } } </script>