在Vue组件实例上更新道具的正确方法是什么?

时间:2018-06-27 23:38:00

标签: javascript vue.js

我正在尝试找出更新在组件实例上创建的propsData的最佳方法。基本上,我有一个签名包装页面,并接收一堆使用v-html呈现的html。然后,我在呈现的html中创建了可变数量的签名板组件。由于我不知道html将会是什么,我被迫(据我所知)被迫在安装后立即创建组件。

因此,我正在父mounted()上运行以下命令:

    initializeSignaturePads() {

        const signatureAreas = document.querySelectorAll('.signature_area');

        // dynamically create a new vue instance for each signature pad and mount onto the respective .signature_area element
        // since the html is loaded via ajax, we don't know where to render this template on load, so a new Vue must be created
        signatureAreas.forEach(element => {
            const id = element.id;
            const signatureType = element.classList.contains('initials') ? 'initials' : 'signature';

            if (this.needsCustomerSignature(id)) {
                let length = this.signatures.push({
                    fieldName: id,
                    valid: false,
                    data: null,
                    type: signatureType
                });

                const SignaturePadClass = Vue.extend(SignaturePad);
                const SignaturePadInstance = new SignaturePadClass({
                    parent: this,
                    propsData: {
                        fieldName: id,
                        editable: true,
                        signatureType: signatureType,
                        signatureIndex: length - 1,
                        signatureData: null
                    }
                });

                // add handler for signed emit
                SignaturePadInstance.$on('signed', signature => {
                    this.padSigned(signature);
                });

                // watch this for an accepted signature, then pass to each child
                this.$watch('createdSignature.accepted', function (val) {
                    let signatureData = null;

                    if (val) {
                        signatureData = signatureType == 'signature' ? this.createdSignature.signatureData : this.createdSignature.initialsData;
                    }

                    // These two lines are the problem
                    SignaturePadInstance._props.signatureData = signatureData;
                    SignaturePadInstance._props.editable = !val;
                });

                SignaturePadInstance.$mount(element);
            }
        });
    },

据我所知,propsData现在是在组件上静态设置的。但是对于signatureDataeditable道具,我需要能够在更新子组件时将其传递给子组件。观察者工作正常,道具正在更新,但是我收到Avoid mutating a prop directly警告。这是可以理解的,因为我直接在孩子身上改变了道具。有没有解决这个问题的好方法?

2 个答案:

答案 0 :(得分:1)

找到这个stackoverflow answer之后,我就知道了。在propsData上设置道具时,我使用了所有原始类型,因此它们没有内置的反应式getter和setter。现在,我意识到我正在做的事情等效于将字符串作为道具传递给组件元素,这是有道理的。完成该操作后,该道具就变得反应灵敏,而且我也不必为手动创建观察者而烦恼。

无论如何,这是解决方案:

const SignaturePadInstance = new SignaturePadClass({
    parent: this,
    propsData: {
        fieldName: id, // << primitive
        editable: true, // << primitive
        signatureType: signatureType, // << primitive
        signatureIndex: length - 1,  // << primitive
        createdSignature: this.createdSignature  // << reactive object, updates to the child when changed
    }
});

答案 1 :(得分:0)

我使用Vue.observable(VueJS 2.6及更高版本)使该属性具有反应性。这是一个完整的示例:

    initializeSignaturePad() {
       const signaturePadComponent = Vue.extend(SignaturePad)
       this.instance = new signaturePadComponent()
       instance._props = Vue.observable({
          ...instance._props,
          editable: true
       })
       this.instance.$mount()
       document.body.appendChild(instance.$el)
    }
    
    onSignatureAccepted {
        this.instance.editable = false
    }