如何优化表示以列组织的数据的表上的数据绑定

Posted

技术标签:

【中文标题】如何优化表示以列组织的数据的表上的数据绑定【英文标题】:How to optimize data binding on table representing data organized as columns 【发布时间】:2018-07-07 13:19:24 【问题描述】:

在显示以表格的列组织的数据时,我不知道如何正确使用计算属性。 我的代码的完整示例可在jsfiddle 获得,这里是简短版本和描述。 我想将此数据呈现为表格:

var vueData = 
  objects: [
    
      name: "objectName",
      objectData: [
        prop1: "val1", prop2: "val2"
      ]
    
  ]

在此vueData 中,objectData 数组的每个元素都应显示为一列(该列表示一个月或一天的数据)。 objectData 元素中的道具不应按原样显示,而应显示为计算值。并且显示的值应该反映vueData的变化。

于是我来到了这个vue模板:

<table>
<tr>
  <th>Object Name</th>
  <th>Data Piece 1</th>
  <th>Data Piece 2</th>
</tr>
<template v-for="obj in objects">
<tr> 
  <th rowspan="2"> obj.name </th>
  <td v-for="dataPiece in obj.objectData"> compute(dataPiece.prop1) </td>
</tr>
<tr><td v-for="dataPiece in obj.objectData"> compute(dataPiece.prop2) </td></tr>
</template>
</table>

除了我使用了方法,而不是 vue 的计算属性之外,一切都很好。方法的问题在于它们的结果不会缓存,并且在单个 prop 更改后,ALL 单元格的值会被重新计算。

我可以为每个具有计算属性的单元格使用一个 vue 组件,而不是 tds ,但它看起来有点矫枉过正,因为表格可能很大。

从 vue 的角度来看,还有其他解决方案吗? (我的意思是不改变表格的数据结构或外观等)。

【问题讨论】:

这是 Vue 中极少数的缺点之一:无法创建动态计算。我最好的想法是在你的 compute 函数中实现缓存。 尝试这篇文章的第二个答案,它应该会有所帮助:***.com/questions/40322404/… 【参考方案1】:

我本来想用一个指令来做这个,但是没有很好的方法来传递函数和参数,直到我记得我可以使用vnode.context 来获取上下文,在那里我可以通过名称而不是传递来查找函数它作为一个实际的功能。

所以这是一个指令,它使用函数调用的结果更新其元素的textContent

var vueData = 
  objects: [
      name: 'Object 1',
      objectData: [
          prop1: '1-1-1',
          prop2: '1-1-2'
        ,
        
          prop1: '1-2-1',
          prop2: '1-2-2'
        ,
        
          prop1: '1-3-1',
          prop2: '1-3-2'
        
      ]
    ,
    
      name: 'Object 2',
      objectData: [
          prop1: '2-1-1',
          prop2: '2-1-2'
        ,
        
          prop1: '2-2-1',
          prop2: '2-2-2'
        ,
        
          prop1: '2-3-1',
          prop2: '2-3-2'
        
      ]
    ,
    
      name: 'Object 3',
      objectData: [
          prop1: '3-1-1',
          prop2: '3-1-2'
        ,
        
          prop1: '3-2-1',
          prop2: '3-2-2'
        ,
        
          prop1: '3-3-1',
          prop2: '3-3-2'
        
      ]
    ,
  ]
;

var vue = new Vue(
  el: document.getElementById("vue"),
  data: vueData,
  methods: 
    compute: function(prop) 
      console.log('computing ' + prop);
      return 'computed(' + prop + ')';
    
  ,
  directives: 
    cache(el, binding, vnode) 
      if (binding.value !== binding.oldValue) 
        el.textContent = vnode.context[binding.arg](binding.value);
      
    
  ,
  computed: 
    firstProp: function() 
      return this.objects[0].objectData[0].prop1;
    
  
);

setTimeout(function() 
  vueData.objects[0].objectData[0].prop1 = 'changed on timeout';
, 3000);
th,
td 
  border: 1px solid black;
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="vue">
  <table>
    <tr>
      <th>Object Name</th>
      <th>Data Piece 1</th>
      <th>Data Piece 2</th>
      <th>Data Piece 3</th>
    </tr>
    <template v-for="obj in objects">
      <tr>
        <th rowspan="2"> obj.name </th>
        <td v-for="dataPiece in obj.objectData"
          v-cache:compute="dataPiece.prop1"
          >
        </td>
      </tr>
      <tr>
        <td v-for="dataPiece in obj.objectData"
          v-cache:compute="dataPiece.prop2">
        </td>
      </tr>
    </template>
  </table>
  <span>Computed prop1 value =  firstProp </span>
</div>

【讨论】:

@RichardMatsen 这个有点轻。【参考方案2】:

我看到了 LinusBorg Generating computed properties on the fly 的这篇文章,其中他展示了一个将属性映射到计算属性的函数。

我为您的 objects 变量调整了函数,因为原来的函数更侧重于平面数据(也有点吓人)。

function mapObjectToComputed(objects) 
  console.log(objects)
  let res = ;
  objects.forEach((obj,i) => 
    obj.objectData.forEach((dat,j) => 
      ['prop1', 'prop2'].forEach(prop => 
        const propModel = `objects_$i_$j_$prop`;
        const computedProp = 
          get() 
            console.log(`Getting $propModel`)
            const val = this.objects[i].objectData[j][prop];
            return val;
          
        
        res[propModel] = computedProp;
      )
    )
  )
  return res;

这是模板的内部部分。我已将 prop1 更改为新语法,并保留了 prop2

<template v-for="(obj, i) in objects">
  <tr> 
    <th rowspan="2"> obj.name </th>
    <td v-for="(dataPiece, j) in obj.objectData">
       fetch(i,j,'prop1') 
    </td>
  </tr>
  <tr><td v-for="dataPiece in obj.objectData">
     compute(dataPiece.prop2) 
  </td></tr>
</template>

组件是

var vue = new Vue(
    el: document.getElementById("vue"),
  data: vueData,
  methods: 
    fetch: function(i,j,prop) 
      const propModel = `objects_$i_$j_$prop`
      return this[propModel];
    ,
    compute: function(prop) 
        console.log('computing ' + prop);
        return 'computed(' + prop + ')';
    
  ,
  computed: 
    firstProp: function() 
        return this.objects[0].objectData[0].prop1;
    ,
    ...mapObjectToComputed(vueData)
  
);

超时后的控制台是

Getting objects_0_0_prop1  
computing 1-1-2  
computing 1-2-2  
computing 1-3-2  
computing 2-1-2  
computing 2-2-2  
computing 2-3-2  
computing 3-1-2  
computing 3-2-2  
computing 3-3-2  

所以只有prop2 全面重新计算。

这里是Fiddle

【讨论】:

set 没有被使用,如果使用的话会出错。 干杯,get也需要使用枚举属性。 无法调用计算函数,所以结果不对。他们没有说“计算”。 其实想法是替换compute函数——但是那个函数显然可以传入。 我将函数定义移到了 Vue 之外,以便 map 函数可以使用它。 jsfiddle.net/47wkovgj/1【参考方案3】:

正如您所提到的,您可以使用组件。这是我找到的最干净的解决方案。该组件非常简单,已针对此示例进行了调整。如果计算特别昂贵,则可能值得使用。

var vueData = 
  objects: [
      name: 'Object 1',
      objectData: [
          prop1: '1-1-1',
          prop2: '1-1-2'
        ,
        
          prop1: '1-2-1',
          prop2: '1-2-2'
        ,
        
          prop1: '1-3-1',
          prop2: '1-3-2'
        
      ]
    ,
    
      name: 'Object 2',
      objectData: [
          prop1: '2-1-1',
          prop2: '2-1-2'
        ,
        
          prop1: '2-2-1',
          prop2: '2-2-2'
        ,
        
          prop1: '2-3-1',
          prop2: '2-3-2'
        
      ]
    ,
    
      name: 'Object 3',
      objectData: [
          prop1: '3-1-1',
          prop2: '3-1-2'
        ,
        
          prop1: '3-2-1',
          prop2: '3-2-2'
        ,
        
          prop1: '3-3-1',
          prop2: '3-3-2'
        
      ]
    ,
  ]
;

var vue = new Vue(
  el: document.getElementById("vue"),
  data: vueData,
  methods: 
    compute: function(prop) 
      console.log('computing ' + prop);
      return 'computed(' + prop + ')';
    
  ,
  components: 
    cacheResult: 
      props: 
        fn: Function,
        arg: String
      ,
      template: '<td>fn(arg)</td>'
    
  ,
  computed: 
    firstProp: function() 
      return this.objects[0].objectData[0].prop1;
    
  
);

setTimeout(function() 
  vueData.objects[0].objectData[0].prop1 = 'changed on timeout';
, 3000);
th,
td 
  border: 1px solid black;
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="vue">
  <table>
    <tr>
      <th>Object Name</th>
      <th>Data Piece 1</th>
      <th>Data Piece 2</th>
      <th>Data Piece 3</th>
    </tr>
    <template v-for="obj in objects">
      <tr>
        <th rowspan="2"> obj.name </th>
        <td v-for="dataPiece in obj.objectData"
          is="cacheResult"
          :fn="compute"
          :arg="dataPiece.prop1"
          >
        </td>
      </tr>
      <tr>
        <td v-for="dataPiece in obj.objectData"
          is="cacheResult"
          :fn="compute"
          :arg="dataPiece.prop2">
        </td>
      </tr>
    </template>
  </table>
  <span>Computed prop1 value =  firstProp </span>
</div>

【讨论】:

美观紧凑,组件内的一切。 你如何解释caching效应? 如果 props 没有改变,则组件不会更新。 可能有点太简洁了——我们看到的是&lt;td&gt; 与原版没有什么不同。为什么行为不同? 因为它是一个组件,所以就其 props 而言,它类似于 computed:如果没有 props 发生变化,Vue 知道它不需要对组件做任何事情。它只更新依赖于已更改数据的内容。方法调用不是依赖跟踪的一部分,因此必须在每次更新时进行评估。

以上是关于如何优化表示以列组织的数据的表上的数据绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何在 EF Code First 中声明具有 Medium Blob 数据类型的表上的字段

如何应用嵌套在 div 内的表上的 jquery?

如何解决空数据库表上的乐观并发异常错误

获取ajax内容的表上的数据表

我已将未组织的数据转换为 Microsoft Access 上的表,我应该如何移动信息以组织该数据库?

不在数据库中的表上的外键,使用 ORM