有没有更好的方法在动态加载的组件之间共享数据?

时间:2017-04-11 06:50:51

标签: vue.js

我最近使用Vue.js和Express.js构建了一个小应用程序。服务器需要准备的组件很少,例如Article.Category和Article.User的组合框。需要从服务器呈现这两个组件的选项。我在文章编辑表单中使用<component />作为这两个组件的占位符:

<component v-bind:is="user_selection_component"></component>
<component v-bind:is="category_selection_component"></component>

我使用模板字符串初始化组件,模板字符串result.data.template由服务器传递:

let org_data = original_store;
let new_data = () => {

    org_data['remote_options'] = result.data.remote_options;

    //if there is any default value, then assign the value to field referred by "model_name"
    if(model_name && result.data.preset_value){
        let previous_value = $shared.index(org_data, model_name);

        if(!previous_value){
            $shared.index(org_data, model_name, result.data.preset_value);
        }
    }

    return org_data;
}

var default_cb = ()=>{console.info('['+model_name+'].default_cb()')};

let TempComponent = {
    template: result.data.template,
    methods:  component_ref.methods,
    data:     new_data,
    mounted:  cb !== null ? cb.bind(this, org_data) : default_cb.bind(this)
};

app[mount_component] = TempComponent;

问题是,data方法为动态加载的组件返回一个新的Observable商店,它们不与父组件共享同一个商店对象,这是文章编辑的。因此,如果我想修改类别字段值或用户字段值,我必须让回调函数cb接受这两个动态加载组件的商店对象。否则,从父组件中,我无法修改这两个组件中的值。

所以我提出了一个临时解决方法,我将setter方法作为回调函数传递给这些动态加载的函数:

let set_user_id = null;
let set_cate_id = null;

(org_store) => { set_user_id = (new_id) => { org_store.form.user_id = new_id; }}
(org_store) => { set_cate_id = (new_id) => {org_store.form.category_id = new_id; }}

我加载其他组件后或想要设置类别/用户值时,我只需拨打set_user_id($new_user_id)set_cate_id($new_category_id);

我根本不喜欢这项工作。我尝试使用事件处理程序将新值发送到这两个组件中。但我无法通过$ref访问这两个动态加载的组件。有没有更好的方法让动态加载的组件之间共享数据?感谢。

2 个答案:

答案 0 :(得分:2)

如果您的组件将接受道具,您可以本地化您的事件总线,这比拥有全局更好。父组件将总线创建为数据项:

data() {
  ...
  bus: new Vue()
}

组件接受它作为道具:

<component v-bind:is="user_selection_component" :bus="bus"></component>
<component v-bind:is="category_selection_component" :bus="bus"></component>

并且您在答案中使用它,除了引用this.bus而不仅仅是bus

答案 1 :(得分:1)

我不认为我现在拥有的是最好的解决方案。在与其他人协商后,我将事件总线作为更好的解决方案。所以我修改了我的代码:

在我的init组件中:

let org_data = original_store;
let new_data = () => {

    org_data['remote_options'] = result.data.remote_options;

    //if there is any default value, then assign the value to field referred by "model_name"
    if(model_name && result.data.preset_value){
        let previous_value = $shared.index(org_data, model_name);

        if(!previous_value){
            $shared.index(org_data, model_name, result.data.preset_value);
        }
    }

    return org_data;
}

var default_cb = () => { console.info('['+model_name+'].default_cb()') };

let TempComponent = {
    template: result.data.template,
    methods:  component_ref.methods,
    data:     new_data,
    mounted:  cb !== null ? cb.bind(this, org_data) : default_cb.bind(this)
};

bus.$on('set.' + model_name, function(value){
    $shared.index(org_data, model_name, value);
});

区别在于:

bus.$on('set.' + model_name, function(value){
   $shared.index(org_data, model_name, value);
});

bus是由Vue()创建的公共事件总线:

let bus = new Vue()

从父组件中,我可以使用此事件总线发出事件:

bus.$emit('set.form.user_id', this.form.user_id);

更改此解决方案后,我感觉更好。但是,如果有更好的方法,我仍然感激不尽。感谢。