根据上一篇的案例,我们都是把所有的组件定义在main.js的文件中,这样显得非常的混乱:

    1. const { createApp, mount } = window.Vue;
    2. const MyUser = {
    3. template: `
    4. <div style="float: left;">
    5. <a href="#">登录</a>
    6. <span> | </span>
    7. <a href="#">注册</a>
    8. </div>`,
    9. };
    10. const NavItem = {
    11. template: `
    12. <li style="float: left; padding: 0 15px;">
    13. <a :href="item.link" target="_blank">{{ item.title }}</a>
    14. </li>`,
    15. props: ["item"]
    16. };
    17. const MyNav = {
    18. template: `
    19. <ul style="float: left; padding: 0 35px; margin: 0; list-style: none;">
    20. <nav-item v-for="item in navData" :key="item.id" :item="item" />
    21. </ul>`,
    22. props: ["navData"],
    23. components: {
    24. NavItem
    25. }
    26. };
    27. const MyLogo = {
    28. template: `<div style="float: left; padding: 0 20px;">Logo</div>`
    29. };
    30. const MyHeader = {
    31. template: `
    32. <header style="border: 1px solid #333;">
    33. <my-logo />
    34. <my-nav :nav-data="navData" />
    35. <my-user />
    36. <div style="clear: both;"></div>
    37. </header>`,
    38. // 注册数据属性
    39. props: ["navData"],
    40. components: {
    41. MyLogo,
    42. MyNav,
    43. MyUser
    44. }
    45. };
    46. const App = {
    47. template: `
    48. <div>
    49. <!-- 使用组件 -->
    50. <!-- 父组件给子组件传递数据 -->
    51. <my-header :nav-data="navData" />
    52. <!-- 复用组件,相互独立 -->
    53. <my-header :nav-data="navData" />
    54. </div>`,
    55. components: {
    56. // 注册组件,这样的方式叫做局部注册
    57. // 局部注册:在组件内部的局部注册另外一个组件,只供当前组件使用
    58. MyHeader
    59. },
    60. data() {
    61. return {
    62. navData: [
    63. {
    64. id: 1,
    65. title: "百度",
    66. link: "https:www.baidu.com"
    67. },
    68. {
    69. id: 2,
    70. title: "谷歌",
    71. link: "https:www.google.com"
    72. },
    73. {
    74. id: 3,
    75. title: "必应",
    76. link: "https:www.bing.com"
    77. }
    78. ]
    79. };
    80. }
    81. };
    82. createApp(App).mount("#app");

    通过上面的代码我们能够发现,每一个组件其实就是一个个的对象,我们可以利用 ESM 的导入导出功能把每一个组件都单独的抽离出去:
    image.png
    例如components/myHeader/index.js文件导入了所有的组件:

    1. import MyLogo from "../MyLogo/index.js";
    2. import MyNav from "../MyNav/index.js";
    3. import MyUser from "../MyUser/index.js";
    4. const MyHeader = {
    5. template: `
    6. <header>
    7. <my-logo />
    8. <my-nav :nav-data="navData" />
    9. <my-user />
    10. <div style="clear: both;"></div>
    11. </header>`,
    12. // 注册数据属性
    13. props: ["navData"],
    14. components: {
    15. MyLogo,
    16. MyNav,
    17. MyUser
    18. }
    19. };
    20. export default MyHeader;

    然后在在App.js文件进行导入:

    1. import MyHeader from "./components/MyHeader/index.js"
    2. const App = {
    3. template: `
    4. <div>
    5. <my-header :nav-data="navData" />
    6. </div>`,
    7. components: {
    8. // 注册组件,这样的方式叫做局部注册
    9. // 局部注册:在组件内部的局部注册另外一个组件,只供当前组件使用
    10. MyHeader
    11. },
    12. data() {
    13. return {
    14. navData: [
    15. {
    16. id: 1,
    17. title: "百度",
    18. link: "https:www.baidu.com"
    19. },
    20. {
    21. id: 2,
    22. title: "谷歌",
    23. link: "https:www.google.com"
    24. },
    25. {
    26. id: 3,
    27. title: "必应",
    28. link: "https:www.bing.com"
    29. }
    30. ]
    31. };
    32. }
    33. };
    34. export default App;

    我们的组件化不一定非要用.vue文件,因为我们的组件就是一个个的对象,只不过 Vue 对相应的对象进行了处理!
    有没有发现通过我们对上面这些组件抽离拆分后,这好像有点类似我们.vue文件的雏形,只不过我们现在把 template、script 还有 style 都写在了一块,.vue文件把这三大部分都进行了分离,使其看起来更简单明了。
    但是我们的浏览器无法解析.vue文件,这就需要一些工具把.vue文件进行解析返回一个对象,例如在webpack中使用vue-loader

    然后我们可以把.js文件后缀更改为.vue的后缀,我项目使用的是 Vite 对 Vue 进行解析,目录如下:
    image.png

    例如我们在components/MyHeader/index.vue文件进行 template、script 还有 style 进行分离:

    1. <template>
    2. <header>
    3. <my-logo />
    4. <my-nav :nav-data="navData" />
    5. <my-user />
    6. <div style="clear: both"></div>
    7. </header>
    8. </template>
    9. <script>
    10. import MyLogo from "../MyLogo/index.vue";
    11. import MyNav from "../MyNav/index.vue";
    12. import MyUser from "../MyUser/index.vue";
    13. export default {
    14. name: "my-header",
    15. props: ["navData"],
    16. components: {
    17. MyLogo,
    18. MyNav,
    19. MyUser
    20. }
    21. };
    22. </script>
    23. <style lang="scss" scoped>
    24. header {
    25. border: 1px solid #333;
    26. }
    27. </style>

    以上代码,我们把 template、script 还有 style 都放在了.vue的文件中,但是看起来也不会显的很乱。

    然后我们在App.vue文件中导入MyHeader组件看看解析后的效果:

    1. <template>
    2. <my-header :nav-data="navData" />
    3. </template>
    4. <script>
    5. import MyHeader from "./components/MyHeader/index.vue";
    6. console.log(MyHeader)
    7. export default {
    8. components: {
    9. MyHeader
    10. },
    11. data() {
    12. return {
    13. navData: [
    14. {
    15. id: 1,
    16. title: "百度",
    17. link: "https:www.baidu.com"
    18. },
    19. {
    20. id: 2,
    21. title: "谷歌",
    22. link: "https:www.google.com"
    23. },
    24. {
    25. id: 3,
    26. title: "必应",
    27. link: "https:www.bing.com"
    28. }
    29. ]
    30. };
    31. }
    32. };
    33. </script>
    34. <style lang="scss" scoped></style>

    image.png
    可以看到.vue的内容最终还是会被编译为一个对象!!!

    另外,某些组件很多的业务都需要使用,如果每个地方都需要进行局部注册就会显得很麻烦,Vue 为我们提供了component方法供我们进行组件的全局注册。

    1. import { createApp } from "vue";
    2. import globalComponent from "./components/Global/index";
    3. import App from "./App.vue";
    4. const app = createApp(App);
    5. // 我们把所有的全局组件都放到 Global 的文件夹下方便管理
    6. globalComponent(app);
    7. app.mount("#app");
    1. import Search from "./Search/index.vue";
    2. function globalComponent(app) {
    3. // 使用实例对象上的 component 方法进行全局注册
    4. app.component("my-search", Search);
    5. }
    6. export default globalComponent;
    1. <template>
    2. <header>
    3. <!-- 不需要进行局部注册,就可以直接使用 -->
    4. <my-search />
    5. <my-logo />
    6. <my-nav :nav-data="navData" />
    7. <my-user />
    8. <div style="clear: both"></div>
    9. </header>
    10. </template>
    11. <script>
    12. import MyLogo from "../MyLogo/index.vue";
    13. import MyNav from "../MyNav/index.vue";
    14. import MyUser from "../MyUser/index.vue";
    15. export default {
    16. name: "my-header",
    17. props: ["navData"],
    18. components: {
    19. MyLogo,
    20. MyNav,
    21. MyUser
    22. }
    23. };
    24. </script>
    25. <style lang="scss" scoped>
    26. header {
    27. border: 1px solid #333;
    28. }
    29. </style>