VueJs在一次更改时呈现所有元素

时间:2017-08-02 09:26:48

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

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

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

正如您在小提琴中看到的那样,更新的单元格将具有500毫秒的green颜色,并且所有重新渲染的元素将具有yellow颜色。

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

如果你看一下小提琴控制台输出,你会看到像(13001,26001,...)这样的数字,这等于所有单元格的数量(1000行×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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

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

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中更具惯用性的事情,我只是想证明不需要所有来重新渲染。 / p>