需求:项目中需要做一个通知的跑马灯,试了很多方案,最后用了下面这种,感谢大佬的博客
原博客地址: 点这里
最终的效果:
剖析代码(本菜鸡第一次看有点绕)
marquee.vue的源代码
<template>
<div class="marquee-wrap">
<div class="scroll">
<p class="marquee">{{ text }}</p>
<p class="copy"></p>
</div>
<!-- <p class="getWidth">{{ text }}</p> -->
</div>
</template>
<script>
/**
* 调用组件时将要展示的文字传递进来 val
*/
export default {
name: 'marquee',
props: ['val'],
data() {
return {
timer: null,
text: ''
}
},
created() {
const timer = setTimeout(() => {
this.move()
clearTimeout(timer)
}, 200)
},
mounted() {
for (const item of this.val) {
this.text += ' ' + item
}
},
methods: {
move() {
const maxWidth = document.querySelector('.marquee-wrap').clientWidth
const width = document.querySelector('.getWidth').scrollWidth
console.log(width, maxWidth)
if (width <= maxWidth) return
const scroll = document.querySelector('.scroll')
const copy = document.querySelector('.copy')
copy.innerText = this.text
let distance = 0
this.timer = setInterval(() => {
distance -= 1
if (-distance >= width) {
distance = 30
}
scroll.style.transform = 'translateX(' + distance + 'px)'
}, 20)
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>
<style scoped>
.marquee-wrap {
width: 100%;
overflow: hidden;
position: relative;
}
.marquee {
margin-right: 30px;
}
p {
word-break: keep-all;
white-space: nowrap;
font-size: 0.26rem;
}
.scroll {
display: flex;
}
.getWidth {
word-break: keep-all;
white-space: nowrap;
position: absolute;
opacity: 0;
top: 0;
}
</style>
根据自己的实际需要,修改了一点点细节
具体思路:有两个包含文字的p标签,分别是marquee和copy,他们的父标签scroll设置display:flex;使得两个p标签在一行,最外层的marquee-wrap设置overflow:hidden;每次创建组件调一下move方法,主要是逻辑都在move方法里面
<template>
<div class="marquee-wrap">
<div class="scroll">
<p class="marquee">{{ val }}</p>
<p class="copy">{{ val }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'marquee',
props: ['val'],
data() {
return {
timer: null
}
},
created() {
const timer = setTimeout(() => {
this.move()
clearTimeout(timer)
}, 200)
},
mounted() {},
methods: {
move() {
//外层容器的宽度
const maxWidth = document.querySelector('.marquee-wrap').clientWidth
//内容总宽度:scrollWidth:获取指定标签内容层的真实宽度(可视区域宽度+被隐藏区域宽度)
const width = document.querySelector('.marquee').scrollWidth
if (width <= maxWidth) return //如果要展示的内容的宽度小于外层容器宽度,不滚动,直接return
const scroll = document.querySelector('.scroll')//获取scroll,后面要设置样式
let distance = 0 //初始化一个distance
this.timer = setInterval(() => { //开启定时器
distance -= 1 //每20秒distance = distance - 1
if (-distance >= width) { //如果所有的内容都已经滚动出去
distance = 30 //重置distance(和样式里面marquee的margin-right一致!!!)
}
scroll.style.transform = 'translateX(' + distance + 'px)' //将scroll迅速切换到distance的位置(看起来就无缝衔接了)
}, 20)
}
},
beforeDestroy() {
clearInterval(this.timer)//组件销毁之前清掉timer
}
}
</script>
<style scoped lang="less">
.marquee-wrap {
width: 100%;
overflow: hidden;
.scroll {
display: flex;
p {
word-break: keep-all;
white-space: nowrap;
font-size: 0.26rem;
}
.marquee {
margin-right: 30px;
}
}
}
</style>
clientWidth的实际宽度
clientWidth = width+左右padding
scrollWidth实际宽度
scrollWidth:获取指定标签内容层的真实宽度(可视区域宽度+被隐藏区域宽度)