做一个vue轮播图组件
根据huangyi老师的慕课网vue项目跟着做的,下面大概记录了下思路
1.轮播图的图
先不做轮播图逻辑部分,先把数据导进来,看看什么效果。在recommend组件新建一个recommends的数组,用这个数组来接受数据的录播图部分。然后再轮播图的插槽部分添加图片,代码如下
<slider>
<div v-for="(item,index) in recommends" :key="index">
<a :href="item.linkUrl">
<img :src="item.picUrl">
</a>
</div>
</slider>
// recommends.vue
<script>
data() {
return {
recommends: []
}
},
methods: {
_getRecommend() {
getRecommend().then(res => {
if (res.code === ERR_OK) {
this.recommends = res.data.slider
console.log(this.recommends)
}
)
}
},
</script>
但是现在轮播图是糊的,所以就要按着需求来自己做slider组件。
首先,我们给轮播图sliderGroup,设置一个总的宽度。
<div class="slider" ref="slider">
<div class="slider-group" ref="sliderGroup">
<slot></slot>
</div>
<div class="dots"></div>
</div>
要设置sliderGroup的宽度的话,我们要在渲染好dom元素的时候再设置宽度,所以我们要在mouted这个钩子函数里执行设置宽度,_setSliderWidth()和 _initSlider()分别是设置宽度和加入滚动效果。这里是为了分离,不让mounted这个钩子函数里有太多东西,然后不好改逻辑。
mounted() {
setTimeout(() => {
this._setSliderWidth()
this._initSlider()
}, 20)
},
下面就是设置SliderGroup的宽度,其实中我们设置的主要方法,就是把slider的宽度给sliderGroupd的每个children,其中的slider-item属性是让他们左浮动的。然后让他们超出来的都隐藏掉。然后最后因为loop是循环轮播,要给slider前后各加一个宽度,这个是基础了,不懂得百度轮播图原理。然后最后让sliderGroup的宽度变成通过slot传进来的图片加2的宽度。
methods: {
_setSliderWidth() {
this.children = this.$refs.sliderGroup.children
let width = 0
let sliderWidth = this.$refs.slider.clientWidth
for (let i = 0; i < this.children.length; i++) {
let child = this.children[i]
addClass(child, 'slider-item')
child.style.width = sliderWidth + 'px'
width += sliderWidth
}
if (this.loop) {
width += 2 * sliderWidth
}
this.$refs.sliderGroup.style.width = width + 'px'
}
}
addClass方法不是系统自带的,是自己定义的,放在项目的src/common/js/dom/js里
export function addClass(el, className) {
if (hasClass(el, className)) {
return
}
let newClass = el.className.split(' ')
newClass.push(className)
el.className = newClass.join(' ')
}
export function hasClass(el, className) {
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
return reg.test(el.className)
}
在设置完宽度以后,需要在recommend.vue设置一下加入addClass的时间,因为getRecommend这个方法是异步的,所以如果在dom渲染完后的时候在执行addclass方法,此时还没有获得到数据,所以也就没有slot里面的数据,所以要在slder组件外侧的div中设置一个v-if
<div v-if="recommends.length" class="slider-wrapper">
<slider>
<div v-for="(item,index) in recommends" :key="index">
<a :href="item.linkUrl">
<img :src="item.picUrl">
</a>
</div>
</slider>
</div>
当轮播图可以正确显示的时候,我们需要给轮播图添加滑动。我们用better-scroll,直接在npm上安装,然后在script标签里引入BScroll, 然后传入合适的参数,就可以了。
_initSlider() {
this.slider = new BScroll(this.$refs.slider, {
scrollX: true,
scrollY: false,
momentum: false,
snap: true,
snapLoop: this.loop,
snapThreshold: 0.3,
snapSpeed: 400,
click: true
})
}
2.轮播图的dots
首先,我们要通过children.length来新建dots,在哪里新建呢?在mounted里
mounted() {
setTimeout(() => {
this._setSliderWidth()
this._initDots()
this._initSlider()
}, 20)
}
然后顺应着新建一个_initDots方法,这样可以有效的分离,业务逻辑比较清晰。
_initDots() {
this.dots = new Array(this.children.length)
},
现在的程度是仅仅有dots的静态了(css做出样式),然后我们需要根据页面来设置active-dots。所以我们需要在_initSlider()方法中监听scrollEnd事件,这个时间是better-scroll的,如果没导入就没有。
this.slider.on('scrollEnd', () => {
let pageIndex = this.slider.getCurrentPage().pageX
// 这个pageIndex -1是因为前面有一张为了无缝连接轮播图的。需要把他弄掉
if (this.loop) {
pageIndex -= 1
}
this.currentPageIndex = pageIndex
})
然后配合js,我们在html绑定相应的class就行了。
<div class="dots">
<span
class="dot"
v-for="(item,index) in dots"
:key="index"
:class="{active:currentPageIndex === index}"
></span>
</div>
这样就就可以实现轮播带着dots一起动的效果了,接下来做自动播放功能
3. 轮播图自动播放
自动播放的时机,就是在新建轮播图完成的时候,也就是在mounted钩子里,定义一个_play方法
mounted() {
setTimeout(() => {
this._setSliderWidth()
this._initDots()
this._initSlider()
if (this.autoPlay) {
this._play()
}
}, 20)
}
然后我们顺着去找methods里定义_play()这个方法。
_play() {
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout(() => {
// 0 代表y方向,400表示间隔
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
但是这个在mounted钩子里,我们只调用了依次goToPage方法。这很不爽。所以需要我们在想办法,让每次换页的时候都去调用一下,拿着还不好说嘛,用上次的scrollEnd事件,所以只需要在上次那个地方添加一些方法就OK了
this.slider.on('scrollEnd', () => {
let pageIndex = this.slider.getCurrentPage().pageX
if (this.loop) {
pageIndex -= 1
}
this.currentPageIndex = pageIndex
if (this.autoPlay) {
clearTimeout(this.timer)
this._play()
}
})
OK,现在轮播图的dots,滑动,自动播放功能就完成了。下面是组件完整的代码
<template>
<div class="slider" ref="slider">
<div class="slider-group" ref="sliderGroup">
<slot></slot>
</div>
<div class="dots">
<span
class="dot"
v-for="(item,index) in dots"
:key="index"
:class="{active:currentPageIndex === index}"
></span>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
import { addClass } from 'common/js/dom'
export default {
data() {
return {
dots: [],
currentPageIndex: 0
}
},
props: {
// 是否可以循环轮播
loop: {
type: Boolean,
default: true
},
// 是否可以自动轮播
autoPlay: {
type: Boolean,
default: true
},
// 自动轮播时间间隔
interval: {
type: Number,
default: 4000
}
},
mounted() {
setTimeout(() => {
this._setSliderWidth()
this._initDots()
this._initSlider()
if (this.autoPlay) {
this._play()
}
}, 20)
window.addEventListener('resize', () => {
if (!this.silder) {
return
}
this._setSliderWidth(true)
this.slider.refresh()
})
},
methods: {
_setSliderWidth(isResize) {
this.children = this.$refs.sliderGroup.children
let width = 0
let sliderWidth = this.$refs.slider.clientWidth
for (let i = 0; i < this.children.length; i++) {
let child = this.children[i]
addClass(child, 'slider-item')
child.style.width = sliderWidth + 'px'
width += sliderWidth
}
if (this.loop && !isResize) {
width += 2 * sliderWidth
}
this.$refs.sliderGroup.style.width = width + 'px'
},
_initSlider() {
this.slider = new BScroll(this.$refs.slider, {
scrollX: true,
scrollY: false,
momentum: false,
snap: true,
snapLoop: this.loop,
snapThreshold: 0.3,
snapSpeed: 400,
click: true
})
this.slider.on('scrollEnd', () => {
let pageIndex = this.slider.getCurrentPage().pageX
if (this.loop) {
pageIndex -= 1
}
this.currentPageIndex = pageIndex
if (this.autoPlay) {
clearTimeout(this.timer)
this._play()
}
})
},
_initDots() {
this.dots = new Array(this.children.length)
},
_play() {
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout(() => {
// 0 代表y方向,400表示间隔
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
}
}
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">
@import '~common/stylus/variable'
.slider
min-height: 1px
.slider-group
position: relative
overflow: hidden
white-space: nowrap
.slider-item
float: left
box-sizing: border-box
overflow: hidden
text-align: center
a
display: block
width: 100%
overflow: hidden
text-decoration: none
img
display: block
width: 100%
.dots
position: absolute
right: 0
left: 0
bottom: 12px
text-align: center
font-size: 0
.dot
display: inline-block
margin: 0 4px
width: 8px
height: 8px
border-radius: 50%
background: $color-text-l
&.active
width: 20px
border-radius: 5px
background: $color-text-ll
</style>
做一个vue轮播图组件的更多相关文章
- Vue2 轮播图组件 slide组件
Vue2原生始轮播图组件,支持宽度自适应.高度设置.轮播时间设置.左右箭头按钮控制,圆点按钮切换,以及箭头.圆点按钮是否显示. <v-carousel :slideData="slid ...
- vue自定义轮播图组件 swiper
1.banner 组件 components/Banner.vue <!-- 轮播图 组件 --> <template> <div class="swiper- ...
- Vue实现音乐播放器(七):轮播图组件(二)
轮播图组件 <template> <div class="slider" ref="slider"> <div class=&qu ...
- vue移动音乐app开发学习(三):轮播图组件的开发
本系列文章是为了记录学习中的知识点,便于后期自己观看.如果有需要的同学请登录慕课网,找到Vue 2.0 高级实战-开发移动端音乐WebApp进行观看,传送门. 完成后的页面状态以及项目结构如下: 一: ...
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- 使用原生js将轮播图组件化
代码地址如下:http://www.demodashi.com/demo/11316.html 这是一个轮播图组件,这里是代码地址,需要传入容器的id和图片地址,支持Internet Explor ...
- 原生JS面向对象思想封装轮播图组件
原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...
- 03 uni-app框架学习:轮播图组件的使用
1.轮播图组件的使用 参照官方文档 2.在页面上加入这个组件 3.在页面中引去css样式 并编写样式 ps:upx单位是什么 简单来说 就相当于小程序中的rpx 是一个自适应的单位 会根据屏幕宽度自动 ...
- bootstrap轮播图组件
一.轮播图组件模板(官方文档) <div id="carousel-example-generic" class="carousel slide" dat ...
随机推荐
- C++ float vs double
精度 相比 float ,double 从其名字上已经展示出,它的精度是前者的两倍,他们的精度分别为: float: 7 位数字 double: 15 位数字 可通过如下的示例看出,在重复进行计算时, ...
- vscode解决nuget插件不能使用的问题
错误提示 使用vscode安装nuget插件之后出现错误: "Versioning information could not be retrieved from the NuGet pac ...
- C#基本语法<二>_线程
线程 多线程和异步函数 当异步线程在工作完成时如何通知调用线程 当异步线程出现异常的时候该如何处理 异步线程工作的进度如何实时的通知调用线程 如何在调用线程中取消正在工作的异步线程,并进行回滚操作 异 ...
- 解决MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk.问题
突然发现昨天刚搭建的websocket不能连接了,提示: MISCONF Redis is configured to save RDB snapshots, but it is currently ...
- ActiveMQ持久化到MySQL以及使用SSL协议通讯
最近公司事情稍微少了点,研究下怎么优化几个系统的交互,因为我们目前使用的是长链接的同步接口,就考虑用下MQ来处理下.由于公司对安全有要求且和CA业务有关,则使用了SSL协议.此文使用的是Activem ...
- 41-data-packed volume container
在上一节的例子中 volume container 的数据归根到底还是在 host 里,有没有办法将数据完全放到 volume container 中,同时又能与其他容器共享呢? 当然可以,通常我们称 ...
- filebench - File system and storage benchmark - 模拟生成各种各样的应用的负载 - A Model Based File System Workload Generator
兼容posix 接口的文件系统中我们不仅要测试 posix 接口是否兼容.随机读,随机写,顺序读,顺序写等读写模式下的性能.我们还要测试在不同工作负载条件下的文件系统的性能的情况:Filebench ...
- 算法复杂度O(logn)详解
一.O(logn)代码小证明 我们先来看下面一段代码: int cnt = 1; while (cnt < n) { cnt *= 2; //时间复杂度为O(1)的程序步骤序列 } 由于cnt每 ...
- myeclipse 9.0 破解方法,亲测可用
MyEclipse 9.0的破解方法,步骤如下: 1.破解公钥,确保MyEclipse没有开启,否则失败! 用WinRAR打开Common\plugins\com.genuitec.eclipse.c ...
- 201871010102-常龙龙《面向对象程序设计(java)》第十六周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...