vue 自定義marquee無縫滾動組件

先上效果圖:css

(1) 看起來可能有點卡頓,可是實際上頁面上看起來挺順暢的。vue

(2) 思路就是獲取每個列表的寬度,設置定時器移動列表,當移動的距離達到一個列表的寬度的時候,把這個距離放到數組的最後。這樣就能達成無縫循環滾動了。css3

 大體的狀況就是下面這樣:小程序

 

接下來就是代碼的實現:數組

index.vue 引入組件app

<template>
    <div>
        <marqueeLeft :send-val='send'></marqueeLeft >
    </div>
</template>
<script> import marqueeLeft from '../components/marquee' export default { data:function(){ return{ send:[{place: "來自東莞市的", name: "黃女士"}, {place: "來自太原市的", name: "吳先生"}, {place: "來自常州市的", name: "戚先生"}, {place: "來自金華市的", name: "尤先生"}, {place: "來自貴陽市的", name: "陳女士"}, {place: "來自長春市的", name: "魏女士"}, {place: "來自泉州市的", name: "褚先生"}, {place: "來自南昌市的", name: "蔣女士"}, {place: "來自南京市的", name: "沈先生"}, {place: "來自天津市的", name: "韓先生"}, {place: "來自寧波市的", name: "鄒女士"}, {place: "來自嘉興市的", name: "周女士"}, {place: "來自長沙市的", name: "秦先生"}, {place: "來自濟南市的", name: "孫女士"}, {place: "來自杭州市的", name: "楊先生"}] } }, components:{ marqueeLeft }, } </script>

  

marquee.vue 組件頁面less

<template>
    <div class="my-outbox">
        <div class="my-inbox" ref='box'>
            <div class="my-list" v-for="(item,index) in sendVal" :key='index' ref='list'> {{item.place}}<span class="my-uname">{{item.name}}</span>剛剛購買了產品 </div>
        </div>
    </div>
</template>

<script> export default { name:'my-marquee-left', props:{ sendVal:Array }, data() { return { nowTime:null,//定時器標識
 disArr:[],//每個內容的寬度
 } }, mounted:function(){ var that = this; var item = this.$refs.list; var len = this.sendVal.length; var arr = []; var margin = this.getMargin(item[0]) //由於設置的margin值同樣,因此取第一個就行。
            for(var i = 0;i < len;i++){ arr.push(item[i].clientWidth + margin)//把寬度和 margin 加起來就是每個元素須要移動的距離
 } this.disArr = arr; this.moveLeft(); }, beforeDestroy:function(){ clearInterval(this.nowTime);//頁面關閉清除定時器
            this.nowTime = null;//清除定時器標識
 }, methods:{ //獲取margin屬性
 getMargin:function(obj){ var marg = window.getComputedStyle(obj,null)['margin-right']; marg = marg.replace('px','') return Number(marg) //強制轉化成數字
 }, //移動的方法
 moveLeft:function(){ var outbox = this.$refs.box; var that=this; var startDis = 0;//初始位置
                this.nowTime = setInterval(function(){ startDis -= 0.5; if(Math.abs(startDis) > Math.abs(that.disArr[0])){ that.disArr.push(that.disArr.shift())//每次移動完一個元素的距離,就把這個元素的寬度
 that.sendVal.push(that.sendVal.shift())//每次移動完一個元素的距離,就把列表數據的第一項放到最後一項
 startDis = 0; } outbox.style = 'transform: translateX('+ startDis +'px)'; //每次都讓盒子移動指定的距離 },1000/60)
 } } } </script>

<style lang="less" scoped> .my-outbox{ color: #D7BC8D; overflow: hidden; height: 35px; background: #422b02; .my-inbox{ white-space: nowrap; .my-list{ margin-right: 25px; display: inline-block; font-size: 13px; height: 35px; line-height: 35px; .my-uname{ color: #FF8900;
                } } } } </style>

(1) 添加一個獲取margin的方法,是爲了保證若是是使用 rem em 等單位時,margin值不會出現誤差的狀況dom

(2) 若是引入組件的頁面中,send-val的值是異步請求的。那麼,在marquee.vue組件頁面,多數狀況會獲取不了 refs 。這時候我本身的解決方法是:異步

<marqueeLeft :send-val='send' v-if='send'></marqueeLeft >

    表示只有當 send 不爲空的時候才渲染該組件,不過這種狀況會致使若是 請求響應太慢,組件會一直渲染不出來,就可能會影響佈局。佈局

(3) 若是不想每次都去設置transform,那麼能夠把transform放到該元素上,而後修改data中的數據就好了,好比:

<div class="my-inbox" :style='transform: translateX('+ cssStyle +'px)'></div> // 而後在 js 中把 每次移動的值,賦值給cssStyle就好了。不過我感受這種沒什麼區別

  

若是想實現,上下無縫滾動,這種效果。思路和左右無縫滾動同樣,基本上只須要把 transform 改爲 Y軸移動 ,每一個列表的寬度改爲高度就好了。

不清楚這種方式實現是否會有什麼問題,FPS一直保持在 接近60左右。暫時沒發現什麼缺點。。。

  


  

更新一下: 作了一個uniapp版本(小程序端也支持)的無縫滾動,內容和上面這個差很少,可是比上面這個更好一點,不用 16.6ms 左右的時間去更新 data裏面的數據

 

<!-- 從右往左滾動的信息欄 -->
<!-- <myMarqueeLeft :send-val="marqueeLeft(須要動態傳入的數據)" v-if='marqueeLeft(須要動態傳入的數據'></myMarqueeLeft> -->
<template>
    <view class="my-outbox">
        <view class="my-inbox" :style="cssStyle">
            <view class="my-list" v-for="(item,index) in sendVal" :key='index'> {{item.place}}<text class="my-uname">{{item.name}}</text>剛剛購買了產品 </view>
        </view>
    </view>
</template>

<script> export default { name:'my-marquee-left', props:{ sendVal:Array }, data() { return { nowTime:null,//定時器標識
 disArr:[],//每個內容的寬度
 cssDis:0,//當前須要移動的距離
 cssStyle:''//當前須要設置的css樣式
 } }, mounted:function(){ var that = this; //兼容小程序獲取不了內容的狀況,須要用setTimeout延時
 setTimeout(function(){ var target = uni.createSelectorQuery(); target.selectAll('.my-list').boundingClientRect() target.exec(function(msg){ var tdata = msg[0]; var len = tdata.length; for(var i = 0;i < len;i++){ that.disArr.push(tdata[i].width + 25)//把寬度和 margin 加起來就是每個元素須要移動的距離
 } that.moveLeft(); }) },200) }, beforeDestroy:function(){ clearInterval(this.nowTime);//頁面關閉清除定時器
            this.nowTime = null;//清除定時器標識
 }, methods:{ //移動的方法
 moveLeft:function(){ var that=this; that.cssDis = that.disArr[0]; that.cssStyle = 'transform: translateX(-'+ that.cssDis +'px);transition: all 10s linear;'; that.nowTime = setInterval(function(){ that.cssStyle = 'transform: translateX(0);'; that.disArr.push(that.disArr.shift()) that.sendVal.push(that.sendVal.shift()) that.cssDis = that.disArr[0]; //必須等到dom更新完畢才設置內容
                    // #ifdef H5
 that.$nextTick(function(){ that.cssStyle = 'transform: translateX(-'+ that.cssDis +'px);transition: all 10s linear;'; }) // #endif
                    
                    // #ifdef MP-BAIDU
 swan.nextTick(function(){ that.cssStyle = 'transform: translateX(-'+ that.cssDis +'px);transition: all 10s linear;'; }) // #endif
                    
                    // #ifdef MP-WEIXIN
 wx.nextTick(function(){ that.cssStyle = 'transform: translateX(-'+ that.cssDis +'px);transition: all 10s linear;'; }) // #endif
 },10000) } } } </script>

<style lang="scss" scoped>
    /** * @include的公共樣式都在根目錄下的uni.scss中 */ .my-outbox{ color: #D7BC8D; overflow: hidden; height: 70upx; .my-inbox{ white-space: nowrap; .my-list{ margin-right: 25px;//不要轉換成upx display: inline-block; font-size: 26upx; @include lineH(70upx); .my-uname{ color: #FF8900;
                } } } } </style>

1) 換了種思路,這樣就是每隔 10s 纔去更新 data裏面的數據,並且移動的過程也是使用 css3 transition 進行過分,保證了流暢性。若是想移動快一點,就修改transition的時間,不過也不要忘了修改對應settinterval的時間哦。

(2) 若是用 更新前的那種方法,在小程序端會有明顯的卡頓,而且內存佔用比較高。

(3) 樣式無變化,主要就是 js 進行了改變

(3) @include lineH(70upx)  是  height:70upx;line-height:70upx;

(4)  上下滾動的改變也是同樣的思路。

相關文章
相關標籤/搜索