繁体   English   中英

动态注册本地 Vue.js 组件

[英]Register local Vue.js component dynamically

我们知道可以像这样动态注册全局 Vue.js(版本 1)组件:

Vue.component('my-component', MyComponent)

有没有办法对本地组件执行相同的操作,即那些仅对特定组件可用/可见的组件?

这个想法是我希望能够像这样传递要在本地注册的组件:

<outer-component
  :local-component-to-be-registered-dymanically="Foo"
>

这样我就可以在outer-component执行以下操作:

created() {
    this.someMethodINeedToRegisterLocalComponent('cool-component', this.localComponentToBeRegisteredDynamically);
},

这就是我最终组件动态导入注册到本地组件的方式:

created() {
  const requireComponent = require.context(
    // The relative path of the components folder
    "PATH/TO/COMPONENTS_FOLDER",
    // Whether or not to look in subfolders
    false,
    // The regular expression used to match base component filenames
    /[A-Z]\w+\.(vue|js)$/
  );

  requireComponent.keys().forEach(fileName => {
    const componentConfig = requireComponent(fileName);
    console.log(componentConfig.default);
    // Gets the file name regardless of folder depth
    const componentName = fileName
      .split("/")
      .pop()
      .split(".")[0];
    // register the component locally
    this.$options.components[componentName] = componentConfig.default;
  });
}

请注意,必须在安装组件之前注册组件, created生命周期钩子可以完美地实现这一点。

另请参阅基本组件的自动全局注册文档。

这是您实现动态组件的方式,而不是注册动态组件的方式。 .vue文件中,您只能注册一个组件,其他任何组件都需要在外部定义。

应该能够使用:is属性实现您想要完成的任务。 这是 文档中的示例:

var vm = new Vue({
    el: '#example',
    data: {
        currentView: 'home'
    },
    components: {
        home: { /* ... */ },
        posts: { /* ... */ },
        archive: { /* ... */ }
    }
})
<component v-bind:is="currentView">
    <!-- component changes when vm.currentView changes! -->
</component>

或者另一种方法,直接绑定到组件对象(而不是使用某些数据作为指针):

var Home = {
    template: '<p>Welcome home!</p>'
}
var vm = new Vue({
    el: '#example',
    data: {
        currentView: Home
    }
})

从 Vue 2.6 开始,这无法完成。 动态注册只能全局完成,使用Vue.component

我还不能发表评论,但我对 Shaya Ulmans 的回答还有一个补充:

使用 Vue 2.6(.10):如果您检查组件是否已经注册,则不需要在created钩子中。 如果您不这样做,例如将其添加到mounted钩子或自定义方法中,则如果您尚未注册它,它将无法找到该组件。

这可以通过一个简单的 v-if 语句来解决。

我创建了一个基于 Shaya Ulmans 答案的类作为试用,它可以使用配置和动态导入将组件本地注册到给定组件。 可以使用 mixin 来完成,但我只需要在我的组件子集中进行动态本地注册。

/**
 * @class dynamicLocalComponentRegistrator
 * @classdesc can register components to a given component locally
 */
export class dynamicLocalComponentRegistrator {
    /**
     * @typedef ComponentConfig
     * @type {object}
     * @property {string} name
     * @property {Function} component
     */

    /**
     * Reference to component the components should be locally registered to
     * @type {VueComponent}
     */
    localComponent;

    /**
     * Keep track of registered components
     * @type {string[]}
     */
    registeredComponents = [];


    constructor (localComponent) {
        this.localComponent = localComponent;
    }

    /**
     * Register multiple components, skipping those that are already registered
     *
     * @param {ComponentConfig[]} componentConfigArray
     */
    registerMultipleComponents (componentConfigArray) {
        componentConfigArray.forEach(componentConfig => {
            if (!this.isRegistered(componentConfig.name)) {
                this.registerComponent(componentConfig);
            }
        })
    }

    /**
     * Register a component locally to the local component
     *
     * @param {ComponentConfig} componentConfig
     */
    registerComponent (componentConfig) {
        if (!componentConfig.hasOwnProperty('name') || !componentConfig.hasOwnProperty('component') || typeof componentConfig.component !== 'function') {
            throw 'cannot register component: invalid config'
        }

        componentConfig.component().then(component => {
            this.localComponent.$options.components[componentConfig.name] = component.default;
            this.registeredComponents.push(componentConfig.name);
        });
    }

    /**
     * Shorthand to check registration
     *
     * @param {string} componentName
     * @returns {boolean}
     */
    isRegistered(componentName) {
        return this.registeredComponents.includes(componentName);
    }
}

就在你需要有在功能的组件导入此。然后,你喜欢的地方,创建一个实例,并给this给构造函数。

例如:

mounted() {
        this.componentRegistrator = new dynamicLocalComponentRegistrator(this);
        this.componentRegistrator.registerMultipleComponents(this.customComponents);
    }

并在 .vue 模板中使用它:

<component v-if="componentRegistrator && componentRegistrator.isRegistered(dynamicComponent.name)" :is="dynamicComponent.name" />

这不会抛出错误,到目前为止工作得很好。

你不要那样做。 这是反模式。 组件被设计为只向使用它的父组件公开那么多事件和道具,您可以利用多功能性和复杂性并添加更多到孩子的界面(道具和事件),以涵盖您希望孩子适应的所有情况. 但不是动态定义孩子。 如果你改变了父级中的子级,那么就违背了组件系统解耦的目的。 如果您想在父级中更改它,只需将其作为父级的一部分即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM