一,导入组件
import Banner from '@/components/banner'
components: { banner },
二 在作为标签内使用
<banner :isHover="true" :list="bikeList" :timeSpace="3000" :showCount="count" :length="bikeList.length" v-if="bikeList.length > 0" class="warp">
<div class="item" v-for="(i, index) in bikeList" :key="index" @click="handleDetail(i)">
<div class="cItem">
<span>{{ i.time }}</span>
<span>{{ i.address }}</span>
<span>{{ i.carNo }}</span>
<span>{{ i.person }}</span>
<span>{{ i.behavior1 }}</span>
</div>
</div>
</banner>
源码 如下
<template>
<div v-bind:class="`banner ${className}`" ref="banner" v-on:mouseenter="mouseenterFunc" v-on:mouseleave="mouseleaveFunc">
<div class="originDom" ref="originDom">
<div class="originDomItem" ref="originDomItem" v-for="n in repeatTime" v-bind:key="n">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
// 是否反向
reverse: {
type: [Boolean],
default: function () {
return false
}
},
// 偏移的百分比
offsetPrecent: {
type: [Number],
default: function () {
return 10
}
},
// 滚动模式,单条或者整页,可选值为 item 或者 page
mode: {
type: [String],
default: function () {
return 'item'
}
},
// 动画的持续时间,ms为单位
transitionDuration: {
type: [Number],
default: function () {
return 500
}
},
// 单条动画之间的间隔时间
animationInterval: {
type: [Number],
default: function () {
return 100
}
},
// 轮播的间隔时间,ms为单位
intervalTime: {
type: [Number],
default: function () {
return 3000
}
},
// 显示的条数
showCount: {
type: [Number],
default: function () {
return 3
}
},
// 鼠标悬停的时候是否暂停
hoverPause: {
type: [Boolean],
default: function () {
return true
}
},
// 起始模糊程度
startBlur: {
type: [Number],
default: function () {
return 0
}
},
// 结束模糊程度
endBlur: {
type: [Number],
default: function () {
return 0 * window.innerHeight / 1440
}
},
// 起始透明度
startOpacity: {
type: [Number],
default: function () {
return 1
}
},
// 结束透明度
endOpacity: {
type: [Number],
default: function () {
return 1
}
},
// 类名
className: {
type: [String],
default: function () {
return ''
}
},
// 是否使用复制模式,即传入的数据小于等于要显示的条数的时候,自动复制
repeat: {
type: [Boolean],
default: function () {
return false
}
}
},
data: function () {
return {
msg: 'banner',
enable: true,
childrenDom: [],
repeatTime: 1,
active: 0,
originLength: 0,
timer: 0,
alive: true
}
},
methods: {
mouseenterFunc: function () {
/* eslint-disable */
this.hoverPause && (this.enable = false)
},
mouseleaveFunc: function () {
/* eslint-disable */
this.hoverPause && (this.enable = true)
},
computeChildrenDom: function () {
return new Promise(resolve => {
if (this.$refs.originDomItem[0].children.length) {
let origin = [...this.$refs.originDomItem[0].children]
this.originLength = origin.length
let repeatTime = 1
if (!this.repeat && this.childrenDom.length < this.showCount) {
console.log()
} else {
while (repeatTime * this.originLength < this.showCount + 2) {
repeatTime = repeatTime + 1
}
}
this.repeatTime = repeatTime
this.childrenDom = []
this.$nextTick(() => {
let list = [...this.$refs.originDomItem]
list.forEach(item => {
[...item.children].forEach(dom => {
dom.style.position = 'absolute'
dom.style.transition = `all ${this.transitionDuration / 1000}s`
dom.style.width = '100%'
dom.style.opacity = 1
this.childrenDom.push(dom)
})
})
resolve()
})
}
})
},
computeContainerHeight: function () {
if (!this.childrenDom.length) {
return false
}
let sum = 0
for (let i = 0; i < this.showCount; i++) {
let index = (this.active + i) % this.childrenDom.length
sum = sum + this.childrenDom[index].offsetHeight
}
/* eslint-disable */
this.$refs.banner && (this.$refs.banner.style.height = `${sum}px`)
},
computeItemStyle: function () {
if (!this.childrenDom.length) {
return false
}
if (!this.repeat && this.childrenDom.length < this.showCount + 1) {
let sum = 0
this.childrenDom.forEach((item, index) => {
item.style.top = `${sum}px`
item.style.left = 0
item.style.opacity = this.startOpacity + (this.endOpacity - this.startOpacity) / (this.childrenDom.length - 1) * index
item.style.filter = `blur(${this.startBlur + (this.endBlur - this.startBlur) / (this.childrenDom.length - 1) * index}px)`
sum = sum + this.childrenDom[index].offsetHeight
})
} else {
// 当使用非重复模式,并且 当前的数据数量 < 显示条数 + 1
let sum = 0
let indexList = []
let prevIndex = (this.active + this.childrenDom.length - 1) % this.childrenDom.length
let prev = this.childrenDom[prevIndex]
prev.style.top = 0
prev.style[this.reverse ? 'left' : 'right'] = `${this.offsetPrecent / 100 * this.$refs.banner.offsetWidth}px`
prev.style.opacity = 0
prev.style.pointerEvents = 'none'
indexList.push(prevIndex)
for (let i = 0; i < this.showCount; i++) {
setTimeout(() => {
let index = (this.active + i) % this.childrenDom.length
indexList.push(index)
this.childrenDom[index].style.top = `${sum}px`
this.childrenDom[index].style[this.reverse ? 'left' : 'right'] = 0
this.childrenDom[index].style.pointerEvents = 'auto'
if (this.showCount > 1) {
// console.log(this.startOpacity + (this.endOpacity - this.startOpacity) / (this.showCount - 1) * i)
this.childrenDom[index].style.opacity = this.startOpacity + (this.endOpacity - this.startOpacity) / (this.showCount - 1) * i
this.childrenDom[index].style.filter = `blur(${this.startBlur + (this.endBlur - this.startBlur) / (this.showCount - 1) * i}px)`
} else {
console.log(this.startOpacity)
this.childrenDom[index].style.opacity = this.startOpacity
this.childrenDom[index].style.filter = `blur(${this.startBlur}px)`
}
sum = sum + this.childrenDom[index].offsetHeight
}, this.animationInterval * (i + 1))
}
setTimeout(() => {
for (let i = 0; i < this.childrenDom.length; i++) {
if (indexList.indexOf(i) < 0) {
this.childrenDom[i].style[this.reverse ? 'left' : 'right'] = 0
this.childrenDom[i].style.top = `${sum}px`
this.childrenDom[i].style.opacity = 0
this.childrenDom[i].style.pointerEvents = 'none'
}
}
}, this.showCount * this.animationInterval)
}
},
animationFrame: function () {
window.requestAnimationFrame(() => {
if (this.enable) {
this.timer = this.timer + 1000 / 60
if (this.timer > this.intervalTime) {
this.timer = 0
this.active = (this.active + 1) % this.childrenDom.length
this.$emit('changeActive', this.active % this.originLength)
this.computeContainerHeight()
this.computeItemStyle()
}
}
/* eslint-disable */
this.alive && this.animationFrame()
})
},
init: function () {
setTimeout(() => {
this.computeChildrenDom().then(() => {
this.computeContainerHeight()
this.computeItemStyle()
})
}, 0)
}
},
mounted: function () {
this.alive = true
/* eslint-disable */
this.intervalTime !== 0 && this.animationFrame()
setTimeout(() => {
this.computeChildrenDom().then(() => {
this.computeContainerHeight()
this.computeItemStyle()
})
}, 0)
},
watch: {
// activeIndex: function (newVal) {
// this.$emit('changeActive', (newVal + 1) % this.children.length)
// }
},
beforeUpdate: function () {},
beforeDestroy: function () {
this.alive = false
}
}
</script>
<style lang="less" scoped>
.banner {
position: relative;
overflow: visible;
.originDom {
.originDomItem {
>* {
opacity: 0;
}
}
}
}
</style>