在显示组织为带有表的列的数据时,我无法正确使用计算属性。 我的代码的完整示例位于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的计算属性外,一切正常。方法的问题在于它们的结果不会缓存,并且在单个支柱更改后所有单元格&#39;值被重新计算。
我可以为每个具有计算属性而不是td
s的单元格使用vue组件,但它看起来有点过分,因为表格可能很大。
从vue的角度来看还有其他解决方案吗? (我的意思是不改变数据结构或表的外观等)。
答案 0 :(得分:1)
我通过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
答案 1 :(得分:1)
如您所述,您可以使用组件。这是我发现的最干净的解决方案。该组件非常简单,已针对此示例进行了调整。如果计算特别昂贵,可能值得使用。
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);
&#13;
th,
td {
border: 1px solid black;
}
&#13;
<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>
&#13;
答案 2 :(得分: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>