我有一个vue实例将对象传递给子组件 . 子组件有一个复选框,单击该复选框时,调用vue实例处理的事件以更新传递给子组件的父对象 . 基于vue documentation我认为这会导致子组件更新相关字段 . 但是,当我单击复选框时,日期字段不会像我期望的那样更新 . 在下图中,当我选中管理名称复选框时,我希望当天出现,但我没有看到任何日期 . 我在这里错过了什么?
设计
父实例
new Vue({
el: "#evaluations-app",
data: {
evaluation: new Evaluation()
},
methods: {
updateEmployeeSO: function (newSO, newSODate) {
this.evaluation.EmployeeSO = newSO;
this.evaluation.EmployeeSODate = newSODate;
},
updateReviewerSO: function (newSO, newSODate) {
this.evaluation.ReviewerSO = newSO;
this.evaluation.ReviewerSODate = newSODate;
},
updateManagementSO: function (newSO, newSODate) {
this.evaluation.ManagementSO = newSO;
this.evaluation.ManagementSODate = newSODate;
}
});
子组件
Vue.component('sign-off', {
props: ['initEvaluation', 'perspective'],
template: `
<div class="sign-off-comp">
<div class="sign-off-item">
<div class="sign-off-field-1 col-1">{{evaluation.EmployeeName}}</div>
<input :disabled="!enableEmployeeSO" v-model="evaluation.EmployeeSO" class="sign-off-field-2 col-2" type="checkbox" @click="EmployeeSOChanged"/>
<div class="sign-off-field-3 col-3">{{employeeSODate}}</div>
</div>
<div class="sign-off-item">
<div class="sign-off-field-1 col-1">{{evaluation.ReviewerName}}</div>
<input :disabled="!enableReviewerSO" v-model="evaluation.ReviewerSO" class="sign-off-field-2 col-2" type="checkbox" @click="ReviewerSOChanged"/>
<div class="sign-off-field-3 col-3">{{reviewerSODate}}</div>
</div>
<div class="sign-off-item">
<div class="sign-off-field-1 col-1">{{evaluation.ManagementName}}</div>
<input :disabled="!enableManagementSO" v-model="evaluation.ManagementSO" class="sign-off-field-2 col-2" type="checkbox" @click="ManagementSOChanged"/>
<div class="sign-off-field-3 col-3">{{managementSODate}}</div>
</div>
</div>
`,
data: function () {
return {
evaluation: this.initEvaluation,
employeeClicked: false,
reviewerClicked: false,
managementClicked: false,
currentCommentSource: this.perspective
}
},
methods: {
EmployeeSOChanged: function () {
this.employeeClicked = true;
//this.evaluation.EmployeeSODate == null || this.evaluation.EmployeeSODate == "" ? this.evaluation.EmployeeSODate = Helpers.getCurrentDate() : this.evaluation.EmployeeSODate = "";
this.$emit('employee-so-changed', this.evaluation.EmployeeSO, this.evaluation.EmployeeSODate);
},
ReviewerSOChanged: function () {
this.reviewerClicked = true;
//this.evaluation.ReviewerSODate == null || this.evaluation.ReviewerSODate == "" ? this.evaluation.ReviewerSODate = Helpers.getCurrentDate() : this.evaluation.ReviewerSODate = "";
this.$emit('reviewer-so-changed', this.evaluation.ReviewerSO, this.evaluation.ReviewerSODate);
},
ManagementSOChanged: function () {
this.managementClicked = true;
//this.evaluation.ManagementSODate == null || this.evaluation.ManagementSODate == "" ? this.evaluation.ManagementSODate = Helpers.getCurrentDate() : this.evaluation.ManagementSODate = "";
this.$emit('management-so-changed', this.evaluation.ManagementSO, this.evaluation.ManagementSODate == null || this.evaluation.ManagementSODate == "" ? Helpers.getCurrentDate() : "");
}
},
computed: {
enableEmployeeSO: function () {
return (this.perspective == "Employee" && !this.evaluation.EmployeeSO) || this.employeeClicked;
},
enableReviewerSO: function () {
return (this.perspective == "Reviewer" && !this.evaluation.ReviewerSO && this.evaluation.EmployeeSO) || this.reviewerClicked;
},
enableManagementSO: function () {
return (this.perspective == "Management" && !this.evaluation.ManagementSO && this.evaluation.ReviewerSO && this.evaluation.EmployeeSO) || this.managementClicked;
},
employeeSODate: function () {
return this.evaluation.EmployeeSODate != null && this.evaluation.EmployeeSODate == new Date("01-01-1900") ? "" : this.evaluation.EmployeeSODate != null && this.evaluation.EmployeeSODate.length >= 10 ? this.evaluation.EmployeeSODate.substring(0, 10) : this.evaluation.EmployeeSODate;
},
reviewerSODate: function () {
return this.evaluation.ReviewerSODate != null && this.evaluation.ReviewerSODate == new Date("01-01-1900") ? "" : this.evaluation.ReviewerSODate != null && this.evaluation.ReviewerSODate.length >= 10 ? this.evaluation.ReviewerSODate.substring(0, 10) : this.evaluation.ReviewerSODate;
},
managementSODate: function () {
return this.evaluation.ManagementSODate != null && this.evaluation.ManagementSODate == new Date("01-01-1900") ? "" : this.evaluation.ManagementSODate != null && this.evaluation.ManagementSODate.length >= 10 ? this.evaluation.ManagementSODate.substring(0, 10) : this.evaluation.ManagementSODate;
}
}
});
型号
export class Evaluation {
private _EmployeeName: string;
private _EmployeeSO: boolean;
private _EmployeeSODate: Date;
private _ReviewerName: string;
private _ReviewerSO: boolean;
private _ReviewerSODate: Date;
private _ManagementReviewerName: string;
private _ManagementReviewerSO: boolean;
private _ManagementReviewerSODate: Date;
constructor() {
this._EmployeeName = "";
this._EmployeeSO = false;
this._EmployeeSODate = new Date("01-01-1900");
this._ReviewerName = "";
this._ReviewerSO = false;
this._ReviewerSODate = new Date("01-01-1900");
this._ManagementReviewerName = "";
this._ManagementReviewerSO = false;
this._ManagementReviewerSODate = new Date("01-01-1900");
}
get EmployeeName(): string {
return this._EmployeeName;
}
set EmployeeName(employeeName: string) {
if (this._EmployeeName != employeeName) {
this._EmployeeName = employeeName;
}
}
get EmployeeSO(): boolean {
return this._EmployeeSO;
}
set EmployeeSO(employeeSO: boolean) {
if (this._EmployeeSO != employeeSO) {
this._EmployeeSO = employeeSO;
}
}
get EmployeeSODate(): Date {
return this._EmployeeSODate;
}
set EmployeeSODate(employeeSODate: Date) {
if (this._EmployeeSODate != employeeSODate) {
this._EmployeeSODate = employeeSODate;
}
}
get ReviewerName(): string {
return this._ReviewerName;
}
set ReviewerName(reviewerName: string) {
if (this._ReviewerName != reviewerName) {
this._ReviewerName = reviewerName;
}
}
get ReviewerSO(): boolean {
return this._ReviewerSO;
}
set ReviewerSO(reviewerSO: boolean) {
if (this._ReviewerSO != reviewerSO) {
this._ReviewerSO = reviewerSO;
}
}
get ReviewerSODate(): Date {
return this._ReviewerSODate;
}
set ReviewerSODate(reviewerSODate: Date) {
if (this._ReviewerSODate != reviewerSODate) {
this._ReviewerSODate = reviewerSODate;
}
}
get ManagementReviewerName(): string {
return this._ManagementReviewerName;
}
set ManagementReviewerName(managementReviewerName: string) {
if (this._ManagementReviewerName != managementReviewerName) {
this._ManagementReviewerName = managementReviewerName;
}
}
get ManagementReviewerSO(): boolean {
return this._ManagementReviewerSO;
}
set ManagementReviewerSO(managementReviewerSO: boolean) {
if (this._ManagementReviewerSO != managementReviewerSO) {
this._ManagementReviewerSO = managementReviewerSO;
}
}
get ManagementReviewerSODate(): Date {
return this._ManagementReviewerSODate;
}
set ManagementReviewerSODate(managementReviewerSODate: Date) {
if (this._ManagementReviewerSODate != managementReviewerSODate) {
this._ManagementReviewerSODate = managementReviewerSODate;
}
}
}
更新
我刚注意到,在我的子组件中,我正在使用 MangementSO
& ManagementSODate
而模型有 ManagementReviewerSO
& ManagementReviewerSODate
. 更改这些修复了我的代码 . 但是,基于下面的讨论,我有点困惑为什么将道具放入本地数据是处理这种情况的错误方法 . 有人可以解释一下吗?
2 回答
使用props初始化数据属性没有任何问题 . 我认为这里很多评论中最大的混淆来源是
initEvaluation
是一个对象 . 在这种情况下,对该对象的任何更改都将反映在使用该对象的任何位置 .在相关代码中,父组件中的
evaluation
和子组件中的evaluation
是同一个对象 . 对该对象所做的更改将反映在父对象中,并且不会对Vue 's part because you are not technically mutating the reference to the object, you are just changing values of it'属性进行投诉 .通常,如果您将原始值作为属性传递,Vue将发出警告 . 假设您传递了一个字符串值,然后将该值与
v-model
一起使用 . 在这种情况下,Vue会抛出一个警告(在开发版本中),你正在改变一个属性 . 警告有两个原因;首先是因为该值未传播到父级(这可能是意外行为),其次,因为无论何时在父级中更改数据,它都将覆盖子级中的更改 .但是,当一个对象或数组作为属性传递时,Vue只会在您更改对象引用时发出抱怨 . 例如,在您的代码中,如果您这样做:
Vue会抱怨你正在改变一个 property . 在您的代码中,您只是更改
initEvaluation
的属性,这不会导致警告,并且还会导致这些值反映在任何地方,因为您在任何地方都在更新同一个对象 .其中一个原因是,在您的代码中有效,设置
evaluation: this.initEvaluation
是虚假的 . 您可以在模板中使用initEvaluation
,并获得与使用evaluation
相同的结果 . 同样,这是因为它们是同一个对象 . 这是Luiz试图解释的一部分 . 在这种情况下,路易斯的第一句话有点误导 . 数据函数只调用一次,这意味着使用属性初始化的数据将只接收属性的值一次 . 但是,因为initEvaluation
是一个对象,所以它没有't really matter in the question'的代码 . 对象引用永远不会更改,只有属性才会更改 . 如果父母由于某种原因要更改参考,则不会使用新参考更新子项中的evaluation
.是否需要立即反映对象的所有更新是值得商榷的 . 在许多情况下,您希望控制何时进行更新 . 在这些情况下,您可能会执行类似
evaluation: Object.assign({}, this.initEvaluation)
的操作,它会复制initEvaluation
对象 . 这样做的优点是,您可以根据需要对子组件中的对象进行任意多次更改,而不会将这些更改反映在组件外部 . 然后,在验证所有更改都正确后,您可以发出这些更改 .当您基于
props
(initEvaluation
和perspective
)创建data
属性时,它们不再依赖于道具并且您对道具做出反应're exclusively referencing the data, as if they were simply copies, but not the actual props received. So, they don' .由于您似乎没有在组件中更新它们,因此您可以直接引用
props
,而不是从props
创建的data
.编辑:抓一点,你在
evaluation
上使用了v-model
,所以如果直接引用它们你就改变道具 .所以,一般来说,我会从数据中删除它:
并直接引用
props
并替换v-model
与:value
和@input
,如文档中所建议的那样 .