手把手教你用VUE封装一个文本滚动组件
Sumu 人气:0一、引言
项目有文本滚动展示的需求,一开始使用marquee标签来实现需求,但是看一下MDN对该标签的描述:
这个标签已经不再推荐使用了,那就自己封装一个类似的组件来用。
二、实现思路
1.如何让文本滚动起来?
通过动画我们设置过渡transform:translateX(a) => transfrom:translateX(b)来实现向左或向右的滚动效果。transform:translateY(c) => transfrom:translateY(d)来实现向下或向上的滚动效果。
2.组件需要哪些配置?
(1)滚动的方向:上右下左
(2)滚动的速度:这里我以px/s作为单位
三、实现过程
1.html
2.css
最外层的div为滚动的可视区,里面的div为文本滚动区。可视区宽度高度均为100%使用时大小由外部容器决定,overflow设为hidden,防止文本滚动区滚动出可视区外仍可见。文本滚动区设置宽高都为fit-content使大小随内容自适应,内部设置插槽使用组件时插入滚动内容。
3.动画
动画应设置在文本滚动区上
需要上右下左四个方向滚动的动画,我们只需要定义上左两个方向,另外两个方向直接反转即可。先来想想向上滚动的动画怎么写,向上滚动的话文本滚动区的起点应设置在可视区外正下方,所以动画的起点应为 transform: translateY(可视区的高度),终点应设置在可视区外正上方应为transform: translateY(-100%)。
向上向左动画即为:
--text-scroll-height、--text-scroll-width两个css变量的值是可视区的高度和宽度,由于可视区的宽高不确定,所以需要通过js获取并设置这两个css变量。
注意: 动画样式不能加上scoped,否则不生效!
4.js
(1)组件配置
通过props传入组件配置
(2)计算得到滚动动画
scrollLength为一次动画的实际滚动的长度,time为一次动画的持续时间。我们可以算出scrollLength应为:可视区的宽或高加上文本滚动区的宽或高(根据滚动的方向来判断是宽还是高)。time应为 scrollLegnth / 组件配置的滚动速度。
(3)生命周期
在mounted里调用上面的方法初始化组件。在updated里同样调用该方法,当组件宽高改变或插槽内容变动重新计算动画样式。
三、完整代码
<template> <!-- 文本滚动 --> <div class="text-scroll" ref="textScroll"> <div class="content" ref="content" :style="scrollAnimation"> <!-- 默认插槽,插入滚动内容 --> <slot></slot> </div> </div> </template> <script> export default { name: "TextScroll", props: { /* 滚动方向 * value: up、down、left、right */ direction: { default: "up", type: String, }, //滚动速度 单位px/s speed: { default: 60, type: Number, }, }, data() { return { //滚动动画 scrollAnimation: {}, }; }, methods: { getScrollAnimation() { //获取文本滚动实际显示宽度高度,设为css变量,用于设置动画开始起始位置 let height = this.$refs.textScroll.offsetHeight; let width = this.$refs.textScroll.offsetWidth; this.$refs.content.style.setProperty( "--text-scroll-height", `${height}px` ); this.$refs.content.style.setProperty("--text-scroll-width", `${width}px`); //滚动长度、时间 let scrollLength, time; //根据滚动方向来设置不同的滚动动画 switch (this.direction) { case "up": scrollLength = this.$refs.content.offsetHeight + height; time = scrollLength / this.speed; this.scrollAnimation.animation = `up-scroll linear ${time}s infinite`; break; case "down": scrollLength = this.$refs.content.offsetHeight + height; time = scrollLength / this.speed; this.scrollAnimation.animation = `up-scroll linear ${time}s infinite reverse`; break; case "left": scrollLength = this.$refs.content.offsetWidth + width; time = scrollLength / this.speed; this.scrollAnimation.animation = `left-scroll linear ${time}s infinite`; break; case "right": scrollLength = this.$refs.content.offsetWidth + width; time = scrollLength / this.speed; this.scrollAnimation.animation = `left-scroll linear ${time}s infinite reverse`; break; } }, }, async mounted() { //设置文本滚动动画 this.getScrollAnimation(); }, updated() { //当插槽内容更新重新计算滚动动画 this.getScrollAnimation(); }, }; </script> <style scoped lang="scss"> .text-scroll { width: 100%; height: 100%; overflow: hidden; .content { height: fit-content; width: fit-content; } } </style> <style lang="scss"> .text-scroll { .content { @keyframes up-scroll { 0% { transform: translateY(var(--text-scroll-height)); } 100% { transform: translateY(-100%); } } @keyframes left-scroll { 0% { transform: translateX(var(--text-scroll-width)); } 100% { transform: translateX(-100%); } } } } </style>
总结
加载全部内容