根据上一篇的案例,我们都是把所有的组件定义在main.js的文件中,这样显得非常的混乱:
const { createApp, mount } = window.Vue;const MyUser = {template: `<div style="float: left;"><a href="#">登录</a><span> | </span><a href="#">注册</a></div>`,};const NavItem = {template: `<li style="float: left; padding: 0 15px;"><a :href="item.link" target="_blank">{{ item.title }}</a></li>`,props: ["item"]};const MyNav = {template: `<ul style="float: left; padding: 0 35px; margin: 0; list-style: none;"><nav-item v-for="item in navData" :key="item.id" :item="item" /></ul>`,props: ["navData"],components: {NavItem}};const MyLogo = {template: `<div style="float: left; padding: 0 20px;">Logo</div>`};const MyHeader = {template: `<header style="border: 1px solid #333;"><my-logo /><my-nav :nav-data="navData" /><my-user /><div style="clear: both;"></div></header>`,// 注册数据属性props: ["navData"],components: {MyLogo,MyNav,MyUser}};const App = {template: `<div><!-- 使用组件 --><!-- 父组件给子组件传递数据 --><my-header :nav-data="navData" /><!-- 复用组件,相互独立 --><my-header :nav-data="navData" /></div>`,components: {// 注册组件,这样的方式叫做局部注册// 局部注册:在组件内部的局部注册另外一个组件,只供当前组件使用MyHeader},data() {return {navData: [{id: 1,title: "百度",link: "https:www.baidu.com"},{id: 2,title: "谷歌",link: "https:www.google.com"},{id: 3,title: "必应",link: "https:www.bing.com"}]};}};createApp(App).mount("#app");
通过上面的代码我们能够发现,每一个组件其实就是一个个的对象,我们可以利用 ESM 的导入导出功能把每一个组件都单独的抽离出去:
例如components/myHeader/index.js文件导入了所有的组件:
import MyLogo from "../MyLogo/index.js";import MyNav from "../MyNav/index.js";import MyUser from "../MyUser/index.js";const MyHeader = {template: `<header><my-logo /><my-nav :nav-data="navData" /><my-user /><div style="clear: both;"></div></header>`,// 注册数据属性props: ["navData"],components: {MyLogo,MyNav,MyUser}};export default MyHeader;
然后在在App.js文件进行导入:
import MyHeader from "./components/MyHeader/index.js"const App = {template: `<div><my-header :nav-data="navData" /></div>`,components: {// 注册组件,这样的方式叫做局部注册// 局部注册:在组件内部的局部注册另外一个组件,只供当前组件使用MyHeader},data() {return {navData: [{id: 1,title: "百度",link: "https:www.baidu.com"},{id: 2,title: "谷歌",link: "https:www.google.com"},{id: 3,title: "必应",link: "https:www.bing.com"}]};}};export default App;
我们的组件化不一定非要用.vue文件,因为我们的组件就是一个个的对象,只不过 Vue 对相应的对象进行了处理!
有没有发现通过我们对上面这些组件抽离拆分后,这好像有点类似我们.vue文件的雏形,只不过我们现在把 template、script 还有 style 都写在了一块,.vue文件把这三大部分都进行了分离,使其看起来更简单明了。
但是我们的浏览器无法解析.vue文件,这就需要一些工具把.vue文件进行解析返回一个对象,例如在webpack中使用vue-loader。
然后我们可以把.js文件后缀更改为.vue的后缀,我项目使用的是 Vite 对 Vue 进行解析,目录如下:
例如我们在components/MyHeader/index.vue文件进行 template、script 还有 style 进行分离:
<template><header><my-logo /><my-nav :nav-data="navData" /><my-user /><div style="clear: both"></div></header></template><script>import MyLogo from "../MyLogo/index.vue";import MyNav from "../MyNav/index.vue";import MyUser from "../MyUser/index.vue";export default {name: "my-header",props: ["navData"],components: {MyLogo,MyNav,MyUser}};</script><style lang="scss" scoped>header {border: 1px solid #333;}</style>
以上代码,我们把 template、script 还有 style 都放在了.vue的文件中,但是看起来也不会显的很乱。
然后我们在App.vue文件中导入MyHeader组件看看解析后的效果:
<template><my-header :nav-data="navData" /></template><script>import MyHeader from "./components/MyHeader/index.vue";console.log(MyHeader)export default {components: {MyHeader},data() {return {navData: [{id: 1,title: "百度",link: "https:www.baidu.com"},{id: 2,title: "谷歌",link: "https:www.google.com"},{id: 3,title: "必应",link: "https:www.bing.com"}]};}};</script><style lang="scss" scoped></style>

可以看到.vue的内容最终还是会被编译为一个对象!!!
另外,某些组件很多的业务都需要使用,如果每个地方都需要进行局部注册就会显得很麻烦,Vue 为我们提供了component方法供我们进行组件的全局注册。
import { createApp } from "vue";import globalComponent from "./components/Global/index";import App from "./App.vue";const app = createApp(App);// 我们把所有的全局组件都放到 Global 的文件夹下方便管理globalComponent(app);app.mount("#app");
import Search from "./Search/index.vue";function globalComponent(app) {// 使用实例对象上的 component 方法进行全局注册app.component("my-search", Search);}export default globalComponent;
<template><header><!-- 不需要进行局部注册,就可以直接使用 --><my-search /><my-logo /><my-nav :nav-data="navData" /><my-user /><div style="clear: both"></div></header></template><script>import MyLogo from "../MyLogo/index.vue";import MyNav from "../MyNav/index.vue";import MyUser from "../MyUser/index.vue";export default {name: "my-header",props: ["navData"],components: {MyLogo,MyNav,MyUser}};</script><style lang="scss" scoped>header {border: 1px solid #333;}</style>
