「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」。
比如我们现在开发一个 App
组件,这个组件中的内容结构如下:
这个组件的内容包含三大块:header
、main
和 footer
,如果我们将所有的内容都放在这个 App
组件中的话,随着代码量越来越多,最后会变得越来越难以维护,而且对于可扩展性和可维护性来说都是非常差的。
所以在真实开发中,我们就会对这些代码进行拆分,将它们拆分成一个个小的组件,每个小的组件都有属于自己的逻辑和功能,我们只需要在对应的组件里开发对应的逻辑和功能就可以了。
那么,上面这个 App
组件中的代码如果想通过组件化的方式进行拆分的话,该如何进行拆分呢?比如,我们可以根据下面的结构进行拆分:
按照如上的拆分方式拆分组件后,我们开发对应的逻辑时只需要去对应的组件中编写即可。
下面,我们打开刚才创建的 learn_component
项目,为了便于讲解多个知识点,我们先删除 src
目录下的 assets
、components
和 App.vue
,只保留 main.js
,后续将要讲解的每个知识点都放在 src
目录下的一个对应文件夹中,比如,现在我们要讲的第一个知识点是关于组件的拆分和嵌套的,那么我们在 src
目录下新建 01_组件的拆分和嵌套
,然后,我们在 01_组件的拆分和嵌套
文件夹下新建 App.vue
文件,开始开发 App
组件。
在使用
VS Code
开发.vue
文件时,默认情况下VS Code
是不认识.vue
文件的,所以你在.vue
文件中写的代码可能就没有高亮,因此,我们可以安装相应的VS Code
扩展已提供.vue
文件的支持。这里推荐使用Volar
(之前官方说过后续会基于Volar
开发一个属于Vue
官方的VS Code
插件),或者使用Vetur
,我这里暂且选择使用Vetur
扩展。另外,还推荐安装一个提供Vue
代码片段(snippets
)的扩展:Vue VSCode Snippets
或者Vue 3 Snippets
(这两个扩展你也可以都安装),借助于它们提供的代码片段,可以提高我们的开发效率。我这里选择使用Vue VSCode Snippets
扩展(因为个人觉得Vue 3 Snippets
提示的代码过多了,有时候会提示一些不想要的东西),需要注意的是Vue VSCode Snippets
依赖Vetur
,所以必须先启用Vetur
。
首先,我们要知道,App.vue
中代码的结构是这样的:
<template>
</template>
<<script>
export default {
}
</script>>
<style scoped>
</style>
但如果我们每次开发新组件(.vue
文件)都手动敲一遍这个结构可能有点麻烦,所以,我们可以借助于安装的 Vue VSCode Snippets
扩展(安装后还需要启用)自动帮我们完成 Vue
代码片段的创建。前期我们主要使用 vbase-css
片段,输入 vbase
后选择 vbase-css
代码片段即可:
效果如下:
<template>
<div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
这里,
<template>
下会有一个<div>
作为根元素,其实在真实开发中,我们还是比较习惯给它一个根元素的(比如我们要开发Header
组件,就会用一个<div>
作为根元素,甚至会给这个<div>
一个id
)。当然,目前Vue 3
中也可以不加根元素了,但事实上,Vue 3
内部会使用fragment
(片段)来实现根元素的效果(其实Vue 3
中fragment
这个东西是借鉴了React
,因为React
中也是要求多个根组件需要有一个根的,但如果不用根的话可以使用fragment
)。
前面我们把所有的代码都写在了 App.vue
中,我们已经说过,这样做后期会很臃肿难以维护,那么现在,我们就要使用组件拆分的方式将 App.vue
拆分成多个组件再组合起来。比如拆分前 App
组件中模板的结构是这样的:
<template>
<div id="app">
<div class="header">
<h2>Header</h2>
<h2>NavBar</h2>
</div>
<div class="main">
<h2>Banner</h2>
<ul>
<li>商品信息1</li>
<li>商品信息2</li>
<li>商品信息3</li>
<li>商品信息4</li>
<li>商品信息5</li>
</ul>
</div>
<div class="footer">
<h2>Footer</h2>
</div>
</div>
</template>
拆分后,就多了三个独立的组件:Header.vue
、Main.vue
和 Footer.vue
:
Header.vue
:
<template>
<div class="header">
<h2>Header</h2>
<h2>NavBar</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Main.vue
:
<template>
<div class="main">
<h2>Banner</h2>
<ul>
<li>商品信息1</li>
<li>商品信息2</li>
<li>商品信息3</li>
<li>商品信息4</li>
<li>商品信息5</li>
</ul>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Footer.vue
:
<template>
<div class="footer">
<h2>Footer</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
这样拆分完成后,怎么在 App.vue
中引入拆分出来的这三个组件呢?有两种方案:
- 将拆分出来的这三个组件都注册成全局组件,但没有必要,因为全局组件一旦注册,就一直不会销毁了,这样会有一点点浪费性能的;
- 当某个组件(比如这里的
App.vue
)用到拆分出来的这三个组件时,对它们做局部注册;
所以我们采用局部注册组件的方案在 App.vue
中导入这三个组件并使用它们:
<template>
<div id="app">
<!-- 3. 注册完这 3 个组件之后,在这里使用它们 -->
<Header></Header>
<Main></Main>
<Footer></Footer>
</div>
</template>
<script>
// 1. 导入这 3 个组件
import Header from './Header.vue';
import Main from './Main.vue';
import Footer from './Footer.vue';
export default {
// 2. 在 App.vue 中导出的对象中的 components 选项中注册这 3 个组件
components: {
Header,
Main,
Footer
}
}
</script>
<style scoped>
</style>
注意:
- 在导入组件时,
.vue
后缀可以不加,因为我们当前的项目是用Vue CLI 4
创建的,而Vue CLI 4
是基于Webpack
的,而Webpack
中有一个resolve.extensions
配置选项(里面会配置一些后缀名,用来提供给Webpack
尝试帮助我们解析没有写上文件后缀名的路径),虽然我们没有配置过它,但Vue CLI
已经帮我们配置过了,并且有帮我们在resolve.extensions
中配置上.vue
:所以我们导入
.vue
文件时,可以不写.vue
后缀。但是,不写.vue
后缀可能会存在没有代码提示的问题,我们待会会说到。
- 在
<template>
中使用组件时,组件的名称如果只有一个大写字母开头的单词,写成大写字母开头或小写字母开头都是可以的,但我们这里的例子情况有点特殊,需要使用大写字母,因为<heade>
、<main>
、<footer>
都是原本就存在的HTML
元素,所以我们不能通过以小写字母开头的<heade>
、<main>
、<footer>
来使用对应的3
个组件,否则会被解析为对应的HTML
元素而不是我们定义的组件。不过在开发中,一般不会把组件名称命名成某个HTML
元素的名称,所以在使用组件时我们通常会全部使用小写字母,然后如果有多个单词时就用-
连字符将多个单词进行连接。更多内容可以查阅官方文档:v3.vuejs.org/guide/compo…
拆分完组件并重新使用拆分出来的组件后,我们再来更新下 src/main.js
文件中导入 App
组件时的路径:
import { createApp } from 'vue'
import App from './01_组件的拆分和嵌套/App.vue'
createApp(App).mount('#app')
然后我们运行 npm run serve
把项目跑起来看下:
可以看到,重新引入拆分出来的 3
个组件后,它们的内容都是可以正常显示的。
但是,现在 Main.vue
中其实还可以分成两块内容,如果我们还想对它们做进一步拆分呢?我们可以这样做:
-
再新建两个
.vue
文件:然后将
Main.vue
中的内容抽离到这两个文件中:MainBanner.vue
中的内容:<template> <h2>Banner</h2> </template> <script> export default { } </script> <style scoped> </style>
MainProductList.vue
中的内容:<template> <ul> <li>商品信息1</li> <li>商品信息2</li> <li>商品信息3</li> <li>商品信息4</li> <li>商品信息5</li> </ul> </template> <script> export default { } </script> <style scoped> </style>
-
然后在
Main.vue
中引用这两个拆分出来的组件(跟前面在App.vue
中引入3
个组件的思路是一样的):<template> <div class="main"> <main-banner></main-banner> <main-product-list></main-product-list> </div> </template> <script> import MainBanner from './MainBanner.vue'; import MainProductList from './MainProductList.vue'; export default { components: { MainBanner, MainProductList } } </script> <style scoped> </style>
再来看下效果:
效果和之前是一样的。
以上,就是关于组件的拆分以及嵌套的说明,在真实开发中,就会按照这种拆分组件的方式,对组件进行各种各样的拆分,拆分之后再讲组件组合在一起,最终形成整个的 App
。