数据更改【=>dom diff -> 把虚拟dom传化为真实的dom ->$nextTick(在回调函数后真实) -> 告知浏览器绘制】
分割成3个件,BannerButton,BannerPagination,BannerPlugin
- 注意:组件命名采用驼峰式写法
- 解析关键词作用:template:每一个组件都有一个template,没有template也必须有rand,最起码要指定出我们的视图来
- data>return : 视图有了,就有数据,为了防止组件之间的数据冲突,把data用闭包包起来,
- template:`
:每一个组件只能有一个根节点,加上div,将button里面的内容加进来
<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>Documenttitle>
<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>
<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>
//分割成3个组件,BannerButton,BannerPagination,BannerPlugin
/*
* 注意:组件命名采用驼峰式写法
* 解析关键词作用:template:每一个组件都有一个template,没有template也必须有rand,最起码要指定出我们的视图来
* data>return : 视图有了,就有数据,为了防止组件之间的数据冲突,把data用闭包包起来,
* template:`:每一个组件只能有一个根节点,加上div,将button里面的内容加进来
*/
//=>左右切换按钮小组件
const BannerButton = {
template: ``,
data() {
return {}
},
methods:{
change(dir){
this.$emit('handle',dir)
}
}
};
//=>分页器小组件
const BannerPagination = {
template: `
`,
//=>注册组件
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: `
`,
//=>传递属性的校验(当前轮播图组件支持的参数配置)
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;
}