我需要一个用户列表以垂直无限循环。
我知道我应该对这类内容使用“ translateY”而不是“ top”-但我不知道如何。
我已经完成了“热门”版本,并且可以使用。有什么想法可以改善吗?
谢谢你们!
Example in Codepen
<div id="app">
<div id="rows">
<div class="row" v-for="row in rows" v-bind:style="{ top: row.top + 'px' }">
{{row.id}}
</div>
</div>
</div>
<script>
const app = new Vue({
el: '#app',
data() {
return {
rows: []
}
},
created() {
for (let i = 0; i < 30; i++) {
this.rows.push({
id: i,
top: i * 40
})
}
setInterval(() => {
window.requestAnimationFrame(this.update);
}, 16);
},
methods: {
update() {
this.rows.forEach(row => {
row.top -= 0.5
});
if (this.rows[0].top <= -40) {
this.rows.push({
id: this.rows[0].id,
top: (this.rows.length - 1) * 40
})
this.rows.shift();
}
}
}
})
</script>
<style>
#rows {
position: relative;
}
.row {
position: absolute;
width: 100%;
height: 40px;
border: 1px solid black;
}
</style>
最佳答案
这是我的尝试:
new Vue({
el: '#app',
data() {
const rows = []
for (let i = 0; i < 30; i++) {
rows.push({
id: i
})
}
return {
offset: 0,
rows
}
},
mounted () {
this.frameTime = Date.now()
const animate = () => {
this.animationId = requestAnimationFrame(() => {
this.update()
animate()
})
}
animate()
},
beforeDestroy () {
cancelAnimationFrame(this.animationId)
},
methods: {
update() {
const now = Date.now()
const elapsed = now - this.frameTime
this.offset -= elapsed / 16
this.frameTime = now
if (this.offset < -400) {
while (this.offset < -40) {
this.rows.push(this.rows.shift())
this.offset += 40
}
}
}
}
})
* {
box-sizing: border-box;
}
#rows {
border: 1px solid #f00;
height: 200px;
overflow: hidden;
}
.row {
width: 100%;
height: 40px;
border: 2px solid black;
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<div id="rows">
<div :style="{ transform: `translateY(${Math.round(offset)}px)` }">
<div
v-for="row in rows"
:key="row.id"
class="row"
>
{{row.id}}
</div>
</div>
</div>
</div>
您不一定必须进行我所做的所有更改,如果愿意,可以有选择地进行大多数更改。主要变化是:
在列表项上放置一个
key
,以便Vue在发生随机播放时移动DOM节点,而不是更新所有节点。使用包装器
<div>
使得实际上只有一个元素在移动(在此过程中,我摆脱了绝对定位)。根据要求使用
translateY
。摆脱
setInterval
,您只需要requestAnimationFrame
。通过跟踪经过了多少时间来保持动画速度。当行跳转时,我只是将对象移到数组的末尾,而不是进行复制。
销毁组件后,动画将被取消。
更新:
三个进一步的变化:
我添加了
box-sizing: border-box
来修复计算中的2px错误。现在将DOM节点重新排序批处理为仅每400像素发生一次。不知道这是否真的是一个好主意,对于这样一个简单的示例,它实际上并没有任何区别。
我对
translateY
进行了四舍五入以使用整个像素。对我来说,这看起来稍微好一点,但是在像素比率更高的屏幕上,我可以想象它看起来会更糟。根据情况的不同,可能还会有进一步的优化。
不可见的行可以省略。
通过对每行应用
translateY
可以完全避免重新排序,尽管对于许多行而言可能不切实际。由于需要将行向下跳回底部,因此使用过渡或CSS动画对此进行动画处理将非常棘手。如果每一行都独立设置动画,我不确定保持所有动画同步有多么容易。