Vue.js-改善无限列表循环的性能

时间:2019-07-15 12:40:13

标签: javascript css vue.js animation

我需要一个用户列表来垂直无限循环。 我知道我应该对这类内容使用“ translateY”而不是“ top”-但我不知道如何。 我已经完成了“热门”版本,并且可以使用。有什么想法可以改善它吗?

谢谢大家!

Example in Codepen

<table class="userList w990 marginTop10">
  <tbody>
    <tr>
      <th class="w195 whiteFont leftAlign">Status</th>
      <td class="even width150" id="status">Active</td>
      <th class="w195 whiteFont leftAlign">Name</th>
      <td class="even" id="name"> NATESAN</td>
    </tr>
  </tbody>
</table>

1 个答案:

答案 0 :(得分:1)

这是我的尝试:

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/vue@2.6.10/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>

您不一定必须进行我所做的所有更改,如果愿意,可以有选择地进行大多数更改。主要变化是:

  1. 在列表项上放置key,以便Vue在发生混洗时移动DOM节点,而不是更新所有DOM节点。
  2. 使用包装器<div>,这样实际上只有一个元素在移动(为此,我摆脱了绝对定位)。
  3. 根据要求使用translateY
  4. 摆脱setInterval,您只需要requestAnimationFrame。通过跟踪经过了多少时间来检查动画速度。
  5. 当行跳转时,我只是将对象移到数组的末尾,而不是进行复制。
  6. 在销毁组件时取消动画。

更新

三个进一步的变化:

  1. 我添加了box-sizing: border-box来解决计算中2px的误差。
  2. 现在已对DOM节点重新排序进行批处理,仅每400像素发生一次。不知道这是否真的是一个好主意,对于这样一个简单的示例,它实际上并没有任何作用。
  3. 我将translateY舍入为整像素。对我来说,这看起来稍微好一点,但是在像素比率更高的屏幕上,我可以想象它看起来会更糟。

视情况而定,还有其他优化可能适用。

  1. 不可见的行可以省略。
  2. 通过对每行应用translateY可以完全避免重新排序,尽管对于很多行来说可能并不实际。

使用过渡或CSS动画对此进行动画处理将非常棘手,因为需要将行向下跳回到底部。如果每一行都独立设置动画,我不确定保持所有动画同步有多么容易。