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>
<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() {
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
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 {
arr
: new Array (this.total
).fill(null)
}
},
methods
:{
activeHandle(){
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
: {
type
: Array
,
require
: true
},
initialsilde
: {
type
: Number
,
default: 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() {
let bannerData
= [...this.data
, this.data
[0]],
activeIndex
= this.initialslide
;
return {
bannerData
,
activeIndex
,
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';
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';
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() {
},
mounted() {
this.$autoTimer
= setInterval(this.autoMove
, this.interval
);
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
;
}