javascript - VueJs 在一次更改后呈现所有元素

标签 javascript performance vue.js vue-component virtual-dom

我有以下示例网格,我在其中将一些新值推送到绑定(bind)列表。

按网格中的任意位置将新值推送到网格。

正如您在 fiddle 中所见,更新后的单元格将具有 绿色 颜色 500 毫秒,所有重新渲染的元素都将具有 黄色 颜色。

问题是我们应该如何配置 Vue 组件,以便它只重新渲染更改的元素而不是全部?

如果您查看 fiddle 控制台输出,您会看到类似 (13001, 26001, ...) 的数字,这等于所有单元格的数量(1000 行 x 13 列)。

.yellow {
  background-color: yellow;
}

.pushed {
  background-color: lightgreen
}
<script src="https://unpkg.com/vue">
  var globalCount = 0;
</script>


<head>
  <title>Vue Render Performance</title>
</head>
<div id="demo">
  <demo-grid :data="gridData" :columns="gridColumns"> </demo-grid>
</div>

<script type="text/x-template" id="grid-template">
  <table @click="pushData()">
    <thead>
      <tr>
        <th v-for="key in columns">
          {{key}}
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(entry, i) in data">
        <td v-for="(key, j) in columns" :id="'a'+i +'_'+j">
          {{renderMe(entry[key], 'a'+i +'_'+j)}}
        </td>
      </tr>
    </tbody>
  </table>
</script>


<script>
  const data = newData(1000);
  var renderedCount = 0;
  var startTime = performance.now();

  Vue.component('demo-grid', {
    props: {
      data: Array,
      columns: Array,
      renderCount: Object,
    },
    template: '#grid-template',
    methods: {
      renderMe(el, id) {

        const elm = document.getElementById(id);
        if (elm) {
          elm.className += " yellow";
        }

        if (!renderedCount) {
          renderedCount = 0
        } else {
          renderedCount++;
        }

        return el;
      },
      pushData() {
        debugger
        var push = function() {
          let cols = ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"];

          var t0 = performance.now();
          for (let i = 0; i < 1; i++) {
            let newVal = Math.random() * 10000,
              row = Math.round(Math.random() * 1000),
              cellIndex = Math.floor(Math.random() * cols.length);
            cell = cols[cellIndex];
            if (data[row])
              data[row][cell] = newVal;

            var el = document.querySelector('tbody tr:nth-child(' + row + ') td:nth-child(' +
              cellIndex +
              ')');

            if (el) {
              el.className = 'pushed';

              el.scrollIntoView();

              var t = function() {
                if (el) {
                  el.className = '';
                }
                clearTimeout(t);
              };

              setTimeout(t, 500);
            }

            console.log('pushed  to cell [' + row + ',' + cellIndex + '] :' + newVal);
            console.log('Rendered Count: ' + renderedCount)
            renderedCount++;
          };
          var t1 = performance.now();
          console.log(t1 - t0)
        };

        push();
      }
    }
  });


  // bootstrap the demo
  var demo = new Vue({
    el: '#demo',
    data: {
      searchQuery: '',
      gridColumns: ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"],
      gridData: data
    }
  })

  Vue.config.devtools = true;

  function newData(count) {
    const data = [];
    for (let i = 0; i < count; i++) {
      data.push({
        Col1: "Record",
        Col2: 818959475,
        Col3: 467587749,
        Col4: 438,
        Col5: 439,
        Col6: 440,
        Col7: 2.1,
        Col8: 436.2,
        Col9: 2.4,
        Col10: 5770,
        Col11: 5771,
        Col12: 5772,
        Col13: 5773
      });
    }

    return data;
  }
</script>

最佳答案

当您不想重新呈现整个信息列表时,处理它的典型方法是将需要重新呈现的内容推送到组件中。这是您的代码的更新版本,它将行推送到组件中并呈现您之前所做的一小部分。

Vue.component("demo-row", {
  props:["entry", "columns", "rowIndex"],
    template:`
        <tr>
            <td v-for="(key, j) in columns" :id="'a'+rowIndex +'_'+j">
                {{renderMe(entry[key], 'a'+rowIndex +'_'+j)}}
            </td>
        </tr>  
  `,
  methods:{
    renderMe(el, id) {

      const elm = document.getElementById(id);
      if (elm) {
        elm.className += " yellow";
      }

      if (!renderedCount) {
        renderedCount = 0
      } else {
        renderedCount++;
      }

      return el;
    },
    }
})

Vue.component('demo-grid', {
  props: {
    items: Array,
    columns: Array
  },
  template: '#grid-template',
  methods: {
    pushData() {
      this.$parent.pushData(this.$parent.gridItems, this.$parent.gridColumns);
    }
  }
});

Example codepen .

请注意,我没有改变您正在做的任何其他事情,这些事情可能可以在 Vue 中以更惯用的方式完成,我只是想证明没有必要一切重新渲染。

关于javascript - VueJs 在一次更改后呈现所有元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45456781/

相关文章:

java - Amazon DynamoDB 中的 MAX 操作

javascript - 引用 vue.js 数据但没有

javascript - leaflet.js WMS 图层缩放在双击时不起作用

javascript - 如何将变量放入 PhantomJS 生成的 HTML 标题中以进行 PDF 转换?

javascript - ASPX 页面中引用的文件不会导致调用 Application_BeginRequest

javascript - 显示弹出脚本以使其在每个浏览器 session 中仅弹出一次

c - switch语句的效率

performance - 可视化钢琴演奏评估

javascript - v-html 中的 Vue.js v-model

vue.js - vuejs 动态指令绑定(bind)到数据/计算值