一、理清思路,理解需求和原理

1. 要写一个什么样的轮播?

  1. 在点击右侧箭头时,图片向左滑动到下一张;点击左侧箭头时,图片向右滑到下一张
  2. 点击下面的小圆点,滑到对应的图片,相应小圆点的样式也发生改变
  3. 要有过渡效果,要缓缓滑动过去
  4. 当鼠标hover到图片上时,轮播暂停,当鼠标leave时,轮播继续
  5. 自动播放功能
  6. 无限滚动,即在滚动到最后一张时,再点击下一张时会继续向左滑动到第一张,而不是整个拉到第一张,这里有点难

2. 理解无限轮播的原理

我们先看下原理图:

图中红线区域即是我们看到的图片,这个轮播只展示5张图片,但是在它的首尾各还有两张图片,在图1前面放置了图5,在图5后面放置了图1,之所以这么做,是为了做无限滚动。无限滚动的原理在于:当整个图向左侧滚动到右边的图5时,会继续向前走到图1,在完全显示出图1后,会以肉眼看不到的速度向右侧拉回到最左边的图1。 这样,即使再向左侧滑动看到的就是图2了。

如下图:在最后的图1完成过渡完全显示出来后,再将整个列表瞬间向右拉到左侧的图1。另一张边界图图5的滚动也是,不过方向相反。

二、先让图片切换起来

1. 布局和准备

<template>
<div id="slider">
<div class="window"> // window上图中红线框
<ul class="container" :style="containerStyle"> //注意这里的:style //这是图片列表,排成一排
<li> //列表最前面的辅助图,它和图5一样,用于无限滚动
<img :src="sliders[sliders.length - 1].img" alt="">
</li>
<li v-for="(item, index) in sliders" :key="index"> //通过v-for渲染的需要展示的5张图
<img :src="item.img" alt="">
</li>
<li> //列表最后面的辅助图,它和图1一样,用于无限滚动
<img :src="sliders[0].img" alt="">
</li>
</ul>
<ul class="direction"> //两侧的箭头
<li class="left">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M481.233 904c8.189 0 16.379-3.124 22.628-9.372 12.496-12.497 12.496-32.759 0-45.256L166.488 512l337.373-337.373c12.496-12.497 12.496-32.758 0-45.255-12.498-12.497-32.758-12.497-45.256 0l-360 360c-12.496 12.497-12.496 32.758 0 45.255l360 360c6.249 6.249 14.439 9.373 22.628 9.373z" /></svg>
</li>
<li class="right">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M557.179 904c-8.189 0-16.379-3.124-22.628-9.372-12.496-12.497-12.496-32.759 0-45.256L871.924 512 534.551 174.627c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0l360 360c12.496 12.497 12.496 32.758 0 45.255l-360 360c-6.249 6.249-14.439 9.373-22.628 9.373z" /></svg>
</li>
</ul>
<ul class="dots"> //下面的小圆点
<li v-for="(dot, i) in sliders" :key="i"
:class="{dotted: i === (currentIndex-1)}"
>
</li>
</ul>
</div>
</div>
</template> <script>
export default {
name: 'slider',
data () {
return {
sliders:[
{
img:'../../static/images/1.jpg'
},
{
img:'../../static/images/2.jpg'
},
{
img:'../../static/images/3.jpg'
},
{
img:'../../static/images/4.jpg'
},
{
img:'../../static/images/5.jpg'
}
],
currentIndex:1,
distance:-600
}
},
computed:{
containerStyle() { //这里用了计算属性,用transform来移动整个图片列表
return {
transform:`translate3d(${this.distance}px, 0, 0)`
}
}
}
}
</script>

好了,布局大概就是这样,效果图如下

上面的代码已经做了注释,有几个点在这里再提一下:

  • window是红线框,宽度为600px,它不会动,移动的是包裹着图片的container,它的移动方式用:style="containerStyle",这是一个计算属性,用transform:translate3d(${this.distance, 0, 0})来控制左右移动
  • data里的distancecurrentIndex是关键,distance控制着移动的距离,默认是-600,显示7张图片中的第二张,也就是图1。currentIndex是window显示的图片的索引,这里默认是1,也是7张图片中第2张。
  • 需要展示的只有5张图片,但是在图1前了一张图5、在图5后面放了一张图1来做无限滚动,原理前面说过了
  • 当点击右侧的箭头,container向左移动,distance会越来越小;当点击左侧的箭头,container向右移动,distance会越来越大,方向不要弄错

2. 图片切换

我们在左侧和右侧的箭头上添加点击事件:

      <ul class="direction">
<li class="left" @click="move(600, 1)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M481.233 904c8.189 0 16.379-3.124 22.628-9.372 12.496-12.497 12.496-32.759 0-45.256L166.488 512l337.373-337.373c12.496-12.497 12.496-32.758 0-45.255-12.498-12.497-32.758-12.497-45.256 0l-360 360c-12.496 12.497-12.496 32.758 0 45.255l360 360c6.249 6.249 14.439 9.373 22.628 9.373z" /></svg>
</li>
<li class="right" @click="move(600, -1)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M557.179 904c-8.189 0-16.379-3.124-22.628-9.372-12.496-12.497-12.496-32.759 0-45.256L871.924 512 534.551 174.627c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0l360 360c12.496 12.497 12.496 32.758 0 45.255l-360 360c-6.249 6.249-14.439 9.373-22.628 9.373z" /></svg>
</li>
</ul> ...... methods:{
move(offset, direction) {
this.distance += this.distance * direction
if (this.distance < -3000) this.distance = -600
if (this.distance > -600) this.distance = -3000
}
}
解释下上面的代码:点击左侧或者右侧的箭头,调用move函数,move接收偏移量offset和方向direction两个参数。direction只传两个值,1表示container向右移动,-1表示container向左移动;偏移量是600,也就是一张图片的宽度。如果移动到7张图片的最后一张,就把container拉到7张图片里的第二张;如果移动到7张图片里第一张,就把container拉到7张图片里的第5张。

可以看到,图片切换效果已经出来了,但是下面的小圆点没有跟着变换。接下来我们把这个效果加上。从上面的html代码可以看到,:class="{dotted: i === (currentIndex - 1)}",小圆点的切换效果和data里的currentIndex值相关,我们只要随着图片切换变动currentIndex值就可以了。

修改move方法里的代码:

......

move(offset, direction) {
direction === -1 ? this.currentIndex++ : this.currentIndex--
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5
this.distance = this.distance + offset * direction
if (this.distance < -3000) this.distance = -600
if (this.distance > -600) this.distance = -3000
}

上面的添加的三行代码很好理解,如果是点击右侧箭头,container就是向左移动,this.currentIndex就是减1,反之就是加1。可以看到,小圆点的切换效果已经出来了。

三、过渡动画

上面的代码已经实现了切换,但是没有动画效果,显的非常生硬,接下来就是给每个图片的切换过程添加过渡效果。

这个轮播组件笔者并没有使用Vue自带的class钩子,也没有直接使用css的transition属性,而是用慕课网原作者讲的setTimeout方法加递归来实现。

其实我也试过使用Vue的钩子,但是总有一些小问题解决不掉;比如下面找到的这个例子:例子

这个例子在过渡的边界上有一些问题,我也遇到了,而且还是时有时无。而如果使用css的transition过渡方法,在处理边界的无限滚动上总会在chrome浏览器上有一下闪动,即使添加了-webkit-transform-style:preserve-3d;-webkit-backface-visibility:hidden也还是没用,而且要配合transition的transitionend事件对于IE浏览器的支持也不怎么好。

如果大家有看到更好的办法,请在评论中留言哦~

下面我们来写这个过渡效果,主要是改写:

methods:{
move(offset, direction) {
direction === -1 ? this.currentIndex++ : this.currentIndex--
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5 const destination = this.distance + offset * direction
this.animate(destination, direction)
},
animate(des, direc) {
if ((direc === -1 && des < this.distance) || (direc === 1 && des > this.distance)) {
this.distance += 30 * direc
window.setTimeout(() => {
this.animate(des, direc)
}, 20)
} else {
this.distance = des
if (des < -3000) this.distance = -600
if (des > -600) this.distance = -3000
}
}
}

上面的代码是这个轮播我觉得最麻烦、也是最难理解的地方。

来理解一下:首先,我们对于move方法进行了改写,因为要一点点的移动,所以要先算出要移动到的目标距离。然后,我们写一个animate函数来实现这个过渡。这个animate函数接收两个参数,一个是要移动到的距离,另一个是方向。如果我们点击了右侧的箭头,container要向左侧移动,要是没有移动到目标距离,就在this.distance减去一定的距离,如果减去后还是没有到达,在20毫米以后再调用这个this.animate,如此不断移动,就形成了过渡效果。而如果移动到了目标距离,那就将目标距离赋值给this.distance,然后再进行边界和无限滚动的判断。

当然,使用window.setInterval()也可以实现这个效果,而且会稍微好理解一点,因为没有用到递归:

methods:{
move(offset, direction) {
direction === -1 ? this.currentIndex++ : this.currentIndex--
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5 const destination = this.distance + offset * direction
this.animate(destination, direction)
},
animate(des, direc) {
const temp = window.setInterval(() => {
if ((direc === -1 && des < this.distance) || (direc === 1 && des > this.distance)) {
this.distance += 30 * direc
} else {
window.clearInterval(temp)
this.distance = des
if (des < -3000) this.distance = -600
if (des > -600) this.distance = -3000
}
}, 20)
}
}

实现出来的效果如下:

四、简单节流一下

写到这里,效果是出来了,但是会有一点问题,如果多次快速点击,就会有可能出现下面这种情况:

出现这种情况的原因很简单,因为是使用定时器过渡,所以连续快速点击就会出现错乱,简单节流一下就好了:在过渡完成之前点击箭头无效,其实就是设了一个闸,第一次点击把闸打开,在闸再次打开之前,让一部分代码无法执行,然后再在恰当的时机把闸打开。

我们把这个闸设在move函数里:

move(offset, direction) {
if (!this.transitionEnd) return //这里是闸
this.transitionEnd = false //开闸以后再把闸关上
direction === -1 ? this.currentIndex++ : this.currentIndex--
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5 const destination = this.distance + offset * direction
this.animate(destination, direction)
}

this.transitionEnd是这个闸的钥匙,我们把它放到data里:

this.transitionEnd: true

这个闸一开始默认的状态是开着的,第一次点击以后,这个闸就关上了,this.tranisitonEnd = false,在再次打开之前,后面的代码都执行不了。接下来就是在恰当的时机把这个闸打开,而这个恰当的时机就是过渡完成时,也就是在animate函数里:

animate(des, direc) {
if (this.temp) {
window.clearInterval(this.temp)
this.temp = null
}
this.temp = window.setInterval(() => {
if ((direc === -1 && des < this.distance) || (direc === 1 && des > this.distance)) {
this.distance += 30 * direc
} else {
this.transitionEnd = true //闸再次打开
window.clearInterval(this.temp)
this.distance = des
if (des < -3000) this.distance = -600
if (des > -600) this.distance = -3000
}
}, 20)
}

这下快速点击就没有之前的那个问题了

五、点击小圆点实现图片过渡切换

到目前为止的代码:

<template>
<div id="slider">
<div class="window">
<ul class="container" :style="containerStyle">
<li>
<img :src="sliders[sliders.length - 1].img" alt="">
</li>
<li v-for="(item, index) in sliders" :key="index">
<img :src="item.img" alt="">
</li>
<li>
<img :src="sliders[0].img" alt="">
</li>
</ul>
<ul class="direction">
<li class="left" @click="move(600, 1)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M481.233 904c8.189 0 16.379-3.124 22.628-9.372 12.496-12.497 12.496-32.759 0-45.256L166.488 512l337.373-337.373c12.496-12.497 12.496-32.758 0-45.255-12.498-12.497-32.758-12.497-45.256 0l-360 360c-12.496 12.497-12.496 32.758 0 45.255l360 360c6.249 6.249 14.439 9.373 22.628 9.373z" /></svg>
</li>
<li class="right" @click="move(600, -1)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M557.179 904c-8.189 0-16.379-3.124-22.628-9.372-12.496-12.497-12.496-32.759 0-45.256L871.924 512 534.551 174.627c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0l360 360c12.496 12.497 12.496 32.758 0 45.255l-360 360c-6.249 6.249-14.439 9.373-22.628 9.373z" /></svg>
</li>
</ul>
<ul class="dots">
<li v-for="(dot, i) in sliders" :key="i"
:class="{dotted: i === (currentIndex-1)}"
>
</li>
</ul>
</div>
</div>
</template> <script>
export default {
name: 'slider',
data () {
return {
sliders:[
{
img:'../../static/images/1.jpg'
},
{
img:'../../static/images/2.jpg'
},
{
img:'../../static/images/3.jpg'
},
{
img:'../../static/images/4.jpg'
},
{
img:'../../static/images/5.jpg'
}
],
currentIndex:1,
distance:-600,
transitionEnd: true
}
},
computed:{
containerStyle() {
return {
transform:`translate3d(${this.distance}px, 0, 0)`
}
}
},
methods:{
move(offset, direction) {
if (!this.transitionEnd) return
this.transitionEnd = false
direction === -1 ? this.currentIndex++ : this.currentIndex--
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5 const destination = this.distance + offset * direction
this.animate(destination, direction)
},
animate(des, direc) {
if (this.temp) {
window.clearInterval(this.temp)
this.temp = null
}
this.temp = window.setInterval(() => {
if ((direc === -1 && des < this.distance) || (direc === 1 && des > this.distance)) {
this.distance += 30 * direc
} else {
this.transitionEnd = true
window.clearInterval(this.temp)
this.distance = des
if (des < -3000) this.distance = -600
if (des > -600) this.distance = -3000
}
}, 20)
}
}
}
</script>

接下来我们要实现点击下面的小圆点来实现过渡和图片切换。

<ul class="dots">
<li v-for="(dot, i) in sliders" :key="i"
:class="{dotted: i === (currentIndex-1)}"
@click = jump(i+1)>
</li>
</ul>

在点击小圆点的时候我们调用jump函数,并将索引i+1传给它。这里需要特别注意,小圆点的索引和图片对应的索引不一致,图片共7张,而5个小圆点对应的是图片中中间的5张,所以我们才传i+1

jump(index) {
const direction = index - this.currentIndex >= 0 ? -1 : 1 //获取滑动方向
const offset = Math.abs(index - this.currentIndex) * 600 //获取滑动距离
this.move(offset, direction)
}

上面的代码有一个问题,在jump函数里调用move方法,move里对于currentIndex的都是+1,而点击小圆点可能是将currentIndex加或者减好多个,所以要对move里的代码修改下:

direction === -1 ? this.currentIndex += offset/600 : this.currentIndex -= offset/600

改一行,根据offset算出currentIndex就行了。

但是又有一个问题,长距离切换速度太慢,如下:

所以我们需要控制一下速度,让滑动一张图片耗费的时间和滑动多张图片耗费的时间一样,给move和animate函数添加一个speed参数,还要再算一下:

jump(index) {
const direction = index - this.currentIndex >= 0 ? -1 : 1
const offset = Math.abs(index - this.currentIndex) * 600
const jumpSpeed = Math.abs(index - this.currentIndex) === 0 ? this.speed : Math.abs(index - this.currentIndex) * this.speed
this.move(offset, direction, jumpSpeed)
}

六、自动播放与暂停

前面的写的差不多了,到这里就非常简单了,写一个函数play:

play() {
if (this.timer) {
window.clearInterval(this.timer)
this.timer = null
}
this.timer = window.setInterval(() => {
this.move(600, -1, this.speed)
}, 4000)
}

除了初始化以后自动播放,还要通过mouseover和mouseleave来控制暂停与播放:

stop() {
window.clearInterval(this.timer)
this.timer = null
}

七、 两处小坑

1. window.onblurwindow.onfocus

写到这里,基本功能都差不多了。但是如果把页面切换到别的页面,导致轮播图所在页面失焦,过一段时间再切回来会发现轮播狂转。原因是页面失焦以后,setInterval停止运行,但是如果切回来就会一次性把该走的一次性走完。解决的方法也很简单,当页面失焦时停止轮播,页面聚焦时开始轮播。

window.onblur = function() { this.stop() }.bind(this)
window.onfocus = function() { this.play() }.bind(this)

2. window.setInterval()小坑

当定时器window.setInterval()在多个异步回调中使用时,就有可能在某种机率下开启多个执行队列,所以为了保险起见,不仅应该在该清除时清除定时器,还要在每次使用之前也清除一遍。

八、用props简单写两个对外接口

props: {
initialSpeed: {
type: Number,
default: 30
},
initialInterval: {
type: Number,
default: 4
}
},
data() {
......
speed: this.initialSpeed
},
computed:{
interval() {
return this.initialInterval * 1000
}
}

然后再在相应的地方修改下就可以了。

完整的代码如下:

<template>
<div id="slider">
<div class="window" @mouseover="stop" @mouseleave="play">
<ul class="container" :style="containerStyle">
<li>
<img :src="sliders[sliders.length - 1].img" alt="">
</li>
<li v-for="(item, index) in sliders" :key="index">
<img :src="item.img" alt="">
</li>
<li>
<img :src="sliders[0].img" alt="">
</li>
</ul>
<ul class="direction">
<li class="left" @click="move(600, 1, speed)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M481.233 904c8.189 0 16.379-3.124 22.628-9.372 12.496-12.497 12.496-32.759 0-45.256L166.488 512l337.373-337.373c12.496-12.497 12.496-32.758 0-45.255-12.498-12.497-32.758-12.497-45.256 0l-360 360c-12.496 12.497-12.496 32.758 0 45.255l360 360c6.249 6.249 14.439 9.373 22.628 9.373z" /></svg>
</li>
<li class="right" @click="move(600, -1, speed)">
<svg class="icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M557.179 904c-8.189 0-16.379-3.124-22.628-9.372-12.496-12.497-12.496-32.759 0-45.256L871.924 512 534.551 174.627c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0l360 360c12.496 12.497 12.496 32.758 0 45.255l-360 360c-6.249 6.249-14.439 9.373-22.628 9.373z" /></svg>
</li>
</ul>
<ul class="dots">
<li v-for="(dot, i) in sliders" :key="i"
:class="{dotted: i === (currentIndex-1)}"
@click = jump(i+1)
>
</li>
</ul>
</div>
</div>
</template> <script>
export default {
name: 'slider',
props: {
initialSpeed: {
type: Number,
default: 30
},
initialInterval: {
type: Number,
default: 4
}
},
data () {
return {
sliders:[
{
img:'../../static/images/1.jpg'
},
{
img:'../../static/images/2.jpg'
},
{
img:'../../static/images/3.jpg'
},
{
img:'../../static/images/4.jpg'
},
{
img:'../../static/images/5.jpg'
}
],
currentIndex:1,
distance:-600,
transitionEnd: true,
speed: this.initialSpeed
}
},
computed:{
containerStyle() {
return {
transform:`translate3d(${this.distance}px, 0, 0)`
}
},
interval() {
return this.initialInterval * 1000
}
},
mounted() {
this.init()
},
methods:{
init() {
this.play()
window.onblur = function() { this.stop() }.bind(this)
window.onfocus = function() { this.play() }.bind(this)
},
move(offset, direction, speed) {
if (!this.transitionEnd) return
this.transitionEnd = false
direction === -1 ? this.currentIndex += offset/600 : this.currentIndex -= offset/600
if (this.currentIndex > 5) this.currentIndex = 1
if (this.currentIndex < 1) this.currentIndex = 5 const destination = this.distance + offset * direction
this.animate(destination, direction, speed)
},
animate(des, direc, speed) {
if (this.temp) {
window.clearInterval(this.temp)
this.temp = null
}
this.temp = window.setInterval(() => {
if ((direc === -1 && des < this.distance) || (direc === 1 && des > this.distance)) {
this.distance += speed * direc
} else {
this.transitionEnd = true
window.clearInterval(this.temp)
this.distance = des
if (des < -3000) this.distance = -600
if (des > -600) this.distance = -3000
}
}, 20)
},
jump(index) {
const direction = index - this.currentIndex >= 0 ? -1 : 1
const offset = Math.abs(index - this.currentIndex) * 600
const jumpSpeed = Math.abs(index - this.currentIndex) === 0 ? this.speed : Math.abs(index - this.currentIndex) * this.speed
this.move(offset, direction, jumpSpeed)
},
play() {
if (this.timer) {
window.clearInterval(this.timer)
this.timer = null
}
this.timer = window.setInterval(() => {
this.move(600, -1, this.speed)
}, this.interval)
},
stop() {
window.clearInterval(this.timer)
this.timer = null
}
}
}
</script>

九、结语

大概写完了这个组件,发现其实还有许多地方可以优化,this.distancethis.currentIndex耦合性很高,完全可以通过计算属性连到一起。还有过渡方式,用定时器的方法还是有些生硬,没有发挥出Vue的优势来。不过,第一个组件算是写完了,也费了一番力气。

github地址

Vue写一个图片轮播组件【转载】的更多相关文章

  1. Vue学习—Vue写一个图片轮播组件

    1.先看效果: 熟悉的图片轮播,只要是个网站,百分之90以上会有个图片轮播.我认为使用图片轮播. 第一可以给人以一种美观的感受,而不会显得网站那么呆板, 第二可以增加显示内容,同样的区域可以显示更多内 ...

  2. Angular2组件与指令的小实践——实现一个图片轮播组件

    如果说模块系统是Angular2的灵魂,那其组件体系就是其躯体,在模块的支持下渲染出所有用户直接看得见的东西,一个项目最表层的东西就是组件呈现的视图.而除了直接看的见的躯体之外,一个完整的" ...

  3. VUE开发一个图片轮播的组件

    完成效果图如下: vue开发的思路主要是数据绑定,代码如下: <template> <div ref="root" style="user-select ...

  4. 实现一个图片轮播-3d播放效果

    前言:最近在做一个音乐播放器,首页要做一个图片轮播,看了bootstrap的carousel插件以及移动端的swipe.js库,都是平面图片轮播的效果,所以自己想着实现类似网易云app里那种3d图片轮 ...

  5. 基于ionic框架封装一个图片轮播指令的几点

    在这里我想在项目中封装一个图片轮播的指令 (本项目使用的是ionic框架) 1)定义指令 define(['app'],function(myapp){ myapp.directive('myslid ...

  6. Omi-touch实战 移动端图片轮播组件的封装

    pc端的轮播,移动端的轮播都很常见.一年前,我还为手机端没有左滑,右滑事件从而封装了一个swipe库,可以自定义超过多少滑动时间就不触发,也可以设置滑动多少距离才触发,这一个功能的代码就达到400多行 ...

  7. 一分钟搞定AlloyTouch图片轮播组件

    轮播图也涉及到触摸和触摸反馈,同时,AlloyTouch可以把惯性运动打开或者关闭,并且设置min和max为运动区域,超出会自动回弹. 除了一般的竖向滚动,AlloyTouch也可以支持横向滚动,甚至 ...

  8. 如何将angular-ui的图片轮播组件封装成一个指令

    在项目开发中我们经常会遇到图片轮播的功能点: 如果我们开发人员自己原生手写,将会花费很多的时间,最终得不偿失. 接下来就详细说说如何使用angular-ui发热图片轮播模块,并且将它写成一个指令(便于 ...

  9. 如何将angular-ui-bootstrap的图片轮播组件封装成一个指令

    在项目开发中我们经常会遇到图片轮播的功能点: 如果我们开发人员自己原生手写,将会花费很多的时间,最终得不偿失. 接下来就详细说说如何使用angular-ui发热图片轮播模块,并且将它写成一个指令(便于 ...

  10. 原生js写一个无缝轮播图插件(支持vue)

    轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...

随机推荐

  1. Debian/ubuntu系统的开机自启动服务的设置——update-rc.d: error: XXX Default-Start contains no runlevels, aborting.

    最近把自己的树莓派搞了起来,搭了个上网的共享热点,但是遇到了开机自启动的设置问题. 我们先给出正常的ubuntu系统的开机自启动服务的设置: 在 /etc/init.d/ 路径下面创建自启动的shel ...

  2. 再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(5) —— 第一个用于解决2048游戏的Reinforcement learning方法——《Temporal Difference Learning of N-Tuple Networks for the Game 2048》

    <2048>游戏在线试玩地址: https://play2048.co/ 如何解决<2048>游戏源于外网的一个讨论帖子,而这个帖子则是讨论如何解决该游戏的最早开始,可谓是&q ...

  3. Apache DolphinScheduler支持Flink吗?

    随着大数据技术的快速发展,很多企业开始将Flink引入到生产环境中,以满足日益复杂的数据处理需求.而作为一款企业级的数据调度平台,Apache DolphinScheduler也跟上了时代步伐,推出了 ...

  4. 利用 Amazon EMR Serverless、Amazon Athena、Apache Dolphinscheduler 以及本地 TiDB 和 HDFS 在混合部署环境中构建无服务器数据仓库(一)云上云下数据同步方案设计

    引言 在数据驱动的世界中,企业正在寻求可靠且高性能的解决方案来管理其不断增长的数据需求.本系列博客从一个重视数据安全和合规性的 B2C 金融科技客户的角度来讨论云上云下混合部署的情况下如何利用亚马逊云 ...

  5. 面试官:说说volatile应用和实现原理?

    volatile 是并发编程中的重要关键字,它的名气甚至是可以与 synchronized.ReentrantLock 等齐名,也是属于并发编程五杰之一. 需要注意的是 volatile 并不能保证原 ...

  6. Lambert cos 定律再积分无穷级数求和

    设有能量为 \(I\) 的一束光射向表面 \(s\),发生理想的漫反射.设反射率为 \(a\),则 \(s\) 向在 \(\phi\) 方向反射的能量 \(R\) 可由 Lambert cos 定律给 ...

  7. 【图文安装教程】在docker中安装kibana

    在上一篇中,我们已经在docker里面安装了ES. kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习. 所以,本篇咱们就在docker里面安装kibana图文教程: ...

  8. spring boot 若依系统整合Ueditor,部署时候上传图片错误解决

    spring boot 若依系统整合Ueditor,部署时候上传图片错误解决 前言:国庆假期找了个ruoyi版本的cms玩玩,从git上看,介绍如下图: 后台部分截图: 编辑 ​ 编辑 ​ 编辑 ​ ...

  9. vue echarts map 中国地图显示不出来

    测试区忽然无法显示中国地图,所以对比了一下测试区与开发环境中echarts版本的区别 测试区echarts版本为 5.4.2 开发环境为5.0.2 所以将package.json中的 "ec ...

  10. vue打包后dist的使用

    发现问题 vue项目完成打包出dist后准备打开index.html,发现居然页面是一片空白,f12一片报红. 分析问题 经过多次网上查询后发现这是由于vue打包时,脚手架会帮你配置好大量参数,但其中 ...