先上效果图:
(1) 看起来可能有点卡顿, 但是实际上页面上看起来挺顺畅的.
(2) 思路就是获取每一个列表的宽度, 设置定时器移动列表, 当移动的距离达到一个列表的宽度的时候, 把这个距离放到数组的最后. 这样就能达成无缝循环滚动了.
大致的情况就是下面这样:
接下来就是代码的实现:
index.vue 引入组件
- <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 组件页面
- <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 = Windows.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 值不会出现偏差的情况
(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 左右. 暂时没发现什么缺点...
来源: https://www.cnblogs.com/zjjDaily/p/10675708.html