Vue——图片轮播组件
Notices: 这是我一个项目中的一个子组件,要展示的数据、图片地址等的都在父组件data中。所以后面的讲述都是基于从父组件获取的参数进行处理。(如需将这个SlideShow写成一个单独的主组件,将本文使用的data写在这个组件的data中)必备知识:写轮播页面:HTML+CSSvue-cli:创建项目Vue基础:模板语法、计算属性、侦听器、渲染方式(条件渲染、列表渲染)、组件...
Notices: 这是我一个项目中的一个子组件,要展示的数据、图片地址等的都在父组件data中。所以后面的讲述都是基于从父组件获取的参数进行处理。(如需将这个SlideShow写成一个单独的主组件,将本文使用的data写在这个组件的data中)
必备知识:
- 写轮播页面:HTML+CSS
- vue-cli:创建项目
- Vue基础:模板语法、计算属性、侦听器、渲染方式(条件渲染、列表渲染)、组件
- 深入组件:组件注册、父子组件的交互方式、自定义事件
- vue过渡:进入、离开过渡
- CSS动画:CSS3 transfrom 属性
效果图:
组件构成:
- 利用Html 和 CSS 写一个基本的图片轮播页面
这部分很简单吧,常规的显示图片及轮播数字下标。CSS按照自己喜欢的样式随便调整。(最后面会给出我写的完整的CSS样式)
<!-- 布局 -->
<template>
<div class="slide-show">
<div class="slide-img" >
<a href="" >
<img src="" alt="">
</a>
</div>
<h3>{{ title }}</h3>
<ul class="slide-page" >
<li><</li>
<li>
<a href="">1</a>
<a href="">2</a>
<a href="">3</a>
</li>
<li>></li>
</ul>
</div>
</template>
- 加入响应式的数据驱动
(1)引入数据:
我这里轮播了三张图,需要多一点轮播的,直接加在data中。将轮播的三组数据放在sildes数组中。
我们父组件中的数据:
Tips: 这里加载图片的路径必须使用require引入,方便webpack打包。
data(){
return{
slides:[
{
src:require('../assets/slide1.jpg'),
title:"男人帮特色",
href:'detail/****'
},
{
src:require('../assets/slide2.jpg'),
title:"女神养成计划",
href:'detail/###'
},
{
src:require('../assets/slide3.jpg'),
title:"有腔调的品味",
href:'detail/###'
}
]
}
(2)数据驱动
依据slide数组,利用v-for列表渲染,v-bind绑定img的src等
随着nowIndex的动态变化显示不同的图片,在nowIndex初始化为0
(3)添加点击翻页等事件:左右箭头点击上下翻页、点击数字切换到相应的图片
在methods中定义跳转方法goto(index),跳转到index索引图片页
goto(index){
this.nowIndex = index
}
所以 上翻页只需要修改传入的参为preIndex,依据当前的index决定上翻页的Index,(第一页的上翻页为最后一页,考虑循环),所以这里利用计算属性computed;同理,下翻页。
computed:{
preIndex(){
if(this.nowIndex == 0){
return this.slides.length-1
}else{
return this.nowIndex - 1
}
},
nextIndex(){
if(this.nowIndex == this.slides.length-1){
return 0
}else{
return this.nowIndex + 1
}
}
}
(4)图片自动轮播
使用javascript的setInterval方法实现间隔10ms自动轮播 。指定的时间间隔重复执行代码。(鼠标放在图片上,需要停止动画效果,所以需要利用clearInterval()清除效果)
事件间隔在父级组件指定(v-bind绑定),利用props接收来自父级的数据
runInv需要在加载后调用,利用生命周期中的mounted实现调用
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
props:{
slides:{
type:Array,
default:[]//初始值为空
},
inv:{//父级传递
type:Number,
default:1000
}
},
methods:{
//幻灯片自动切换
runInv(){
this.invId = setInterval(()=>{
this.goto(this.nextIndex)
},this.inv)
},
clearInv(){
clearInterval(this.invId)
}
},
mounted(){
this.runInv()
}
- 定义动画
上面的轮播有点生硬,所以我们加上vue过渡效果。
有某一时刻是同时存在两张照片的(CSS中利用overflow:hidden隐藏溢出的图片),所以有两个<img>标签,利用v-if条件渲染让只有一个图片出现
<!-- 动画 -->
<transition name="slide-trans">
<img v-if="isShow" :src="slides[nowIndex].src" alt="slides[nowIndex].title">
</transition>
<transition name="slide-trans-old">
<img v-if="!isShow" :src="slides[nowIndex].src" alt="slides[nowIndex].title">
</transition>
.slide-trans-enter-active{
transition: all 1s;
}
.slide-trans-enter{
transform: translateX(1200px);
}
.slide-trans-old-leave-active{
transition: all 1s;
transform: translateX(-1200px);
}
vue组件完整代码:
<!-- 布局 -->
<template>
<div class="slide-show" @mouseover="clearInv" @mouseout="runInv">
<!-- v-for="item in slides" -->
<div class="slide-img" >
<a :href="slides[nowIndex].href" >
<!-- 动画 -->
<transition name="slide-trans">
<img v-if="isShow" :src="slides[nowIndex].src" alt="slides[nowIndex].title">
</transition>
<transition name="slide-trans-old">
<img v-if="!isShow" :src="slides[nowIndex].src" alt="slides[nowIndex].title">
</transition>
</a>
</div>
<h3>{{ slides[nowIndex].title }}</h3>
<ul class="slide-page" >
<li @click="goto(preIndex)"><</li>
<li v-for="(item,index) in slides" @click="goto(index)">
<a href="" :class="{on:index == nowIndex}">{{index + 1}}</a>
</li>
<li @click="goto(nextIndex)">></li>
</ul>
</div>
</template>
<script>
export default {
// props:子组件接受的什么属性
props:{
slides:{
type:Array,
default:[]//初始值为空
},
inv:{//父级传递
type:Number,
default:1000
}
},
data(){
return{
nowIndex:1,
isShow:true
}
},
computed:{
preIndex(){
if(this.nowIndex == 0){
return this.slides.length-1
}else{
return this.nowIndex - 1
}
},
nextIndex(){
if(this.nowIndex == this.slides.length-1){
return 0
}else{
return this.nowIndex + 1
}
}
},
methods:{
goto(index){
this.isShow = false
setTimeout(()=>{
this.isShow = true
this.nowIndex = index
//index传给父组件,实现交互
// this.$emit('onchange',index)
//
},10)
},
//幻灯片自动切换
runInv(){
this.invId = setInterval(()=>{
this.goto(this.nextIndex)
},this.inv)
},
clearInv(){
clearInterval(this.invId)
}
},
mounted(){
this.runInv()
}
}
</script>
<style scoped>
.slide-trans-enter-active{
transition: all 1s;
}
.slide-trans-enter{
transform: translateX(1200px);
}
.slide-trans-old-leave-active{
transition: all 1s;
transform: translateX(-1200px);
}
/* 淘宝css初始化 */
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button,
input, textarea, th, td { margin:0; padding:0; }
body, button, input, select, textarea { font:12px/1.5tahoma, arial, \5b8b\4f53; }
h1, h2, h3, h4, h5, h6{ font-size:100%; }
address, cite, dfn, em, var { font-style:normal; }
code, kbd, pre, samp { font-family:couriernew, courier, monospace; }
small{ font-size:12px; }
ul, ol { list-style:none; }
a { text-decoration:none; }
a:hover { text-decoration:underline; }
sup { vertical-align:text-top; }
sub{ vertical-align:text-bottom; }
legend { color:#000; }
fieldset, img { border:0; }
button, input, select, textarea { font-size:100%; }
table { border-collapse:collapse; border-spacing:0; }
.slide-show{
height: 400px;
width: 1200px;
position: relative;
overflow: hidden;
}
.slide-show h3{
width: 100%;
position: absolute;
color: #fff;
background-color: #000;
opacity: 0.7;
bottom: 0px;
padding: 10px 0px;
text-indent: 20px;
font-weight: 500;
}
.slide-img img{
width: 1200px;
position: absolute;
top: 0;
}
.slide-page{
right: 15px;
bottom: 0px;
position: absolute;
}
.slide-page .on{
text-decoration: underline;
}
.slide-page li{
list-style: none;
float: left;
display: inline-block;
padding: 0 10px;
cursor: pointer;
color: #fff;
font-size: 14px;
height: 32px;
}
.slide-page li a{
display: block;
float:left;
color: #fff;
text-decoration: none;
}
.slide-page li:hover{
color: #1fdd88;
}
.slide-page a:hover{
color: #1fdd88;
}
</style>
更多推荐
所有评论(0)