marquee transition

本文介绍了一种基于Vue.js的滚动字幕组件实现方案,详细解释了如何通过DOM操作和CSS样式实现平滑滚动效果,以及如何根据方向调整滚动行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<template>
    <div id="m-marquee" class="zzui-broadcast-window" :style="{height: height + 'px'}">
        <ul class="zzui-broadcast-container" ref="container">
            <slot></slot>
        </ul>
        <ul class="zzui-broadcast-container" ref="containerCopy">
            <slot></slot>
        </ul>
    </div>
    
</template>
<script>
export default{
    data (){
        return {
            height: '',
            visibleLiNum:1,
            length: 0,
            currentIndex: 0
        }
    },
    props: {
        interval: {
            type: Number,
            default: 3000 //ms
        },
        duration: {
            type: Number,
            default: 600 //ms
        },
        liHeight: {
            type: Number,
            default: 0 //px
        },
        dHeight: {
            type: Number,
            default: 0 //px
        },
        direction: {
            validator (val){
                return val === 'up' || val === 'down';
            },
            default: 'up'
        }
    },
    mounted (){
        this.dealAppendNum();

    },
    methods: {

        initScroll(){
            let area = document.getElementById('m-marquee');
            let  ul1 = this.$refs.container;
            let  ul2 = this.$refs.containerCopy;
            area.scrollTop= 0;
            ul2.innerHTML = ul1.innerHTML;


        },
        /*
         * 根据方向将第一个或最后一个item复制添加到列表最后或前面,保证下一次轮播连贯
         * 将单个item高度设置为广播视窗高度
         */
        fixList (){
            let cloneNode,
                firstItem = this.$refs.container.firstElementChild;

            let children = this.makeArray(this.$refs.container.children);
            let appendUpChildren = children.slice(0,this.visibleLiNum);
            let appendDownChildren = children.slice(-this.visibleLiNum);

            // 根据item高度设置视窗container高度
            this.length = this.$refs.container.children.length;

            if(this.direction === 'up'){
                // 向上则clone第一个item置于列表末端
                for(let i=0; i< appendUpChildren.length; i++ ){
                    cloneNode = appendUpChildren[i].cloneNode(true);
                    this.$refs.container.appendChild(cloneNode);
                }

            }else{
                for(let i = appendDownChildren.length-1; i>=0; i-- ) {
                    // 向下则clone最后一个item置于列表首部
                    cloneNode = appendDownChildren[i].cloneNode(true);
                    this.$refs.container.insertBefore(cloneNode, firstItem);
                }
            }

            this.$nextTick(()=>{
                // 用总高度/length,减小较小
                this.height = this.$refs.container.offsetHeight / (this.length + 1);
            });
        },
        dealAppendNum(){
            this.visibleLiNum = 1; //容器高度能放下几个li
            if(this.liHeight && +this.liHeight>0) {
                this.$nextTick(()=>{
                    // 用总高度/length,减小较小
            });
                this.visibleLiNum  =  parseInt((+this.dHeight)/(+this.liHeight)) ;

            }
            let children = this.$refs.container.children;
            if (this.visibleLiNum >= children.length){
                return; //内容较少,不需要滚动
            }
            else {
                this.fixList();
                this.start();
            }

        },
        makeArray(obj){
        return Array.prototype.slice.call(obj,0);
    },
    /*
     * 启动轮播
     */
        start (){
            let currenTransitionTime,
                currenTranslateY;

            // 方向向下,列表初始时跳转到最后item
            if(this.direction === 'down')this.quickJump(false);

            setInterval(()=>{
                if(this.direction === 'up'){
                    this.currentIndex += 1;
                }else{
                    this.currentIndex -= 1;
                }

                // 正常轮播transition时间为用户设置duration时间
            // 1.匀速
            currenTransitionTime = 'transform ' + this.duration+ 'ms linear';
           // 2.每条有停顿
//                currenTransitionTime = 'transform ' + this.duration+ 'ms ease-in-out';
                this.setTransition(this.$refs.container, currenTransitionTime);

                // 正常轮播每次currenTranslateY增加一个item高度
                if(this.direction === 'up'){
                    currenTranslateY = -this.currentIndex * this.height + 'px';
                }else{
                    currenTranslateY = - (this.currentIndex + 1) * this.height + 'px';
                }

                this.setTransform(this.$refs.container, 'translate3d(0,' + currenTranslateY + ',0)');

                // 当滑动到首尾边界替补item时,需即刻跳转到正确item位置
                if(this.currentIndex == this.length){
                    setTimeout(()=>{
                        this.quickJump(true);
                    }, this.duration/2.5);
                }else if(this.currentIndex == -1){
                    setTimeout(()=>{
                        this.quickJump(false);
                    }, this.duration/2.5);
                }
            }, this.interval + this.duration);
        },
        /*
         * 设置transition 0ms,再设置translatet位置启动跳转
         * 由于跳转前后展现的内容完全一样,肉眼看不到跳转过程
         */
        quickJump (toFirst){            
            let currenTranslateY,
                    currenTransitionTime = 'transform 0ms linear';
//            currenTransitionTime = 'transform 0ms ease-in-out';

            this.setTransition(this.$refs.container, currenTransitionTime);

            if(toFirst){
                // 跳转到首个item
                this.currentIndex = 0;
                currenTranslateY = '0px';
            }else{
                this.currentIndex = this.length - 1;
                currenTranslateY = - (this.currentIndex + 1) * this.height + 'px';
            }

            this.setTransform(this.$refs.container, 'translate3d(0,' + currenTranslateY + ',0)');
        },
        /*
         * transition添加浏览器前缀
         * transform同
         */
        setTransition (ele, val){
            ele.style.transition = val;
            ele.style.WebkitTransition = '-webkit-' + val;
            ele.style.MozTransition = '-moz-' + val;
            ele.style.OTransition = '-o-' + val;
        },
        setTransform (ele, val){
            ele.style.transform = val;
            ele.style.WebkitTransform = val;
            ele.style.MozTransform = val;
            ele.style.OTransform = val;
        }
    }
}
</script>
<style lang="less">
    .zzui-broadcast-window{
        width: 100%;
        overflow: hidden;
        transform: translateZ(0);
        height: 100%;
        .zzui-broadcast-container{
            padding: 0;
            margin: 0;
            width: 100%;
            height: auto;
            li{
                margin: 0;
            }
        }
    }
</style>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值