vue2 、 vue3 文本超出自动滚动

本文分享了一段Vue2和Vue3代码实现文本超出屏幕宽度时自动滚动的效果。通过设置CSS样式和JavaScript监听元素尺寸变化,当内容宽度大于容器宽度时启动滚动动画。代码可以直接复制使用。

vue2、vue3 实现文本超出自动滚动

一、直接上代码

<template>
    <div class="sizeScroll">
        <h1>1、文字滚动·超出时自动滚动</h1>
        <div class="content" ref="songName1">
            <div id="inner" :class="{innerActive: nameScroll }">
                <span ref="first" id="first">本店主营拉面,刀削面,烩面,盖浇饭</span>
                <span id="second">本店主营拉面,刀削面,烩面,盖浇饭</span>
            </div>
        </div>
    </div>
</template>

<script>
import { onMounted, ref, getCurrentInstance  } from 'vue'
export default {
		/** vue2写法 */
    // data() {
    //     return {
    //         nameScroll: false
    //     }
    // },
    // mounted() {
    //     console.log(this.$refs.songName1.clientWidth,'his.$refs.songName1.clientWidth');
    //     if (this.$refs.songName1.clientWidth > this.$refs.first.clientWidth) {
    //         this.nameScroll = true
    //     } else {
    //         this.nameScroll = false
    //     }
    // }
    /** vue3写法 */
    setup() {
        const internalInstance  = getCurrentInstance()
        let nameScroll = ref(false)
        onMounted(() => {
            console.log(internalInstance.ctx.$refs.songName1.clientWidth, internalInstance.ctx.$refs.first.clientWidth, 'songName1.clientWidth');
            if (internalInstance.ctx.$refs.songName1.clientWidth < internalInstance.ctx.$refs.first.clientWidth) {
                nameScroll.value = true
            } else {
                nameScroll.value = false
            }

        })
        return { nameScroll }
    }
}
</script>

<style lang="scss" scoped>
h1{ font-weight: bold; }
.sizeScroll{
    padding: 36px;
    .content {
        overflow: hidden;
        position: relative;
        width: 200px;
        height: 50px;
        margin: 16px 10%;
        white-space: nowrap;
        border: 1px solid #808080;
    }
    #inner {
        position: absolute;
    }
    .innerActive{
        animation: slide 5s linear infinite;
        #first{
            margin-right: 8px;
        }
        #second{
            display: inline-block;
        }
    }

    #first{
        display: inline-block;
        border: 1px solid red;
    }

    #second{
        display: none;
        border: 1px solid green;
    }

    @keyframes slide {
        0% {
            transform: translateX(0);
        }
        100% {
            transform: translateX(-51%);
        }
    }
}
</style>

二、实际效果

fileOverfiewscroll

直接copy过去,修改参数即可使用。

原文章 ==> css 文本超出自动滚动

<think>我们正在讨论Vue中实现循环渲染的数据在文本超宽时自动滚动的效果。用户希望在一个循环(如v-for)中,每个项目的文本内容如果超出宽度,能够自动滚动(通常是横向滚动)。实现思路:1.每个循环项可以包裹在一个固定宽度的容器中,超出部分隐藏。2.在容器内部,放置一个可以滚动文本元素,当文本内容超出容器宽度时,出现滚动条(通常是横向滚动条)。3.但是用户希望自动滚动,可能是指类似跑马灯的效果(marquee),即文本自动向左或向右滚动,直到完全显示,然后重复。但是,请注意,HTML5已经不推荐使用<marquee>标签,所以我们可以用CSS3动画或者JavaScript来实现类似效果。然而,用户要求的是“超宽文本自动滚动”,我们通常有两种理解:A.当文本超宽时,出现横向滚动条,让用户可以手动滚动查看(但这不是自动滚动)。B.文本自动向左或向右滚动,无需用户操作,类似新闻滚动效果。根据问题描述,用户希望“自动滚动”,所以应该是类似跑马灯效果。但要注意,这种效果可能会影响用户体验,所以一般用于需要强调的滚动信息。方案:1.使用CSS动画实现无限滚动效果。2.使用JavaScript计算文本宽度和容器宽度,动态设置动画。具体步骤(以水平向左滚动为例):-为每个循环项设置一个固定宽度的容器(例如:width:200px;overflow:hidden;white-space:nowrap;)。-在容器内,放置一个内联元素(比如div)来包裹文本,并设置display:inline-block;(这样宽度会随内容而变)。-当文本内容宽度大于容器宽度时,我们通过CSS动画让这个内联元素水平移动(从右向左)。但是,我们需要动态判断是否应该滚动?只有当内容超过容器宽度时才需要滚动,否则不滚动。因此,我们可能需要使用Vue指令来动态判断并应用动画。我们创建一个Vue自定义指令,用于判断文本是否超宽,并添加滚动动画。具体代码实现:第一步:创建自定义指令(比如v-auto-scroll)-在指令的bind或inserted钩子中,判断元素的宽度是否超过其父容器的宽度。-如果超过,则应用滚动动画。-注意:由于是循环渲染,每个元素都需要独立判断。第二步:定义动画-通过动态添加CSS类名来触发动画。但是,我们还需要注意:-当文本内容变化时,需要重新判断(可以使用update钩子)。-动画效果:初始状态,文本在右侧隐藏位置(translateX(100%)),然后向左滚动文本完全出现,最后回到初始位置并重复。但实际中,我们更希望:文本从初始位置开始向左滚动,直到文本的尾部出现,然后重置,重复滚动。另一种常见的做法是:让文本向左移动,直到整个文本从左边消失,然后重置到右侧,重新开始。但是这样会有一个跳跃,为了平滑,我们可以使用两个相同的文本来循环。然而,考虑到性能,特别是循环渲染,我们尽量简化。简单方案(单个文本):-动画:将文本从初始位置(0)向左移动(负方向)到文本的尾部与容器左对齐,即移动距离为(文本宽度-容器宽度)。-然后重置,但重置会有跳跃。为了无限循环,我们可以使用CSS动画的迭代次数为infinite。但是,使用CSS动画可以实现无缝滚动吗?如果文本很长,移动整个距离会花费较长时间,然后突然跳回,体验可能不好。我们这里先实现一个简单的版本:当文本超出时,添加一个动画,让它无限向左滚动直到显示完整个文本后跳回重新开始。但注意:跳回时会有闪烁。为了避免闪烁,我们可以使用两个相同的文本并排,在第一个文本即将滚动出容器时,第二个文本紧接着进入,这样形成无缝滚动。但这样需要复制文本节点,并且需要计算。考虑到问题复杂度,我们先实现一个简单的滚动(非无缝),然后根据需求再优化。由于用户的问题中没有要求无缝,我们可以先做简单版本。实现步骤:1.模板结构:<divclass="container"><divv-for="iteminitems":key="item.id"class="scroll-container"><divclass="text"v-auto-scroll>{{item.text}}</div></div></div>2.自定义指令v-auto-scroll:在Vue中注册指令:Vue.directive(&#39;auto-scroll&#39;,{inserted:function(el,binding){//判断是否超宽constparent=el.parentNode;constcontainerWidth=parent.offsetWidth;consttextWidth=el.scrollWidth;if(textWidth>containerWidth){el.style.display=&#39;inline-block&#39;;//确保文本元素是行内块,宽度由内容撑开el.style.paddingLeft=&#39;100%&#39;;//在文本前增加一段空白,目的是在初始时空白在容器中,文本在右侧不可见//添加动画el.style.animation=&#39;marquee10slinearinfinite&#39;;}}//同样,在update时也需要判断});3.定义CSS动画:@keyframesmarquee{0%{transform:translateX(0);}100%{transform:translateX(-100%);}}但是这样,初始时文本在容器右侧不可见,然后向左移动100%(相对于自身宽度),就会将文本完全移进容器,然后跳回0%的位置(因为动画结束会重置)又回到初始,这样会有一个明显的跳跃。改进:我们希望文本从左到右完全滚动出来后,紧接着自己的开头又进来,所以我们需要两个文本。但我们可以用伪元素复制文本吗?不行,因为内容动态。所以我们可以用两个相同的文本节点,并排显示,然后同时滚动。为了简单,我们可以使用一个常见的技巧:将文本复制一份,然后设置两倍的宽度,然后移动一半。修改结构:<divclass="scroll-container"><divclass="text-wrapper"v-auto-scroll><spanclass="text">{{item.text}}</span><spanclass="text">{{item.text}}</span></div></div>然后动画设置为移动整个wrapper的50%(因为有两个文本)。但这样我们需要动态复制节点,指令中操作DOM复制节点,可能会影响性能,而且需要管理。鉴于问题要求,我们可以先给出一个简单方案(有跳跃的)和一个优化方案(无缝滚动)。为了简便,我们先实现简单方案(单文本有跳跃滚动),然后再介绍优化方案(双文本无缝滚动)。但是,用户要求的是循环渲染,所以每个滚动条目不与其他条目干扰。下面提供一个相对完整的例子,包含自定义指令和简单滚动:1.单文本简单滚动(有跳跃):<template><div><divv-for="(item,index)initems":key="index"class="scroll-container"><divclass="text"v-auto-scroll>{{item}}</div></div></div></template><stylescoped>.scroll-container{width:200px;/*固定宽度*/overflow:hidden;/*隐藏溢出部分*/white-space:nowrap;/*禁止换行*/border:1pxsolid#ccc;margin:10px0;position:relative;}.text{display:inline-block;/*宽度由内容决定*/padding-left:100%;/*初始时文本在容器右侧不可见*/will-change:transform;/*优化动画性能*/}@keyframesmarquee{0%{transform:translateX(0);}100%{transform:translateX(-100%);}}</style>2.自定义指令:Vue.directive(&#39;auto-scroll&#39;,{inserted:function(el){constparent=el.parentNode;if(el.scrollWidth>parent.offsetWidth){el.style.animation=&#39;marquee10slinearinfinite&#39;;}}});注意:这个方案在每次动画结束会跳回初始状态(即0%位置),所以会有一个明显的跳动。3.双文本无缝滚动方案:模板结构:<divclass="scroll-container"><divclass="text-wrapper"v-auto-scroll><spanclass="text">{{item.text}}</span><spanclass="text">{{item.text}}</span><!--复制一份--></div></div>样式:.scroll-container{width:200px;overflow:hidden;white-space:nowrap;}.text-wrapper{display:inline-block;white-space:nowrap;animation:marquee10slinearinfinite;}.text{display:inline-block;}动画:@keyframesmarquee{0%{transform:translateX(0);}100%{transform:translateX(-50%);}/*因为有两个文本,所以移动一半的宽度*/}自定义指令需要修改:在inserted钩子中,我们不需要再添加动画,因为动画直接写在CSS中(通过类名控制),但是需要判断是否添加。而且,如果文本没有超宽,我们不应该添加动画,同时也不应该显示两个文本。但是,双文本方案需要复制一份文本,这样在没有超宽的时候,我们只显示一个文本,超宽才显示两个并应用动画。因此,我们需要在指令中动态复制节点,并且动态控制动画的添加。这样会增加复杂度,且需要处理更新(当文本变化时)。考虑到复杂度,我们可以使用一个更简洁的无缝滚动方案:使用CSS线性渐变作为遮罩,让单文本滚动时在两端有渐变消失的效果,从而弱化跳跃。但这不是真正的无缝。由于用户没有明确要求,我们提供单文本简单方案和双文本无缝方案,并说明优缺点。这里我们给出一个综合解决方案:通过指令动态判断,如果超宽则使用双文本并添加动画,否则只显示一个文本。由于指令中操作DOM复制节点较为复杂,我们改为在模板中使用条件渲染,但这样需要每个循环项中判断,不太优雅。所以,我们可以在指令中操作,但要注意内存泄漏(复制节点后,在update或unbind时需要移除)。由于时间关系,我们只实现单文本简单滚动(有跳跃),因为其实现简单,并且对于大多数用户来说可能已经足够。如果用户需要无缝滚动,可以再优化。因此,我们决定给出单文本简单滚动方案。用户如果想要无缝滚动,可以自行扩展。完整示例代码(单文本简单滚动):</think> 在 Vue 中实现循环数据超宽文本自动滚动效果,可以通过以下步骤完成,这里提供完整解决方案: ### 1. 基础实现(CSS动画方案) ```vue <template> <div class="scroll-container"> <div v-for="(item, index) in items" :key="index" class="scroll-item" > <!-- 滚动内容容器 --> <div class="marquee" :style="{ &#39;--scroll-duration&#39;: scrollTime }"> <span class="marquee-text">{{ item.content }}</span> </div> </div> </div> </template> <script> export default { data() { return { items: [ { id: 1, content: &#39;第一行需要滚动显示的超长文本内容...&#39; }, { id: 2, content: &#39;第二行的超宽文本内容需要自动滚动效果...&#39; } ], scrollTime: &#39;15s&#39; // 控制滚动速度 } } } </script> <style scoped> .scroll-container { width: 300px; /* 容器固定宽度 */ } .marquee { overflow: hidden; /* 隐藏溢出内容 */ position: relative; white-space: nowrap; /* 禁止换行 */ } .marquee-text { display: inline-block; padding-left: 100%; /* 初始位置右侧 */ animation: marquee var(--scroll-duration) linear infinite; } @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-100%); } } </style> ``` ### 2. 增强方案(JS动态计算宽度) ```vue <template> <div class="scroll-container"> <div v-for="(item, index) in items" :key="index" class="scroll-item" > <!-- ref绑定用于获取DOM元素 --> <div class="marquee-box" ref="marqueeBox" :data-content="item.content" > <span ref="marqueeText">{{ item.content }}</span> </div> </div> </div> </template> <script> export default { mounted() { this.$nextTick(() => { this.initMarquee(); }); }, methods: { initMarquee() { this.$refs.marqueeText.forEach((textEl, index) => { const boxEl = this.$refs.marqueeBox[index]; const textWidth = textEl.scrollWidth; const boxWidth = boxEl.offsetWidth; // 仅当文本超宽时添加滚动 if (textWidth > boxWidth) { boxEl.classList.add(&#39;scroll-active&#39;); // 动态计算动画时间(根据文本长度) const duration = Math.max(10, textWidth / 50); textEl.style.animationDuration = `${duration}s`; } }); } } } </script> <style scoped> .scroll-container { width: 100%; max-width: 500px; /* 最大宽度限制 */ } .marquee-box { overflow: hidden; position: relative; height: 24px; } .marquee-box.scroll-active > span { display: inline-block; padding-left: 100%; white-space: nowrap; animation: marquee linear infinite; } @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-100%); } } </style> ``` ### 关键实现技术说明: 1. **滚动原理**: - 通过`transform: translateX(-100%)`实现向左滚动 - `padding-left: 100%`确保文本初始位置在容器右侧 - CSS动画控制无限循环滚动效果 2. **自适应处理**: - 使用JS动态检测文本宽度`scrollWidth > offsetWidth` - 根据实际文本长度计算动画时长(文本越长滚动越慢) 3. **性能优化**: - 使用`will-change: transform`加速渲染(可选) - 避免使用`<marquee>`标签(已废弃且性能差) - 通过`overflow: hidden`隐藏滚动条 ### 注意事项: 1. 当数据动态更新时,在`updated`钩子中需重新调用`initMarquee` 2. 可添加`:hover`暂停效果提升用户体验: ```css .marquee:hover > span { animation-play-state: paused; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值