使用 v-model 更改单个值 / full table 被重绘
changing a single value using v-model / full table is redrawn
我正在构建一个 editable table,当行数开始达到 运行 的 100 行时,它开始爬行停止。这促使我调查发生了什么。
在下面的例子中,当改变输入中的值时,整个table被重新绘制,并且ifFunction()
函数被触发了4次。
为什么会这样? Vue 不应该能够重绘相应的单元格吗?我是不是按键绑定有问题?
<template>
<div id="app">
<table border="1" cellpadding="10">
<tr v-for="(row, rowKey) in locations" :key="`row_+${rowKey}`">
<td v-for="(column, columnKey) in row" :key="`row_+${rowKey}+column_+${columnKey}`">
<span v-if="ifFunction()">{{ column }}</span>
</td>
</tr>
</table>
<input v-model="locations[0][1]">
</div>
</template>
<script>
export default {
data() {
return {
locations: [
["1","John"],
["2","Jake"]
], // TODO : locations is not generic enough.
}
},
methods: {
ifFunction() {
console.log('ifFunction');
return true;
},
}
}
</script>
data
属性 定义反应元素 - 如果您更改其中的一部分,将重新计算依赖于那部分 data
的所有内容。
您可以将 computed
属性用于 "cache" 值,并且只更新真正需要更新的那些。
我重建了您的组件,因此可以在整个过程中使用计算属性:创建了一个 cRow
和一个 cCell
组件("custom row" 和 "custom cell")并重新构建了 table 来自这些组件。行和单元格组件每个都有一个计算的 属性 "proxies" prop
到模板 - 因此也缓存它。
在第一次渲染时,您会看到四次 ifFunction()
(这是基于 Vue[=35 中的 data
属性 的单元格数量=] 实例),但是如果您使用输入字段更改值,您只会看到一次(每次更新;您可能必须单击 "Full page" 才能更新值)。
Vue.component('cCell', {
props: {
celldata: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
coords: {
type: Array,
required: true
}
},
data() {
return {
normalCellData: ''
}
},
watch: {
normalCellData: {
handler: function(value) {
this.$emit('cellinput', {
coords: this.coords,
value
})
},
immediate: false
}
},
template: `<td v-if="ifFunction()"><span v-if="!isInput">{{normalCellData}}</span> <input v-else type="text" v-model="normalCellData" /></td>`,
methods: {
ifFunction() {
console.log('ifFunction');
return true;
},
},
mounted() {
this.normalCellData = this.celldata
}
})
Vue.component('cRow', {
props: {
rowdata: {
type: Array,
required: true
},
rownum: {
type: Number,
required: true
}
},
template: `
<tr>
<td
is="c-cell"
v-for="(item, i) in rowdata"
:celldata="item"
:is-input="!!(i % 2)"
:coords="[i, rownum]"
@cellinput="reemit"
></td>
</tr>`,
methods: {
reemit(data) {
this.$emit('cellinput', data)
}
}
})
new Vue({
el: "#app",
data: {
locations: [
["1", "John"],
["2", "Jake"]
], // TODO : locations is not generic enough.
},
methods: {
updateLocations({
coords,
value
}) {
// creating a copy of the locations data attribute
const loc = JSON.parse(JSON.stringify(this.locations))
loc[coords[1]][coords[0]] = value
// changing the whole locations data attribute to preserve
// reactivity
this.locations = loc
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table border="1" cellpadding="10">
<tbody>
<tr v-for="(row, i) in locations" is="c-row" :rowdata="row" :rownum="i" @cellinput="updateLocations"></tr>
</tbody>
</table>
<!-- <input v-model="locations[0][1]">
<input v-model="locations[1][1]">-->
{{locations}}
</div>
我正在构建一个 editable table,当行数开始达到 运行 的 100 行时,它开始爬行停止。这促使我调查发生了什么。
在下面的例子中,当改变输入中的值时,整个table被重新绘制,并且ifFunction()
函数被触发了4次。
为什么会这样? Vue 不应该能够重绘相应的单元格吗?我是不是按键绑定有问题?
<template>
<div id="app">
<table border="1" cellpadding="10">
<tr v-for="(row, rowKey) in locations" :key="`row_+${rowKey}`">
<td v-for="(column, columnKey) in row" :key="`row_+${rowKey}+column_+${columnKey}`">
<span v-if="ifFunction()">{{ column }}</span>
</td>
</tr>
</table>
<input v-model="locations[0][1]">
</div>
</template>
<script>
export default {
data() {
return {
locations: [
["1","John"],
["2","Jake"]
], // TODO : locations is not generic enough.
}
},
methods: {
ifFunction() {
console.log('ifFunction');
return true;
},
}
}
</script>
data
属性 定义反应元素 - 如果您更改其中的一部分,将重新计算依赖于那部分 data
的所有内容。
您可以将 computed
属性用于 "cache" 值,并且只更新真正需要更新的那些。
我重建了您的组件,因此可以在整个过程中使用计算属性:创建了一个 cRow
和一个 cCell
组件("custom row" 和 "custom cell")并重新构建了 table 来自这些组件。行和单元格组件每个都有一个计算的 属性 "proxies" prop
到模板 - 因此也缓存它。
在第一次渲染时,您会看到四次 ifFunction()
(这是基于 Vue[=35 中的 data
属性 的单元格数量=] 实例),但是如果您使用输入字段更改值,您只会看到一次(每次更新;您可能必须单击 "Full page" 才能更新值)。
Vue.component('cCell', {
props: {
celldata: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
coords: {
type: Array,
required: true
}
},
data() {
return {
normalCellData: ''
}
},
watch: {
normalCellData: {
handler: function(value) {
this.$emit('cellinput', {
coords: this.coords,
value
})
},
immediate: false
}
},
template: `<td v-if="ifFunction()"><span v-if="!isInput">{{normalCellData}}</span> <input v-else type="text" v-model="normalCellData" /></td>`,
methods: {
ifFunction() {
console.log('ifFunction');
return true;
},
},
mounted() {
this.normalCellData = this.celldata
}
})
Vue.component('cRow', {
props: {
rowdata: {
type: Array,
required: true
},
rownum: {
type: Number,
required: true
}
},
template: `
<tr>
<td
is="c-cell"
v-for="(item, i) in rowdata"
:celldata="item"
:is-input="!!(i % 2)"
:coords="[i, rownum]"
@cellinput="reemit"
></td>
</tr>`,
methods: {
reemit(data) {
this.$emit('cellinput', data)
}
}
})
new Vue({
el: "#app",
data: {
locations: [
["1", "John"],
["2", "Jake"]
], // TODO : locations is not generic enough.
},
methods: {
updateLocations({
coords,
value
}) {
// creating a copy of the locations data attribute
const loc = JSON.parse(JSON.stringify(this.locations))
loc[coords[1]][coords[0]] = value
// changing the whole locations data attribute to preserve
// reactivity
this.locations = loc
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table border="1" cellpadding="10">
<tbody>
<tr v-for="(row, i) in locations" is="c-row" :rowdata="row" :rownum="i" @cellinput="updateLocations"></tr>
</tbody>
</table>
<!-- <input v-model="locations[0][1]">
<input v-model="locations[1][1]">-->
{{locations}}
</div>