javascript - 当父组件更新 vuejs 时,子组件不会更新

标签 javascript typescript vue.js vuejs2 vue-component

我有一个 vue 实例,它将一个对象传递给子组件。子组件有一个复选框,单击该复选框会调用 vue 实例处理的事件,以更新传递给子组件的父组件上的对象。基于vue documentation我认为这会导致子组件更新相关字段。但是,当我单击复选框时,日期字段并未像我预期的那样更新。在下图中,当我选中“管理名称”复选框时,我希望出现当天,但我没有看到任何日期。我在这里缺少什么?

设计

Layout of Child Component

父实例

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 。更改这些可以修复我的代码。然而,根据下面的讨论,我有点困惑为什么将 Prop 放入本地数据是处理这种情况的错误方法。有人可以解释一下吗?

最佳答案

使用 props 初始化数据属性没有任何问题。我认为这里的许多评论中最大的困惑来源是 initEvaluation 是一个对象。在这种情况下,对该对象的任何更改都将反射(reflect)在使用该对象的任何地方

在相关代码中,父组件中的evaluation和子组件中的evaluation是同一个对象。对该对象所做的更改反射(reflect)在父对象中,并且 Vue 不会不会提示,因为从技术上讲,您并没有改变对该对象的引用,您只是在更改它的属性的值。

通常,如果您将原始值作为属性传递,Vue 会抛出警告。假设您传递了一个字符串值,然后将该值与 v-model 一起使用。在这种情况下,Vue 将发出警告(在开发版本中),提示您正在更改属性。发出警告的原因有两个;首先,因为该值不会传播到父级(这可能是意外行为),其次,因为每当父级中的数据发生更改时,它都会覆盖父级中的更改 child 。

但是,当对象或数组作为属性传递时,Vue 仅在您更改对象引用时才会提示。例如,在您的代码中,如果您要执行此操作:

this.initEvaluation = new Evaluation()

Vue 会提示你正在改变一个属性。然而,在您的代码中,您只需更改 initEvaluation属性,这不会导致警告,并且还会导致这些值随处反射(reflect) em> 因为您在各处更新相同对象。

这样做的后果之一是,在您的代码中,设置 evaluation: this.initEvaluation 是虚假的。您可以在模板中使用initEvaluation并获得与使用evaluation相同的结果。同样,这是因为它们是同一个对象。这是路易斯试图解释的部分内容。在这种情况下,路易斯的第一句话有点误导。数据函数仅被调用一次,这意味着使用属性初始化的数据只会接收该属性的值一次。但是,由于 initEvaluation 是一个对象,因此它在问题的代码中并不重要。对象引用永远不会改变,只有属性会改变。如果父级由于某种原因更改引用,子级中的评估不会使用新的引用进行更新 em>.

对于对象的任何地方的更新是否立即反射(reflect)是值得商榷的。在许多情况下,您希望控制更新发生的时间。在这些情况下,您可能会执行类似 evaluation: Object.assign({}, this.initEvaluation) 的操作,它会创建 initEvaluation 对象的副本 。这样做的优点是您可以对子组件中的对象进行任意数量的更改,而这些更改不会反射(reflect)在组件外部。然后,在验证所有更改均正确后,您可以发出这些更改。

关于javascript - 当父组件更新 vuejs 时,子组件不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45305782/

相关文章:

javascript - vue中子循环中绑定(bind)数据与模型的问题

javascript - 如何使用 VeeValidate (Vue.Js) 上的字典自定义 "required"错误消息

javascript - Python Selenium 网络驱动程序 : trying to call a javascript function

php - Javascript、AJAX 和 PHP 帮助

javascript - 如何在不修改javascript的情况下对其进行丑化?

typescript - 如何让 cypress.io 向左滑动 ionic ion-item-sliding?

typescript - 如何使用 Typescript + Jest 在 React 项目中使用路径别名

javascript - 如何在分形绘图递归函数中创建延迟

typescript - 定义接口(interface) : object with unknown number and name of properties

javascript - 在没有组件的vue js中拖放