推送到数组不会触发 vue 的反应性
Posted
技术标签:
【中文标题】推送到数组不会触发 vue 的反应性【英文标题】:Pushing to array doesn't trigger vue's reactivity 【发布时间】:2019-11-20 16:26:16 【问题描述】:我已经知道在数组中编辑对象不适用于 vue.js,因为它的功能有限,并且基于我使用 vue.set 阅读的内容应该很容易解决这个问题,但我很难让它工作.
这是我的示例数据。父对象称为resource,resource里面有power_generator_groups,power_generator_groups里面有power_generators。
"id": 5,
"bg_member_id": 1,
"code": "G0633",
"name": "namex1",
"power_generator_groups": [
"id": 1,
"resource_id": 5,
"code": "GC033",
"power_generators": [
"id": 1,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
,
"id": 2,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
,
"id": 3,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
]
,
"id": 2,
"resource_id": 5,
"code": "GC033",
"contract_number": "065C001",
"power_generators": [
"id": 4,
"power_generator_group_id": 2,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
]
]
这是我的 vue 文件
<template lang="pug">
.wrapper
.animated.fadeIn
b-container(fluid='')
b-row.my-1
b-col(sm='3')
label(:for='`type-key`') companyName
b-col(sm='9')
b-form-select(v-model='item.bg_member_id' :options="companyList")
b-col(sm='3')
label(:for='`type-key`') code
b-col(sm='9')
b-form-input(v-model='item.code')
b-button(size='sm', @click='addPowerGeneratorGroup', variant="primary")
| Add power_generator_group
template(v-for='(group, group_index) in item.power_generator_groups')
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generator_groups
button.btn.btn-default.btn-sm(type='button' @click='deletePowerGeneratorGroup(group_index)')
span.fa.fa-trash-o
div
b-row.my-1
b-col(sm='3')
label(:for='`type-key`')
| code
b-col(sm='9')
b-form-input(v-model='group.code')
b-col(sm='3')
label(:for='`type-key`') group name
b-col(sm='9')
b-form-input(v-model='group.name')
b-col(sm='3')
label(:for='`type-key`') contract number
b-col(sm='9')
b-form-input(v-model='group.contract_number')
b-container.bv-example-row(fluid='')
b-button(size='sm', @click='addPowerGenerator(group_index)', variant="primary")
| add power_generator
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generators
b-table(small v-bind:item="group.power_generators" v-bind:fields="fields" fixed responsive)
template(v-for="field in fields" :slot="field.key" slot-scope="contract")
template(v-if="field.key == 'actions'")
b-button(size='sm', @click='deletePowerGenerator(group_index, contract.index)', variant="primary")
| Del
template(v-else)
b-form-input(:type='types[field.key]' v-model = 'contract.item[field.key]')
b-button(size='sm', @click='save', variant="primary")
| Save
</template>
<script>
import Vue from 'vue';
export default
props:
item:
type: Object,
required: true,
default: () =>
,
companyList: Array
,
data()
return
companyId: null,
code: null,
name: null,
contract_number: null,
fields: [
key: 'actions', label: '' ,
key: 'code', label: 'code', sortable: true, sortDirection: 'desc',
key: 'name', label: 'name', sortable: true, class: 'text-center',
key: 'contract_number', label: 'contractNo',
key: 'supply_max', label: 'maxunit'
],
types:
code: 'text',
name: 'text',
contract_number: 'text',
supply_max: 'number'
,
items:
,
mounted()
,
computed: ,
methods:
addPowerGenerator(index)
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
)
,
addPowerGeneratorGroup()
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
)
,
deletePowerGenerator(group_index, field_index)
this.item.power_generator_groups[group_index].power_generators.splice(field_index, 1);
,
deletePowerGeneratorGroup(group_index)
this.item.power_generator_groups.splice(group_index, 1);
,
save: function ()
this.$parent.save(this.item)
</script>
【问题讨论】:
我猜是因为数组在内存中的地址在推送时没有变化,所以没有检测到变化。 解决这个问题的方法是什么?我试过 vue.set 但没有运气 【参考方案1】:只有当 power_generator_groups
没有 power_generators
属性时,您才需要 Vue.set
,因为 Vue 无法检测到您何时添加它。
假设您的模板没有问题(您没有显示它),请更改您的 addPowerGenerator
方法:
addPowerGenerator(index)
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
)
Vue.set
返回您刚刚创建的属性,这就是pgs
在这种情况下包含正确引用的方式。
对你编辑的新方法做同样的事情:
addPowerGeneratorGroup()
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
)
You can see a mockup here 我假设this.item
指的是资源本身。我包括了第三组,它没有用于测试的 power_generators
属性。
【讨论】:
仍然对我不起作用,我认为这会起作用,但我认为问题出在我的其他方法上。我更新了问题,你可以检查一下吗? @obliviousfella - 如果您仔细阅读我的答案,您会发现它也解决了您刚刚发布的新方法的问题。您需要以同样的方式使用Vue.set
。我更新了模型给你看。
我尝试用你的 jsfiddle 替换我的代码,但我似乎无法让它工作,该数组在 console.log 中得到更新,但它只是不反映我的 UI 中的变化。也许我的模板有问题?
应该是,不然其他代码某处有错误。
因为它帮助我找到了问题,我会投票赞成,谢谢你的时间。以上是关于推送到数组不会触发 vue 的反应性的主要内容,如果未能解决你的问题,请参考以下文章