vue3从入门到精通下
侦听器
-
作用:可以监听到
data
中数据的变化 -
语法:
watch:{ // 函数名必须和监听的数据名称保持一致 监听的属性名(newValue,oldValue){ // 业务逻辑 } }
表单输入绑定
-
v-model
修饰符-
.lazy
-
默认情况下,
v-model
会在每次input
事件后更新数据input
事件:输入内容改变就会触发 -
添加
.lazy
修饰符来改为在每次change
事件后更新数据。change
事件:输入框失去焦点时会触发,如鼠标点击其他地方
-
-
.number
,输入数据转换成number
类型 -
.trim
,输入删除空格
<input type='text' v-model.number = 'xxx'/> // 数据类型
-
模板引用
-
作用:使用
ref
相关内容,在vue
中直接读取dom
、操作dom
-
语法:
- 模板中:给标签添加
ref='domname'
属性 vue
中:- 获取
dom
元素:this.$refs.domname
- 使用原生
js
的属性xxx
进行操作:this.$refs.domname.xxx
- 获取
- 模板中:给标签添加
-
总结,已有的对模板的操作
- 修改内容:使用插值语法
- 修改属性:使用
v-bind
/:
-
事件:
v-on
/@
- 操作
dom
:ref
组件组成
-
定义:将
vue
组件定义子定义在一个单独的.vue
文件中,单文件组件称为sfc
-
优势:可复用性,提高开发效率和可维护性
-
在一个组件中使用其它组件使用步骤:
-
引入其它组件
import
-
注册引入组件
compoents:{ }
-
在标签中使用
< xxx />
-
组件注册方式
-
前提:一个
vue
组件在使用前必须被注册,这样vue
才能在渲染模板时找到其对应的时间。 -
组件的注册有两种方式:
-
全局注册:在最外侧
main.js
中import
和注册app.component()
- 优点:方便,全局注册后,在任意组件的
template
中都可以使用该组件 - 缺点:
- 全局注册后,没有被使用的组件也会被打包,无法自动移除(
tree-shaking
) - 全局注册在大型项目中的依赖关系不那么明确。
- 全局注册后,没有被使用的组件也会被打包,无法自动移除(
- 优点:方便,全局注册后,在任意组件的
-
局部注册:在某一个组件
import
和写在components
下,之后就可以在该组件的模板中使用该组件
-
组件传递数据
-
需求:组件和组件之间并不是完全独立的,有时候需要通信传递数据
-
语法:
-
父组件的模板中:
在子组件的标签上以
:key='xxx'
(活数据)/key='xxx'
(死数据)的形式传递数据 -
子组件的实例中:在
data
平级的props
中写接受信息
-
注意
props
传递数据只能从父亲到子,不能从子到父。且子组件处不能直接修改数据,使用子组件的
methods
方法修改数据是不行的!如果需要修改数据,应该在子组件处使用触发父元素方法,让父元素修改数据。
- 可传递的数据类型:任何数据类型,下面是常见的类型
- 基本数据类型,比较常见的字符串、数字
- 数组
- 对象
- 函数
-
props
传递校验在子组件的
props
中更细致的声明对传入数据的要求,-
类型
type
-
传递方式不受限制,基本类型、引用类型和函数都可以
-
如果支持多种类型使用数组包含多个类型,如
[String,Number]
-
-
是否必须
require
-
默认值
default
-
基本数据类型:可以直接写
default:值
-
数组和对象:必须通过工厂函数返回默认值
default()=> ['']
、default()=> ({})
-
-
组件事件
-
作用:
$emit
触发自定义事件,实现子组件给父组件传递数据 -
操作:
-
子组件:
- 子组件触发事件执行回调函数
- 在该回调函数中使用
this.$emit
方法触发父组件定义在子组件身上的自定义事件
-
父组件:
-
在模板中使用子组件,在子组件上绑定自定义事件和回调函数,此处回调函数不用写括号和参数
-
在实例中的
methods
下,写对应的回调函数,(如果有接受数据,需要在此处写接受的参数)
-
-
完成流程
- 用户点击、用户输入等操作触发子组件上绑定的回调函数
- 子组件回调函数触发父组件的自定义事件,执行父组件自定义事件对应的回调函数
-
组件事件配合v-model使用
-
需求:
- 用户在子组件使用
v-model
输入数据 - 在父组件上实时接收、展示数据。
常见场景,搜索子组件接受用户的输入,父组件展示数据。
- 用户在子组件使用
-
解决方法:
-
难点:应该在哪里触发父组件的自定义事件,即在哪里写`this.$emit('事件名',数据)`?
之前学习的子组件给父组件通信,是由子组件的点击事件(程序员编程显示指定的用户操作)等事件触发,然后在点击事件的回调函数中使用
this.$emit
触发父组件的自定义事件。 -
解决方法:
- 在
watch
中监听对应的属性, - 当属性值发生改变时自动执行
this.$emit(‘自定义事件’,newValue)
,触发自定义事件将数据传递给父组件
- 在
-
拓展
只要数据发生改变就进行一些操作,优先考虑
watch
,因为watch
的作用就是检测数据的变化。
组件数据传递
-
之前讲过了组件之间的数据传递
-
props
:父传子 -
自定义事件:子传父
-
-
props
:默认是父传子,但是可以通过一些额外操作实现子传父,即,传递函数给子组件 -
实现
-
父组件:
-
组件实例中,
methods
下定义方法methods:{ // 父组件处定义方法,写形参接受数据 transferData(sonData){ // 其他业务代码 this.parentData = sonData // 将子组件传递过来的数据赋值给父组件,传原理:主要是通过this.parentData的引用接收到了子组件的数据 }
-
模板中,在子组件上写属性:
<Son :onEvent="transferData"/>
/
-
-
子组件
porps
接受函数类型的数据- 在模板调用函数或者由其他用户事件触发父组件传递过来的函数
-
透传Attributes
-
透传定义:
传递给一个组件东西,却没有被该组件声明为
props
emits
的attribute
v-on
事件监听器
最常见的例子就是
class
,style
,id
-
表现:当组件只有一个根元素,透传的
attribute
会自动被添加到根元素上。透传的属性会被原样(
key=value
)出现在子组件的根元素上,可以通过谷歌开发者工具查看对应的dom
的属性。 -
限制:子组件必须是唯一根元素,如果有多个根元素那么不生效
-
禁用:如果不想使用这个功能,写如下代码:
插槽
-
需求:
-
props
之前学习了
props
,使得子组件可以接受父组件传递过来的任意JavaScript
数据类型的数据。 -
slot
- 那么子组件如何接受父组件传递过来的模板内容呢?
- 在某些场合,可能想要给子组件传递一些模板片段,让子组件在自己的组件中渲染。
-
-
默认插槽
-
实现步骤:
-
子组件:写
<slot></slot>
-
等父组件传递过来内容后,这里的东西将会被代替为父组件传递内容
-
可以通过调整
slot
的位置来调整模板片段的显示位置
-
-
父组件:在模板中使用子组件的双标签形式,在双标签之间写要传入的模板内容
-
slot
是插槽出口,表示父元素提供的插槽内容将在哪里被渲染。 -
-
渲染作用域
-
原理
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件的模板中的定义的。
-
适用场景
插槽里面的内容用的了动态数据,那这个动态数据应该定义在父组件的
data
中还是子组件的data
中?写在父组件的data
中
-
-
插槽默认内容
- 作用:如果父组件没有传递模板片段给子组件,那么子组件可以显示一个默认值
- 语法:在子组件的
slot
开始和结束标签之间写显示的默认内容,即<slot>这里写默认内容<slot/>
-
具名插槽
-
定义:有名字的插槽
父组件可以传递多个插槽给子组件,此时父、子组件的插槽就需要给定名字。
-
实现步骤:
-
父组件:
在子组件的开始和结束标签之间写:
<template #name1>这里写模板片段1</template>
<template #name2>这里写模板片段2</template>
-
子组件:
子组件中给
slot
标签添加name=xxx
属性,即<slot name="name1"><slot>
、<slot name="name2"><slot>
-
具名插槽图片演示
同时使用匿名插槽和具名插槽传递数据给子组件,父组件处写法:
-
-
插槽中的数据传递(重要)
-
需求:在某些场景下插槽的内容可能想要同时使用父组件域和子组件域内的数据,要实现这个功能,需要让子组件在渲染时提供数据给插槽
-
实现方法:
-
子组件
-
在
slot
标签上使用v-bind
绑定对应数据,即默认插槽
<slot :text='message'>
具名插槽
<slot name='title':text='message'>
-
注意:可传递多个数据,如果传递多个父组件会统一接受到一个对象中
-
-
父组件
-
对于匿名插槽
在子组件的开始标签处使用
v-slot="slotProps"
接受子组件传递的数据,模板中使用slotProps.xxx
使用数据 -
对于具名插槽
在对应的
template
开始标签处使用#name="slotProps"
,接受子组件传递数据,模板中使用slotPrors.xxx
使用数据
注意
v-slot='slotProps'
等号后面的名字不是一定要是这个,这个是习惯- 父组件会将子组件传递的数据统一
slotProps
对象中接收,所以使用时就以slotProps.xxx
方法使用
-
-
-
组件生命周期
-
生命周期意义
从组件创建到销毁的经历一系列的步骤,在不同的重要节点可以做一些重要的事情。
-
区分:
生命周期钩子函数和普通
methods
:生命周期钩子函数会自动调用。 -
生命周期函数
- 创建期:
beforeCreate
、created
- 在这两个钩子之间实现组件初始化,此时有了
data
和各种方法 created
这个时期及之后可以使用this.data
获取数据
- 在这两个钩子之间实现组件初始化,此时有了
- 挂载期:
beforeMount
、mounted
- 在这两个钩子之间实现页面渲染,此时页面有
dom
结构 mounted
这个时期及之后才能通过ref
获取dom
结构
- 在这两个钩子之间实现页面渲染,此时页面有
- 更新期:
beforeUpdate
、updated
- 销毁期:
beforeDestory
、destoryed
- 创建期:
经验:结构更重要,还是数据更重要?
结构更重要,应该先保证结构出来然后再获取渲染数据
所以网络请求写在
mounted
中而不写在created
。因为mounted
此时结构已经渲染完成,然后再去获取数据
动态组件
-
需求:有些场景需要两个或多个组件之间来回切换,被切换掉的组件会被卸载。
(不是通过
v-if
和v-show
方法,但是确实也可以通过这个方法切换) -
实现:
主要操作在父组件的模板中
<component :is='xxx'></comppnent>
xxx
代表要渲染的组件的名字
区分
v-show
:- 只有首次加载渲染那渲染,显示和隐藏切换:只是控制
display
的属性进行显示和隐藏 - 隐藏时节点也存在于
dom
树
- 只有首次加载渲染那渲染,显示和隐藏切换:只是控制
-
v-if
:-
显示和隐藏切换一次就需要重新渲染,
- 隐藏时
dom
树中没有对应的节点 - 配合
v-once
使用时, 可以保留组件状态避免重新渲染
-
-
动态组件:
- 渲染过程和
v-if
类似,但又不同 - 显示时重新渲染,隐藏时不会重新渲染,隐藏时节点也不在
dom
树中 - 配合
<keep-alive>
使用时, 可以保留组件状态避免重新渲染
- 渲染过程和
组件保持存活
-
需求
-
当使用
<component :is='xxx'>
在多个组件之间切换时,被切换掉的组件会被卸载 -
频繁的加载和卸载会耗费资源。
-
-
解决方法
- 通过
<keep-alive>
组件强制被切换掉的组件仍然保持存活状态。
- 通过
异步组件
-
组件分类:
-
同步组件:项目一旦运行,所以项目都会加载
-
异步组件:用到哪个组件加载哪个组件,可以让第一次打开应用时更快
-
-
异步组件
-
作用:优化大型项目的性能
-
实现:
修改的代码是组件中的导入代码
import
,使用defineAsynComponent
方法
-
区分
- 按需加载:
- 技术:使用
es6
的import
- 技术:使用
- 异步加载:
- 技术:使用
vue
提供的defineAsyncComponent
- 技术:使用
依赖注入
-
需求:父组件传递给子组件数据可以使用
props
,如果祖先给孙子或更后代传递数据,通props
一层一层的传就很复杂了,有什么其他解决方法吗?依赖注入 -
语法:
-
provide
:祖先使用provide
传递<script> export default { // 传递死数据 povide:{ message:'爷爷的数据' } // 传递活数据 provide(){ return { message:this.message } } } </script>
-
inject
:后代使用indject
接受<script> export default { inject:['message'] // 接收到的数据也可以传递给data data(){ return{ fullMessage: this.message } } } </script>
-
注意
provide
和inject
只能由上到下传递,不能由下到上传递
vue应用
-
问题:
vue
项目是从哪里开始运行的? -
应用实例:
- 每一个
vue
应用都是通过createApp
创建一个vue
应用实例 - 在一个项目当中,有且只有一个
vue
的实例对象
- 每一个
-
根组件:
- 传入
createApp
的内容要求是一个根组件,所有的组件从根组件开始一层层往下执行 APP
就是根组件。
- 传入
-
挂载应用
-
应用实例必须在调用了
mount()
方法后才会渲染出来。 -
挂载到哪里?
-
该方法中接受一个
容器参数
,可以是实际dom
元素,也可以是css
选择器字符串。 -
就挂在到这个
容器参数
对应的dom
元素上。 -
app.mount(‘#app')
,就是挂在到index.html
下面以id=’app‘
的dom
元素上。
-
-