[英]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.