根据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轮播图组件的更多相关文章

  1. Vue2 轮播图组件 slide组件

    Vue2原生始轮播图组件,支持宽度自适应.高度设置.轮播时间设置.左右箭头按钮控制,圆点按钮切换,以及箭头.圆点按钮是否显示. <v-carousel :slideData="slid ...

  2. vue自定义轮播图组件 swiper

    1.banner 组件 components/Banner.vue <!-- 轮播图 组件 --> <template> <div class="swiper- ...

  3. Vue实现音乐播放器(七):轮播图组件(二)

    轮播图组件 <template> <div class="slider" ref="slider"> <div class=&qu ...

  4. vue移动音乐app开发学习(三):轮播图组件的开发

    本系列文章是为了记录学习中的知识点,便于后期自己观看.如果有需要的同学请登录慕课网,找到Vue 2.0 高级实战-开发移动端音乐WebApp进行观看,传送门. 完成后的页面状态以及项目结构如下: 一: ...

  5. iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  6. 使用原生js将轮播图组件化

    代码地址如下:http://www.demodashi.com/demo/11316.html   这是一个轮播图组件,这里是代码地址,需要传入容器的id和图片地址,支持Internet Explor ...

  7. 原生JS面向对象思想封装轮播图组件

    原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...

  8. 03 uni-app框架学习:轮播图组件的使用

    1.轮播图组件的使用 参照官方文档 2.在页面上加入这个组件 3.在页面中引去css样式 并编写样式 ps:upx单位是什么 简单来说 就相当于小程序中的rpx 是一个自适应的单位 会根据屏幕宽度自动 ...

  9. bootstrap轮播图组件

    一.轮播图组件模板(官方文档) <div id="carousel-example-generic" class="carousel slide" dat ...

随机推荐

  1. 设计院老师良心汇总:值得牢记的15个CAD基础技巧,能帮大忙

    哈喽!你们的CAD魔鬼(老师)来喽! 良心CAD技巧汇总,设计院师傅精心汇总,值得你牢记的15个CAD基础技巧,满满的都是干货,日常最常见的问题以及解决方法这里都汇总给你,给你高效的绘图体验,关键时刻 ...

  2. 关于如何获取项目所部署的本机IP和端口的问题

    关于如何获取项目所部署的本机IP和端口的问题 今天在写一个需求的时候碰到一个不常见的问题,在没有继承或者实现服务器提供的接口或者实现类的时候,比如说部署在tomacat上,某个类不去继承servelt ...

  3. 微信小程序新服务消息推送 —— 订阅消息

    微信团队前不久公测了「订阅消息」,原有的小程序模板消息接口将于 2020 年 1 月 10 日下线,届时将无法发送模板消息.「订阅消息」将完全替代「模板消息」,这两天得空测试了一波. 1.下发权限机制 ...

  4. 【C#】学习笔记(4) 值类型和引用类型相关(Null相关)

    Reference and Value Types Value Types(值类型): struct(结构体) 独立的实例或者是拷贝 值的改变不会影响其它拷贝 值就是它所代表的信息 没有引用,所以不可 ...

  5. python中字典

    字典中key:不可改变的数据类型 #fromkeys 快速定义一个空字典 res = {}.fromkeys([']) print(res) 定义字典: dict1 = { 'name1':'天明', ...

  6. mac环境下Python虚拟环境的安装和配置

    虚拟环境(virtualenv) 安装:在终端输入 pip install virtualenv 如果没安装pip会出现 pip: command not found,此时需要进行 sudo easy ...

  7. Linux内核和用户空间通信之netlink

    1. netlink Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. Netlink 是一种特殊的 socket,它 ...

  8. July 20th, 2019. Week 29th, Saturday

    If we just open the door a crack, the light comes pouring in. 只要把门开个小口,光就会倾泻而入. Don't be so disheart ...

  9. 【测试点】微信小程序的常见测试点

    第一次测试微信小程序,整理了一些必要的测试点和原则,以此为参考去设计详细测试用例

  10. 面向对象程序设计(JAVA) 第15周学习指导及要求

    2019面向对象程序设计(Java) 第15周学习指导及要求(2019.12.6-2019.12.13)   学习目标 (1) 掌握菜单组件用途及常用API: (2) 掌握对话框组件用途及常用API: ...