先看效果图:
1、模板部分
<transition name="fade-sport"><div class="v-message-roll" v-show="visible"><svg class="v-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7405"><pathd="M594.917478 144.398738c0-43.803645-37.123502-79.478146-82.916455-79.478146-45.699832 0-82.918501 35.585473-82.918501 79.478146 0 4.472871 0.38681 8.860808 1.12973 13.133112-114.497731 38.254256-208.430076 155.73083-208.430076 294.718325l0 109.423155c0 0 0 157.590178-40.387849 158.963455-24.082488 0-42.528606 17.792225-42.528606 39.74112 0 22.098297 18.557658 39.737026 41.452087 39.737026l663.36643 0c23.004947 0 41.451064-17.791202 41.451064-39.737026 0-22.103414-18.557658-39.74112-41.451064-39.74112-41.46539 0-41.46539-157.854191-41.46539-157.854191L802.218848 452.263477c0-139.166573-87.828324-256.691243-208.408587-294.828842C594.538855 153.190985 594.917478 148.838863 594.917478 144.398738zM636.377752 839.789535c-0.12382 65.903989-55.286164 119.28885-124.377752 119.28885-68.616774 0-124.254955-53.163827-124.378775-119.28885L636.377752 839.789535z"fill="#f9a60a"p-id="7406"></path></svg><div class="v-content"><ul class="v-content-list" ref="listRef" @touchstart="touchstart" @touchend="touchend"><li class="v-content-item" ref="itemsRef" v-for="(item, index) in contentComputed" :key="index">{{ item }}</li></ul></div><svgv-if="showCloseIcon"@click="close"class="v-icon"viewBox="0 0 1024 1024"version="1.1"xmlns="http://www.w3.org/2000/svg"p-id="8743"><pathd="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z"fill="#f9a60a"p-id="8744"></path></svg></div></transition>
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|arraytouchStop: 触摸是否停止滚动。参数类型:boolean, 默认 falsetouchStopDuration: 触摸停止滚动持续时长(ms)。参数类型:number, 默认1500showCloseIcon:是否显示关闭按钮。参数类型:boolean, 默认 true## 事件close:关闭事件