【问题标题】:Data is being shared with the same component used multiple times数据与多次使用的同一组件共享
【发布时间】:2020-03-05 01:52:25
【问题描述】:

我有以下组件:

//wrapper component
<template>
    <div class="form-group form-group-text">
        <label v-if="label" :for="fieldId()">{{ label }}</label>
        <tiny-wrapper :key="pk"
            class="form-control builderEditor"
            :id="id"
            :name="fieldName()"
            v-model="form[field.key]"
            :init="editorSettings"
            :content="field.content"
        ></tiny-wrapper>
    </div>
</template>

<script>
    import Vue from 'vue'
    import BuilderHelper from './builder-helper'
    import TinyWrapper from '../tiny-wrapper'

    export default Vue.extend({
        props: [
            'pk',
            'title',
            'fieldKey',
            'field',
            'databaseName',
            'required',
            'disabled',
            'options',
            'label',
            'locale',
            'hidden',
        ],

        mixins: [BuilderHelper],

        components: {
            'tiny-wrapper': TinyWrapper,
        },

        computed: {
            editorSettings() {
                return {
                    // editor_selector: '.builderEditor',
                    selector: '#' + this.id,
                    menubar: '',
                    toolbar: 'bold italic | link',
                    height: 150,
                    contextmenu: 'bold italic | link',
                    forced_root_block: false,
                    invalid_elements: 'script',
                    statusbar: false,
                    resize: false,
                    browser_spellcheck: true,
                }
            }
        },
    })
</script>

// child component
<template>
    <textarea :id="id" ref="editor" class="form-control" :class="classList" :value="content"></textarea>
</template>

<script>
    import Vue from 'vue'
    import 'tinymce/tinymce'

    export default Vue.extend({
        props: {
            init: {
                type: Object,
            },
            id: {
                type: String,
                required: true,
            },
            classList: {
                type: String,
            },
            value: {
                type: String,
            }
        },

        data: function () {
            return {
                content: '',
                tinyOptions: {},
            }
        },

        mounted() {
            // this.content = this.value

            this.tinyOptions = Object.assign(window.tinyMCESettings, {
                selector: '#' + this.id,
                init_instance_callback: this.initInstanceCallback,
            }, this.init)

            tinymce.init(this.tinyOptions)
        },

        methods: {
            initInstanceCallback(editor) {
                editor.setContent(this.value)

                editor.on('change', e => {
                    this.update(editor)
                })

                editor.on('keyup', e => {
                    this.update(editor)
                })

                this.$parent.$on('reset', () => editor.setContent(''))
            },

            update(editor) {
                this.content = editor.getContent()
                this.$emit('input', this.content)
            },
        }
    })
</script>

我在文档中使用了 10 次 wrapper-component。

子组件中的数据对于每个包装组件都是相同的,状态由最后实例化的子组件中的数据共享/覆盖。我做错了什么?

【问题讨论】:

  • 不完全清楚你所说的'状态是共享/覆盖'是什么意思。您能否更明确地说明哪些位似乎是共享的,以及哪些观察导致您得出该结论?从代码中跳出来的第一件事是从this.tinyOptions = Object.assign 开始的位。这将在所有实例之间共享相同的 tinyOptions 对象。它们都将是对象window.tinyMCESettings,尽管该对象通过对Object.assign 的调用不断更新。
  • this.tinyOptions 应该是每个组件的本地,不是吗?考虑到它在data-property 中?在 tinyOptions 中有一个名为“selector”的属性,tinymce.init 使用它来确定哪个组件应该是一个小编辑器。早些时候我直接在数据属性上做了 Object.assigning,但同样的事情发生了。

标签: vuejs2 vue-component


【解决方案1】:

我无法从问题中判断这是否是您面临的问题,但这是一个问题。

当您第一次在 data 函数中创建 tinyOptions 时,您正在为其分配一个新的空对象。没事儿。您的组件的每个实例都将有其自己的、不同的对象用于该属性。没有共享任何内容。

但是,我们遇到了这个问题:

this.tinyOptions = Object.assign(window.tinyMCESettings, {
    selector: '#' + this.id,
    init_instance_callback: this.initInstanceCallback,
}, this.init)

这将一个不同的对象分配给tinyOptions 属性,因此原来的空对象被丢弃。这本身不会有问题。但是让我们考虑一下这里发生了什么。上面的代码大致等价于:

window.tinyMCESettings.selector = '#' + this.id
window.tinyMCESettings.init_instance_callback = this.initInstanceCallback,

for (const prop in this.init) {
    window.tinyMCESettings[prop] = this.init[prop]
}

this.tinyOptions = window.tinyMCESettings

所以它所做的是更新对象window.tinyMCESettings 的属性,然后将该对象分配给tinyOptions 属性。

您的所有组件都将获取相同的window.tinyMCESettings 对象并更改其属性。虽然每个组件都有自己独特的 tinyOptions 属性,但所有这些属性最终都会指向同一个对象。

一种解决方案是将所有内容复制到一个新的空对象:

this.tinyOptions = Object.assign({}, window.tinyMCESettings, {
    selector: '#' + this.id,
    init_instance_callback: this.initInstanceCallback,
}, this.init)

我个人会改用... 语法:

this.tinyOptions = {
    ...window.tinyMCESettings,
    selector: '#' + this.id,
    init_instance_callback: this.initInstanceCallback,
    ...this.init
}

选择权在你。

需要注意的关键是window.tinyMCESettings 的属性现在被复制到一个新对象,而不是直接使用该对象。

【讨论】:

  • 你是完全正确的,我检查了 window.tinyMCESettings 并且选择器确实是最后添加的组件的值。然而,这给我带来了一个新问题,textarea 元素现在只是隐藏了......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多