5.1 组件化开发思想
- 组件化是vue的精髓,vue开发就是由一个一个组件构成
- 组件的分类:
- 页面级组件
- 业务上可复用的基础组件
- 与业务无关的独立功能组件
- 组件开发三要素:
- prop 用于定义组件的属性
- 自定义事件用于出发组件的事件
- slot 用于组件功能的扩展
- 组件设计需要考虑的问题:
- 可扩展性强
- 组件中方法函数的抽离,便于复用,适用程度高
- 文档清楚详细
- 颗粒度合适,适度抽象
- 功能尽可能单一
5.2 组建的创建与使用
-
组件划分
- 同样的界面使用两次及以上就可以划分为一个组件
- 组件可以无限嵌套
-
创建组件
- 可以独立创建
- 组件可以任意组合
- 模板+脚本+样式
-
注册组件
-
导入
import 组件名 from '文件路径'
-
注册
export default{ name:'该组件名' components:{ //注册导入的组件 component1, component2, component3, //可以修改名称重新自己设置 rename: component4 } }
-
使用:在模板中将组件直接当作标签使用
<已注册组件名></已注册组件名>
注意,驼峰命名可以改成小写加横线<CardItem>=<card-item>
,推荐使用-
-
5.3 组件之间的通信
-
最外层组件连接服务器获取数据,再将数据传递给需要的子组件
-
父子组件之间不能直接相互访问data内容
-
子组件定义**
props
**接收父组件用属性传递的数据-
props
是只读的:子组件无法直接修改从父组件传递过来的props
数据,它们被视为父组件的数据源。可以在标签中直接输入语句修改props数据,因为子组件接收到的
props
数据实际上是一个响应式的引用。这意味着如果子组件修改了这些引用指向的数据,Vue会自动进行检测和更新相关的视图。???更好的做法是在子组件内部定义一个局部的数据变量,并将
props
数据赋值给它,然后在局部变量上进行操作。这样可以避免不必要的副作用和数据流混乱。 -
数据单向流动:
props
的数据流是自上而下的,即从父组件流向子组件。任何在子组件中对props
进行更改都不会影响父组件中的数据。
//父组件 <template> <div class="box"> 父组件 <!--通过标签给予属性就可以传递数据到子组件--> <!-- 添加:绑定 就可以是整型或布尔型 否则只会当作字符串传输--> <daughter :myarr="arr" :num1="100" str="this is a test"></daughter> </div> </template> <script> import daughter from "@/components/daughter.vue"; export default { name: "mother", components:{ daughter }, data(){ return{ arr:['aaaa','bbbb','cccc'], } } } </script>
//子组件 <template> <div> 子组件 <br> <div class="box"> {{str}} <button @click="str=str+'abc'">改变</button> <button @click="demo()">改变2</button> <br> {{str2}} <br> {{num1}} <br> {{myarr}} <br> <p v-for="item in myarr" :key="item">{{item}}</p> </div> </div> </template> <script> export default { name: "daughter", // 这里接收父组件通过属性传来的数据,props意思就是属性,这些数据的使用和自己的属性几乎没有区别,可以直接在标签里改变属性 props:{ str:{ //必须指定类型 type:String, // 可选 说明必须传值 不能为空 require: true }, str2:{ type:String, // 可选 如果没有传该数据,会有属于自己的缺省值 default:'aaaa' }, num1:{ }, myarr:{ type: Array, } }, // 声明自己组件里的的数据 data(){ return{ msg:'this is data' } }, methods:{ demo(){ //访问不到str,不能修改props数据,props数据被视为只读 this.str=this.str+'bcd' } } } </script>
-
-
子组件通过**
$emit Events
**向父组件传递数据$emit
是组件实例的方法,每个 Vue 组件实例都会自动获得$emit
方法,在脚本中通过this调用,在模板中可以直接使用- 通过事件触发才可以传数据给父组件
- 子组件调用方法
$emit('myevent',args1,args2...)
自定义事件 - 父组件中,子组件标签绑定上一步的自定义事件
@myevent="fatherFun()"
,如果子组件调用了$emit
,就会触发自定义事件myevent
,通过这层绑定关系就可以在父组件中调用父组件的方法,并把数据args1,args2...
传递给父组件方法作为参数
//子组件 <template> <div> 子组件 <br> <button @click="fun('xxxx','111')">传递数据1给父组件</button> <br> <button @click="fun('yyyy','222')">传递数据2给父组件</button> <br> <button @click="fun('zzzz','333')">传递数据3给父组件</button> </div> </template> <script> export default { name: "daughter", props:{ }, data(){ }, methods:{ fun(str1,str2){ console.log('这是子组件数据'+str1); // 自定义事件give由父组件中的子组件标签绑定,str作为参数传给调用的父组件方法中 this.$emit('give',str1,str2); } } } </script>
//父组件 <template> <div class="box"> 父组件 <!--通过标签给予属性就可以传递数据到子组件--> <!-- 添加:绑定 就可以是整型或布尔型 否则只会当作字符串传输--> <!-- 触发事件give 子组件调用父组件demo方法,并传递数据给demo方法,传递参数可以是多个--> <daughter @give="demo" :myarr="arr" :num1="100" str="this is a test"></daughter> </div> </template> <script> import daughter from "@/components/daughter.vue"; export default { name: "mother", components:{ daughter }, data(){ }, methods:{ demo(str1,str2){ console.log('这是子组件调用了父组件方法传递了'+str1+str2) } } } </script>
-
组件插槽slot
-
插槽类似我们写函数时预留参数
-
Vue 实现了一套内容分发的API,将
<slot>
元素作为承载分发内容的出口 -
插槽可以实现组件的扩展性,抽取共性,保留不同,如果没有插槽,写好的组件就是固定的,父组件通过插槽可以传递不同数据给相似但不同的子组件
-
插槽可以有缺省值(直写就是缺省值),如果父组件没有传值则就是缺省值,否则被传的值就会被替换
-
具有name属性的插槽就是具名插槽,父组件通过子组件标签传递数据给具名插槽方式如下:
vue2
<my-com> <div solt="name"> aaaa </div> </my-com>
vue3
<my-com> <template v-slot:name>aaaa</template> </my-com>
-
语法糖:
#
代替v-slot:
<template> <div class="box"> 父组件 <my-com> <template v-slot:left> 1111 </template> <!--语法糖 一个#号代替v-slot--> <template #right> 2222 </template> </my-com> <my-com> <template v-slot:right> 2222 </template> </my-com> <!--默认插槽接收--> <my-com>1111</my-com> <my-com> <!--默认插槽接收--> <template v-slot:default> default </template> </my-com> </div> </template> <script> import MyCom from "@/components/MyCom.vue"; export default { name: "mother", components:{ MyCom }, data(){ } }, methods:{ } } } </script>
<script> //子组件 export default { name: "MyCom" } </script> <template> <div class="box2"> <!--插槽中预留获取的数据,也就是父组件中子组件标签包含的内容--> <slot name="left">这是左边缺省值</slot> <slot name="right">这是右边缺省值</slot> <!-- 没有设置名字的这个插槽就是default插槽--> <slot>这是缺省值</slot> </div> </template>
-
5.4 组件生命周期
-
所有组件都有生命周期,生命周期指组件在创建、更新和销毁过程中经历的一系列阶段
-
调用生命周期函数时书写顺序无关,只和它本身有关系
-
生命周期(钩子)函数:
生命周期函数被称为“钩子函数”,是因为它们提供了在组件不同生命周期阶段中“挂载”(hook)自定义逻辑的机会。
- 创建阶段:
beforeCreate
在实例初始化之后、数据观测 (data observation) 和 event/watcher 事件配置之前被调用。此时组件的选项和初始数据还未被设置。created
在实例创建完成后被调用。此时组件已经完成了数据观测、属性和方法的运算,但尚未挂载到 DOM 中。
- 挂载阶段
beforeMount
Vue 组件生命周期的一个钩子函数,在组件挂载到 DOM 前被调用。在此阶段,模板已编译完成,但尚未将其渲染到页面上。mounted
在组件挂载到 DOM 后被调用。此时组件已经完成了首次渲染,并将其挂载到页面上。
- 更新阶段
beforeUpdate
在组件更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。允许在更新之前访问现有的 DOM。updated
在组件更新完毕后被调用。此时,虚拟 DOM 已重新渲染,并应用了补丁到页面上。
- 销毁阶段
beforeUnmount
在组件销毁之前被调用。此时,组件仍然完全可用。unmounted
在组件销毁后被调用。此时,组件实例已经被销毁,不再可用。
- 缓存阶段(只有组件被包裹在
<keep-alive>
组件内才会生效)activated
当包含组件的<keep-alive>
组件激活并将其缓存组件重新渲染到页面上时,会触发该钩子函数,通常用于初始化一些数据或执行需要在组件激活时进行的操作,如重新加载数据、打开定时器等deactivated
当包含组件的<keep-alive>
组件停用并从页面中移除缓存组件时,会触发该钩子函数。用于清理一些资源或取消未完成的操作,如清除定时器、取消订阅等。
- 创建阶段:
-
通过生命周期函数,可以在不同的阶段执行相关的操作,例如在
mounted
钩子中执行一些异步操作、在beforeUnmount
钩子中清理事件监听器等。 -
Vue 3 中的生命周期函数名称相较于Vue2没有发生变化,但是 Vue 3 中引入了 Composition API,可以通过
setup
函数来替代一部分生命周期钩子的功能。-
相比于 Vue 2.x 版本的选项式 API(Options API),Vue3新引入的Composition API 提供了更灵活和可组合的方式来组织和管理组件的逻辑代码。
-
使用 Composition API可以将相关的逻辑代码聚合到一个或多个自定义函数中,而不是按照生命周期函数来划分。这样做的好处是能够更容易地重用和组合逻辑,提高代码的可读性和维护性。
-
通过
setup
函数来定义组件的逻辑代码。setup
函数是一个在组件创建过程中被调用的特殊函数,它接收两个参数:props
和context
。 -
setup
函数内部可以使用 Vue 3 提供的一系列函数和响应式 API,如ref
、reactive
、watch
等,以及自定义的函数和变量。这些函数和 API 可以用来定义组件的状态、计算属性、方法、事件处理等。
-