官方定义
Vue.component( id, [definition] )
参数:
{string} id
{Function | Object} [definition]
用法:
注册或获取全局组件。注册还会自动使用给定的
id
设置组件的名称// 注册组件,传入一个扩展过的构造器 Vue.component( "my-component", Vue.extend({ /* ... */ }) ); // 注册组件,传入一个选项对象 (自动调用 Vue.extend) Vue.component("my-component", { /* ... */ }); // 获取注册的组件 (始终返回构造器) var MyComponent = Vue.component("my-component");
参考:组件
基本示例
这里有一个 Vue 组件的示例:
// 定义一个名为 button-counter 的新组件
Vue.component("button-counter", {
data: function () {
return {
count: 0,
};
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>',
});
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>
。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: "#components-demo" });
因为组件是可复用的 Vue 实例,所以它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
组件复用的时候,每个组件都会各自独立维护它的 count
。因为你每用一次组件,就会有一个它的新实例被创建。此时data
必须是一个函数。因此每个实例可以维护一份被返回对象的独立的拷贝。如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component
全局注册的:
Vue.component("my-component-name", {
// ... options ...
});
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue
) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
全局注册
各个 UI 组件库里的组件,全局定义,每个页面都可以使用。
到目前为止,我们只用过 Vue.component
来创建组件:
Vue.component("my-component-name", {
// ... 选项 ...
});
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue
) 的模板中。比如:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
局部注册
使用 vue 脚手架搭建的 vue 项目,我们按需引用子组件。
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = {
/* ... */
};
var ComponentB = {
/* ... */
};
var ComponentC = {
/* ... */
};
然后在 components
选项中定义你想要使用的组件:
new Vue({
el: "#app",
components: {
"component-a": ComponentA,
"component-b": ComponentB,
},
});
对于 components
对象中的每个property
来说,其property
名就是自定义元素的名字,其property
值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA
在 ComponentB
中可用,则你需要这样写:
var ComponentA = {
/* ... */
};
var ComponentB = {
components: {
"component-a": ComponentA,
},
// ...
};
或者如果你通过Babel
和webpack
使用ES2015
模块,那么代码看起来更像:
import ComponentA from "./ComponentA.vue";
export default {
components: {
ComponentA,
},
// ...
};
注意在 ES2015+ 中,在对象中放一个类似 ComponentA
的变量名其实是 ComponentA: ComponentA
的缩写,即这个变量名同时是:
- 用在模板中的自定义元素的名称
- 包含了这个组件选项的变量名
模块系统
在模块系统中局部注册
诸如你使用Babel
和webpack
的模块系统。在这些情况下,我们推荐创建一个 components
目录,并将每个组件放置在其各自的文件中。
然后你需要在局部注册之前导入每个你想使用的组件。例如,在一个假设的 ComponentB.js
或 ComponentB.vue
文件中:
import ComponentA from "./ComponentA";
import ComponentC from "./ComponentC";
export default {
components: {
ComponentA,
ComponentC,
},
// ...
};
现在 ComponentA
和 ComponentC
都可以在 ComponentB
的模板中使用了。
基础组件的自动化全局注册
可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到。
所以会导致很多组件里都会有一个包含基础组件的长列表:
import BaseButton from "./BaseButton.vue";
import BaseIcon from "./BaseIcon.vue";
import BaseInput from "./BaseInput.vue";
export default {
components: {
BaseButton,
BaseIcon,
BaseInput,
},
};
而只是用于模板中的一小部分:
<BaseInput v-model="searchText" @keydown.enter="search" />
<BaseButton @click="search">
<BaseIcon name="search" />
</BaseButton>
- 组件全部导入后,批量注册
import dgDialog from "@/components/dgDialog/index.vue";
import svgIcon from "@/components/svgIcon/index.vue";
const allComponent = { dgDialog, svgIcon };
export default {
install(app) {
console.log(app, "app"); //App.vue
Object.keys(allComponent).forEach((key) => {
console.log(key, "key"); //dgDialog svgIcon
app.component(key, allComponent[key]);
});
},
};
// 或是
const ComponentRegister = {
install(Vue) {
console.log(Vue, "Vue"); //App.vue
Object.keys(allComponent).forEach((key) => {
console.log(key, "key");
Vue.component(key, allComponent[key]);
});
}
}
export default ComponentRegister;
- 使用
webpack
(或在内部使用了webpack
的Vue CLI 3+
)全局注册组件
使用 require.context
方法引入组件
// 所有组件放在一个`components`文件夹内的写法
const ComponentRegister = {
install(Vue) {
// 文件结构为components/组件名称.vue
const requireComponent = require.context(
// 其组件目录的相对路径
"@/components",
// 是否查询其子目录
false,
// 匹配基础组件文件名的正则表达式
/\.(vue|js)$/
);
requireComponent.keys().forEach((fileName) => {
// 获取组件配置
const componentConfig = requireComponent(fileName);
// 获取当前组件的文件名称 vue文件中声明的name属性 || 文件名称
const componentName =
componentConfig.default.name ||
fileName
.split("/")
.pop()
.replace(/\.\w+$/, ""); //或 fileName.replace(/^\.\/(.*)\.\w+$/, "$1");
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
);
});
},
};
export default ComponentRegister;
// 组件以文件夹名称命名
const ComponentRegister = {
install(Vue) {
// 文件结构为文件夹名称(即组件名称)/index.vue
const requireComponent = require.context(
// 其组件目录的相对路径
"@/components/",
// 是否查询其子目录
true,
// 匹配基础组件文件名的正则表达式
/\.(vue|js)$/
);
requireComponent.keys().forEach((fileName) => {
// 获取组件配置
const componentConfig = requireComponent(fileName);
//获取当前组件的文件名称 vue文件中声明的name属性 || 文件名称
const componentName =
componentConfig.default.name ||
fileName
.replace(/^\.\/(.*)\.\w+$/, "$1")
.split("/")
.shift(); //移除数组第一个元素 结果为 文件夹名称
// .pop()//移除最后一个数组元素 结果为index
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
);
});
},
};
export default ComponentRegister;
- 使用
vite
方法全局注册组件
使用import.meta.glob
方法引入组件
const ComponentRegister = {
install(Vue) {
//获取所有的vue文件
const requireComponent = import.meta.glob("@/components/*/*.vue", {
// import: 'default',
// The glob option "as" has been deprecated in favour of "query". Please update `as: 'component'` to `query: '?component'`.
// as: "component",
query: '?component',
eager: true,
});
/**
* (\/[^\/]+)+ 匹配一个或多个以/开头,后面跟着一个或多个非/字符的序列。这对应于路径中的目录名。
* \/ 匹配/字符,它是目录名与我们要提取的部分之间的分隔符。
* ([^\/]+) 匹配一个或多个非/字符,这就是我们要提取的部分(文件夹名称)。
* \/ 再次匹配/字符,表示提取部分的结束和下一个目录或文件的开始。
* */
const re = /(\/[^\/]+)+\/([^\/]+)\//; //或是 /\/components\/(.*?)\//; i.match(re)[1];
for (const i in requireComponent) {
//获取当前遍历的组件
const componentName = i.match(re)[2];
const componentConfig = requireComponent[i];
Vue.component(componentName, componentConfig.default || componentConfig);
}
},
};
export default ComponentRegister;
记住全局注册的行为必须在根 Vue 实例 (通过 new Vue
) 创建之前发生。如下
//注册组件到全局
Vue.component("Profile", Profile);
//创建vue
var vue = new Vue({
el: "#app",
data: {
msg: "Vue是最简单的",
},
});