目录
组件
组件是什么?
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。在实际应用中,组件常常被组织成层层嵌套的树状结构:
什么是组件化开发
前端组件化开发的好处:
- 提高了前端代码的复用性和灵活性
- 提升了开发效率和后期的可维护性
vue 中的组件化开发:
了解一下什么是单页面应用程序:
单页面应用程序(英文名:Single Page Application)简称 SPA,顾名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。
特点就是:单页面应用程序将所有的功能局限于一个 web 页面中,仅在该 web 页面初始化时加载相应的资源( HTML、JavaScript 和 CSS)。一旦页面加载完成了,SPA 不会因为用户的操作而进行页面的重新加载或跳转。而是利用 JavaScript 动态地变换 HTML 的内容,从而实现页面与用户的交互。
单页面应用程序的优点:
① 良好的交互体验
- 单页应用的内容的改变不需要重新加载整个页面
- 获取数据也是通过 Ajax 异步获取
- 没有页面之间的跳转,不会出现“白屏现象”
② 良好的前后端工作分离模式
- 后端专注于提供 API 接口,更易实现 API 接口的复用
- 前端专注于页面的渲染,更利于前端工程化的发展
③ 减轻服务器的压力
- 服务器只提供数据,不负责页面的合成与逻辑的处理,吞吐能力会提高几倍单页面应用程序
单页面应用程序的缺点:
① 首屏加载慢
- 路由懒加载
- 代码压缩
- CDN 加速
- 网络传输压缩
② 不利于 SEO
- SSR 服务器端渲染
创建 vue 的 SPA 项目
vue 官方提供了两种快速创建工程化的 SPA 项目的方式:
① 基于 vite 创建 SPA 项目
② 基于 vue-cli 创建 SPA 项目
创建 vite 的项目:
项目名称建议使用英文。
项目目录:
- node_modules 目录用来存放第三方依赖包
- public 是公共的静态资源目录
- src 是项目的源代码目录
- .gitignore 是 Git 的忽略文件
- index.html 是 SPA 单页面应用程序中唯一的 HTML 页面
- package.json 是项目的包管理配置文件
- assets 目录用来存放项目中所有的静态资源文件(如css、fonts、img等)
- components 目录用来存放项目中所有的自定义组件
- App.vue 是项目的根组件
- index.css 是项目的全局样式表文件
- main.js 是整个项目的打包入口文件
vite 项目的运行流程
<div id="app"></div>
// 1. 按需导入 createApp 函数
import { createApp } from 'vue'
// 2. 导入待渲染的 App.vue 组件
import App from './App.vue'
// 3. 调用 createApp 函数,创建 SPA 应用的实例,返回值是SPA实例,用常量app接收,并且把App组件作为参数传递给createApp 函数,表示要把App渲染到index.html中
const app = createApp(App)
// 4. 调用 mount() 把 App 组件的模板结构,渲染到指定的 el 区域中
app.mount('#app)
回到组件:vue组件的构成
- template -> 组件的模板结构
- vue 提供的容器标签,只起到包裹性质的作用,不会被渲染为真正的 DOM 元素
-
vue 2.x 的版本中,<template> 节点内的 DOM 结构仅支持单个根节点,但在 vue 3.x 的版本中,<template> 中支持定义多个根节点
-
在组件的 <template> 节点中,支持使用前面所学的指令语法,来辅助开发者渲染当前组件的 DOM 结构。
- script -> 组件的 JavaScript 行为
- 可以在 <script> 节点中封装组件的 JavaScript 业务逻辑,之后的data数据已经各种方法需要在export default {}中定义导出
-
script 中的 name 节点 可以通过 export default {name: ; }节点为当前组件定义一个名称。(自定义的组件名称可以清晰的区分每个组件)
-
vue 组件渲染期间需要用到的数据,可以定义在 data 节点中,需要return出去。且组件中的 data 必须是一个函数,不能直接指向一个数据对象。
-
export default { data () { return { } }, }
- 组件中的事件处理函数,必须定义到 methods 节点中
- style -> 组件的样式
- 可以在 <style> 节点中编写样式美化当前组件的 UI 结构。
-
如果希望使用 less 语法编写组件的 style 样式,可以按照如下两个步骤进行配置:① 运行 npm install less -D 命令安装依赖包,从而提供 less 语法的编译支持② 在 <style> 标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式
-
<style lang='less' scoped> </style>
定义一个组件
使用构建步骤时,一般会将 Vue 组件定义在一个单独的.vue 文件中,这被叫做单文件组件 (简称 SFC):
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">You clicked me {
{ count }} times.</button>
</template>
当不使用构建步骤时,一个 Vue 组件以一个包含 Vue 特定选项的 JavaScript 对象来定义,也可以使用 ID 选择器来指向一个元素 (通常是原生的 <template>
元素),Vue 将会使用其内容作为模板来源。 :
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
template: `
<button @click="count++">
You clicked me {
{ count }} times.
</button>`
// 或者 `template: '#my-template-element'`
}
也可以使用 ID 选择器来指向一个元素 (通常是原生的 <template>
元素),Vue 将会使用其内容作为模板来源。
组件注册
组件之间可以进行相互的引用,vue 中组件的引用原则:先注册后使用。
组件注册有两种方式:全局注册和局部注册。
全局注册
被全局注册的组件,可以在全局任何一个组件内使用
可以使用 Vue 应用实例的app.component() 方法注册,让组件在当前 Vue 应用中全局可用。
import { createApp } from 'vue'
const app = createApp({})
app.component(
// 注册的名字
'MyComponent',
// 组件的实现
{
/* ... */
}
)
如果使用单文件组件,你可以注册被导入的 .
Vue 文件:(在main.js中注册)
import MyComponent from './App.vue'
app.component('MyComponent', MyComponent)
app.component() 方法可以被链式调用
app
.component('ComponentA', ComponentA)
.component('ComponentB', ComponentB)
.component('ComponentC', ComponentC)
在其他组件中使用时直接以标签的形式进行使用:
<template>
<MyComponent></MyComponent>
</template>
全局注册的问题:
-
全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”)。如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。
-
全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。
相比之下,局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。
局部注册
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
如果没有使用 <script setup>,则需要使用 components 选项来显式注册:(组件内局部注册)
<script>
import ComponentA from './ComponentA.js'
export default {
components: {
// components 对象里的属性,它们的 key 名就是注册的组件名,而值就是相应组件的实现
ComponentA: ComponentA
}
// ...
}
</script>
注意:局部注册的组件在后代组件中并不可用。局部注册后仅在当前组件可用,而在任何的子组件或更深层的子组件中都不可用。
组件名格式
注:帕斯卡命名法(PascalCase) 它的标签名在 DOM 模板中是不可用的,详情参见 DOM 模板解析注意事项。
通过 name 属性注册组件
<script>
export default {
name: 'MySwiper',
}
</script>
main.js中:
import Swiper from './components/Swiper.vue'
//导入Swiper.vue后,可以把组件的 name 属性作为注册后组件的名称。
app.component(Swiper.name, Swiper)
组件之间的样式冲突问题
- 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
- 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素
解决样式冲突问题就需要为每个组件分配唯一的自定义属性。vue 为 style 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题。原理就是在编写组件样式时