vue实践动态轮播图组件

    技术2025-02-06  22

    vue实践动态轮播图组件

    数据更改【=>dom diff -> 把虚拟dom传化为真实的dom ->$nextTick(在回调函数后真实) -> 告知浏览器绘制】

    分割成3个件,BannerButton,BannerPagination,BannerPlugin

    注意:组件命名采用驼峰式写法解析关键词作用:template:每一个组件都有一个template,没有template也必须有rand,最起码要指定出我们的视图来data>return : 视图有了,就有数据,为了防止组件之间的数据冲突,把data用闭包包起来,template:` :每一个组件只能有一个根节点,加上div,将button里面的内容加进来 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <link rel="stylesheet" href="css/reset.min.css"> <link rel="stylesheet" href="css/banner.css"> <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"> </head> <body> <!-- 数据更改【=>dom diff -> 把虚拟dom传化为真实的dom ->$nextTick(在回调函数后真实) -> 告知浏览器绘制】 --> <!-- 将div中的代码分割成3个组件: <section class="container"> <div class="wrapper"> <div class="slide"> <img src="./images/banner01.jpg" alt=""> </div> <div class="slide"> <img src="./images/banner02.jpg" alt=""> </div> <div class="slide"> <img src="./images/banner03.jpg" alt=""> </div> </div> <div class="pagination"> <span class="active"></span> <span></span> <span></span> </div> <a href="javascript:;" class="button-prev"></a> <a href="javascript:;" class="button-net"></a> </section> --> <!-- //调取通过属性传递,调取什么就传什么:init是初始值第一张,interval传递的时候--> <div id="app"> <banner-plugin v-if='bannerData' :data='bannerData' :interval='2000' :transitionend='transitionend' :speed='500' :pagination='false'></banner-plugin> <p>切换到<span v-text='temp'></span>张了 </p> </div> </body> <script src="../node_modules/vue/dist/vue.min.js"></script> <script src="../node_modules/axios/dist/axios.min.js"></script> <script src="axios.defaults.js"></script> <script src="banner-plugin.js"></script> <script> let vm = new Vue({ el: '#app', data: { //=> bannerData: [], temp:0 }, components: { BannerPlugin }, created() { //=>get请求banner,result从服务器获取结果 axios.get('/banner').then(result => { if (parseInt(result.code) === 0) { this.bannerData = result.data; } }); }, methods: { transitionend(example) { this.temp = example.activeIndex + 1; } } }); </script> </html>

    banner-plugin.js

    //分割成3个组件,BannerButton,BannerPagination,BannerPlugin /* * 注意:组件命名采用驼峰式写法 * 解析关键词作用:template:每一个组件都有一个template,没有template也必须有rand,最起码要指定出我们的视图来 * data>return : 视图有了,就有数据,为了防止组件之间的数据冲突,把data用闭包包起来, * template:`<div>:每一个组件只能有一个根节点,加上div,将button里面的内容加进来 */ //=>左右切换按钮小组件 const BannerButton = { template: `<div> <a href="javascript:;" class="button-prev" @click="change('left')"></a> <a href="javascript:;" class="button-net" @click="change('right')"></a> </div>`, data() { return {} }, methods:{ change(dir){ this.$emit('handle',dir) } } }; //=>分页器小组件 const BannerPagination = { template: `<div> <div class="pagination"> <span v-for='(item,i) in arr' :class="{active:activeHanle(i)}" @click="change(i)"></span> </div> </div>`, //=>注册组件 props:['total','index'], data(){ return { //=>.fill填充null arr : new Array (this.total).fill(null) } }, methods:{ activeHandle(){ //=>i是当前循环这一项的索引 //this.index:当前展示slide的索引 let temp = this.index === this.total ? 0 : this.index; return i === temp; }, change(i){ this.$emit('pagination',i); } } }; //=>轮播图大组件 const BannerPlugin = { template: ` <section class="container" @mouseenter='stopTimer(true)' @mouseleave='stopTimer()'> <div class="wrapper" :style='sty' ref='wrapper'> <div class="slide" v-for='item in bannerData'> <img :src='./images/banner02.jpg' alt=""> </div> </div> <banner-pagination v-if='pagination' :total='bannerData.length-1' :index='activeIndex' @pagination='handlePagination'> </banner-pagination> <banner-button v-if='button' @bandle='handleButton'></banner-button> </section>`, //=>传递属性的校验(当前轮播图组件支持的参数配置) props: { //=>data轮播图的数据 [{id:1,pic:'xxx.png',content:''},...] data: { type: Array, require: true }, //=>初始展示索引 initialsilde: { type: Number, default: 0 }, //=>运动间隔(如果值为0,则不开启自动轮播) interval: { type: Number, default: 3000 }, //=>每一次运动动画的时间 speed: { type: Number, default: 200 }, //=>是否设置分页器(默认一旦设定分页器,点击分页器也能是实现切换) pagination: { type: Boolean, default: true }, //=>是否设置左右导航 button: { type: Boolean, default: true }, //=>初始化成功的钩子函数 init: { type: Function, default: Function.prototype }, //=>切换完成后的钩子函数 transitionend: { type: Function, default: Function.prototype } }, components: { BannerPagination, BannerButton }, data() { //=>[...this.data]指的是把传递进来的数据克隆一份放在末尾 let bannerData = [...this.data, this.data[0]], //=>initialslide是当前选中的select索引值 activeIndex = this.initialslide; return { bannerData, activeIndex, //=>wrapper的样式 sty: { width: bannerData * 1000 + 'px', left: -activeIndex * 1000 + 'px', transition: `left ${this.speed}ms liner` } } }, methods: { autoMove() { this.activeIndex++; if (this.activeIndex >= this.bannerData.length) { this.sty.transition = `left 0ms liner`; this.sty.left = '0px'; //=>回调函数会在本次修改数据后,DOM数据渲染完成过后执行 this.$nextTick(() => { this.$refs.wrapper.offsetLeft; this.activeIndex = 1; this.sty.transition = `left ${this.speed}ms liner`; this.sty.left = -this.activeIndex * 1000 + 'px'; }); return; } this.sty.transition = `left ${this.speed}ms liner`; this.sty.left = -this.activeIndex * 1000 + 'px'; }, stopTimer(lx) { if (lx) { clearInterval(this.autoTimer); //清楚定时器 this.autoTimer = null; return; } this.$autoTimer = setInterval(this.autoMove, this.interval); }, //=>左右按钮切换 handleButton(dir) { if (dir === 'right') { this.autoMove(); return; } this.activeIndex--; if (this.activeIndex < 0) { this.sty.transition = `left 0ms liner`; this.sty.left = -(this.bannerData.length - 1) * 1000 + 'px'; //=>回调函数会在本次修改数据后,DOM数据渲染完成过后执行 this.$nextTick(() => { this.$refs.wrapper.offsetLeft; this.activeIndex = this.bannerData.length - 2; this.sty.transition = `left ${this.speed}ms liner`; this.sty.left = -this.activeIndex * 1000 + 'px'; }); return; } this.sty.transition = `left ${this.speed}ms liner`; this.sty.left = -this.activeIndex * 1000 + 'px'; }, handlePagination(i){ this.activeIndex = i; this.sty.transition = `left ${this.speed}ms liner`; this.sty.left = -this.activeIndex * 1000 + 'px'; } }, created() { // console.log(this) }, //=>第一次渲染完成,开始自动轮播 mounted() { this.$autoTimer = setInterval(this.autoMove, this.interval); //=>触发init钩子函数 this.init(this); }, updated() { //=>触发切换完的钩子函数 this.transitionend(this); } };

    banner.css

    .container { box-sizing:border-box; position:relative; margin:20px auto; width:1000px; height:270px; overflow:hidden; } .container .wrapper { position: absolute; top:0; left:0; display:flex; width:400%; height:100%; } .container .wrapper .slide { box-sizing :border-box; width:1000px; height:100%; } .container .wrapper .slide img { width: 100%; height:100%; } .container .pagination { position: absolute; right:20px; bottom:20px; z-index:999; font-size:0; } .container .pagination span{ display:inline-block; margin:0 4px; width:6px; height:6px; background: rgba(0,0,0,4); border: 2px solid rgba(255, 255, 255,4); border-radius:50%; cursor :pointer; } .container .pagination span.active { background: rgba(255, 255, 255,4); border-color:rgba(0,0,0,4); } .container .button-prev, .container .button-next { position: absolute; top:50%; margin-top:-35px; z-index:999; width:40px; height:70px; background: url("../images/icon.png") no-repeat; } .container .button-prev { left:0; background-position: -83px 0; } .container .button-prev:hover { background-position: 0 0; } .container .button-next { right:0; background-position: -124px 0; } .container .button-next:hover { background-position: -41px 0; }
    Processed: 0.009, SQL: 9