先看效果图:
1、模板部分
2、css部分
.v-message-roll {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
transition: opacity 0.2s;
.v-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
.v-content {
flex: 1;
width: 0;
.v-content-list {
width: 100%;
overflow-x: auto;
white-space: nowrap;
&::-webkit-scrollbar {
display: none;
}
.v-content-item {
display: inline-block;
color: #db8412;
}
}
}
}
.fade-sport-enter,
.fade-sport-leave {
opacity: 0;
}
3、js部分
const SPEED = {
FAST: 0.6,
MIDDLE: 0.4,
SLOW: 0.3,
};
export default {
data() {
return {
visible: true,
animationFrameTimer: null,
touchTimeout: null,
refreshRateTimer: null,
};
},
props: {
content: [String, Array],
touchStop: {
type: Boolean,
default: false,
},
touchStopDuration: {
type: Number,
default: 1500,
},
showCloseIcon: {
type: Boolean,
default: true,
},
},
watch: {
content: {
handler() {
this.reset();
this.$nextTick(() => {
this.init();
});
},
deep: true,
},
},
computed: {
contentComputed() {
if (Object.prototype.toString.call(this.content) === "[object Array]") {
return this.content;
}
return [this.content];
},
},
mounted() {
this.calcScreenRefreshRate().then((rate) => {
this.screenRefreshRate = rate;
this.init();
});
},
methods: {
init() {
const itemsRef = this.$refs.itemsRef;
const scrollW = this.$refs.listRef.scrollWidth;
this.scrollW = scrollW;
if (itemsRef.length) {
this.itemsRef = this.$refs.itemsRef;
this.setInterval();
}
},
reset() {
this.$refs.listRef.scrollLeft = 0;
this.cancelAnimationFrame();
},
calcScreenRefreshRate() {
return new Promise((resolve) => {
let screenRefreshRate = 0;
const animationFrameFunc = () => {
screenRefreshRate += 2;
this.refreshRateTimer = window.requestAnimationFrame(animationFrameFunc);
};
setTimeout(() => {
window.cancelAnimationFrame(animationFrameFunc);
resolve(screenRefreshRate);
}, 500);
animationFrameFunc();
});
},
setInterval(num) {
this.animationFrameTimer = window.requestAnimationFrame(() => this.roll(num));
},
roll(num = 0) {
const step = this.calcStep();
this.itemsRef.forEach((ele) => {
ele.style.transform = `translateX(-${num}px)`;
});
this.animationFrameTimer = window.requestAnimationFrame(() =>
this.roll(num < this.scrollW ? num + step : 0)
);
},
calcStep() {
const screenRefreshRate = this.screenRefreshRate;
let step = 0;
if (screenRefreshRate < 90) {
step = SPEED["FAST"];
} else if (screenRefreshRate < 120) {
step = SPEED["MIDDLE"];
} else {
step = SPEED["SLOW"];
}
return step;
},
touchstart() {
if (!this.touchStop) {
this.$refs.listRef.style.overflow = "hidden";
} else {
this.itemsRef.forEach((ele) => {
ele.style.transform = `translateX(0)`;
});
this.cancelAnimationFrame();
window.clearTimeout(this.touchTimeout);
}
},
touchend() {
if (this.touchStop) {
const scrollLeft = this.$refs.listRef.scrollLeft;
this.touchTimeout = setTimeout(() => {
this.$refs.listRef.scrollLeft = 0;
this.setInterval(scrollLeft);
}, this.touchStopDuration);
}
},
close() {
this.visible = false;
this.$emit("close");
this.cancelAnimationFrame();
},
cancelAnimationFrame() {
window.cancelAnimationFrame(this.animationFrameTimer);
window.cancelAnimationFrame(this.refreshRateTimer);
},
},
deactivated() {
this.cancelAnimationFrame();
},
beforeDestroy() {
this.cancelAnimationFrame();
},
};
4、参数和事件
可以的话,点个赞嘛
## 属性
content: 内容。参数类型:string|array
touchStop: 触摸是否停止滚动。参数类型:boolean, 默认 false
touchStopDuration: 触摸停止滚动持续时长(ms)。参数类型:number, 默认1500
showCloseIcon:是否显示关闭按钮。参数类型:boolean, 默认 true
## 事件
close:关闭事件