Vue3快速上手
提示:Vue尚硅谷笔记整理
一、使用 vue-cli 创建Vue3.0工程(js版)
官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve
二、常用 Composition API
1. setup
理解:
Vue3.0中一个新的配置项,值为一个函数。
setup是所有Composition API(组合API)“ 表演的舞台 ”。
组件中所用到的:数据、方法等等,均要配置在setup中。
- setup函数的两种返回值:
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
若返回一个渲染函数:则可以自定义渲染内容。(了解)
- 注意点:
尽量不要与Vue2.x配置混用
- Vue2.x配置
(data、methos、computed...)
中可以访问到setup
中的属性、方法。 - 但在
setup
中不能访问到Vue2.x配置(data、methos、computed...)
。 - 如果有重名,
setup
优先。
- Vue2.x配置
setup不能是一个
async
函数,因为返回值不再是return
的对象, 而是promise
, 模板看不到return
对象中的属性。(后期也可以返回一个Promise
实例,但需要Suspense
和异步组件的配合)一个人的信息
姓名:{{name}}
年龄:{{age}}
1.1 setup的两个注意点
- setup执行的时机
在
beforeCreate
之前执行一次,this
是undefined
。- setup的参数
props
:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。attrs
: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于this.$attrs
。slots
: 收到的插槽内容, 相当于 this.$slots。emit
: 分发自定义事件的函数, 相当于 this.$emit。
context
:上下文对象
2. ref函数
1、作用: 定义一个响应式的数据
2、语法: const xxx = ref(initValue)
- 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
- JS中操作数据:
xxx.value
- 模板中读取数据: 不需要
.value
,直接:{{ xxx }}
3、备注:
- 接收的数据可以是:基本类型、也可以是对象类型。
- 基本类型的数据:响应式依然是靠
Object.defineProperty()
的get
与set
完成的。
4、vue3如何通过ref属性获取元素
I am DIV
5、Vue3 父组件调用子组件的方法
// 父组件
父页面
// 子组件
子页面
一个人的信息
姓名:{{name}}
年龄:{{age}}
工作种类:{{job.type}}
工作薪水:{{job.salary}}
3. reactive函数
- 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
- 语法:
const 代理对象= reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) reactive
定义的响应式数据是“深层次的”。内部基于
ES6
的Proxy
实现,通过代理对象操作源对象内部数据进行操作。一个人的信息
姓名:{{person.name}}
年龄:{{person.age}}
工作种类:{{person.job.type}}
工作薪水:{{person.job.salary}}
爱好:{{person.hobby}}
测试的数据c:{{person.job.a.b.c}}
4. Vue3.0中的响应式原理
4.1 vue2.x的响应式
1、 实现原理:
- 对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
2、 存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
模拟Vue2中实现响应式
//源数据 let person = { name:'张三', age:18 } Object.defineProperty(p,'name',{ configurable:true, get(){ //有人读取name时调用 return person.name }, set(value){ //有人修改name时调用 console.log('有人修改了name属性,我发现了,我要去更新界面!') person.name = value } }) Object.defineProperty(p,'age',{ get(){ //有人读取age时调用 return person.age }, set(value){ //有人修改age时调用 console.log('有人修改了age属性,我发现了,我要去更新界面!') person.age = value } })
4.2 Vue3.0的响应式
1、实现原理:
- 通过
Proxy
(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。 - 通过
Reflect
(反射): 对源对象的属性进行操作。 MDN文档中描述的
Proxy
与Reflect
:
2、模拟Vue3中实现响应式
//源数据
let person = {
name:'张三',
age:18
}
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`)
Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`)
return Reflect.deleteProperty(target,propName)
}
})
5. reactive对比ref
1、从定义数据角度对比:
ref
用来定义:基本类型数据。reactive
用来定义:对象(或数组)类型数据。- 备注:
ref
也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive
转为代理对象。
2、从原理角度对比:
ref
通过Object.defineProperty()
的get与set来实现响应式(数据劫持)。reactive
通过使用Proxy来实现响应式(数据劫持), 并通过Reflect
操作源对象内部的数据。
3、从使用角度对比:
ref
定义的数据:操作数据需要.value
,读取数据时模板中直接读取不需要.value
。reactive
定义的数据:操作数据与读取数据:均不需要.value
。
7. 计算属性与监视
7.1. computed函数
- 与Vue2.x中computed配置功能一致
写法
一个人的信息
姓:
名:
全名:{{person.fullName}}
全名:7.2. watch函数
1、与
Vue2.x
中watch
配置功能一致
2、两个小“坑”:- 监视
reactive
定义的响应式数据时:oldValue
无法正确获取、强制开启了深度监视(deep
配置失效)。 - 监视
reactive
定义的响应式数据中某个属性时:deep
配置有效。
3、写法
当前求和为:{{sum}}
当前的信息为:{{msg}}
姓名:{{person.name}}
年龄:{{person.age}}
薪资:{{person.job.j1.salary}}K
7.3. watchEffect函数
1、watch
的套路是:既要指明监视的属性,也要指明监视的回调。
2、watchEffect
的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
3、watchEffect
有点像computed
:
- 但
computed
注重的计算出来的值(回调函数的返回值),所以必须要写返回值。 而
watchEffect
更注重的是过程(回调函数的函数体),所以不用写返回值。求和为:{{sum}}
当前信息:{{msg}}
姓名:{{person.name}}
年龄:{{person.age}}
薪资:{{person.job.j1.salary}}K
8. 生命周期
1、Vue3.0
中可以继续使用Vue2.x
中的生命周期钩子,但有有两个被更名:
beforeDestroy
改名为beforeUnmount
destroyed
改名为unmounted
2、Vue3.0
也提供了 Composition API
形式的生命周期钩子,与Vue2.x
中钩子对应关系如下:
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
当前求和为:{{sum}}
9. 自定义hook函数
1、什么是hook
?—— 本质是一个函数,把setup
函数中使用的Composition API
进行了封装。
2、类似于vue2.x
中的mixin
。
3、自定义hook
的优势: 复用代码, 让setup
中的逻辑更清楚易懂。
4、Demo.vue
中
当前求和为:{{sum}}
当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}
5、hooks/usePoint.js
中
import {reactive,onMounted,onBeforeUnmount} from 'vue'
export default function (){
//实现鼠标“打点”相关的数据
let point = reactive({
x:0,
y:0
})
//实现鼠标“打点”相关的方法
function savePoint(event){
point.x = event.pageX
point.y = event.pageY
console.log(event.pageX,event.pageY)
}
//实现鼠标“打点”相关的生命周期钩子
onMounted(()=>{
window.addEventListener('click',savePoint)
})
onBeforeUnmount(()=>{
window.removeEventListener('click',savePoint)
})
return point
}
10. toRef
1、作用:创建一个 ref
对象,其value
值指向另一个对象中的某个属性。
2、语法:const name = toRef(person,'name')
3、应用: 要将响应式对象中的某个属性单独提供给外部使用时。
4、扩展:toRefs
与toRef
功能一致,但可以批量创建多个 ref
对象,语法:toRefs(person)
{{person}}
姓名:{{name}}
年龄:{{age}}
薪资:{{job.j1.salary}}K
三、其它 Composition API
1. shallowReactive 与 shallowRef
1、shallowReactive
:只处理对象最外层属性的响应式(浅响应式)。
2、shallowRef
:只处理基本数据类型的响应式, 不进行对象的响应式处理。
3、什么时候使用?
- 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===>
shallowReactive
。 - 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===>
shallowRef
。
当前的x.y值是:{{x.y}}
{{person}}
姓名:{{name}}
年龄:{{age}}
薪资:{{job.j1.salary}}K
2. readonly 与 shallowReadonly
1、readonly
: 让一个响应式数据变为只读的(深只读)。
2、shallowReadonly
:让一个响应式数据变为只读的(浅只读)。
3、应用场景: 不希望数据被修改时。
当前求和为--:{{sum}}
姓名:{{name}}
年龄:{{age}}
薪资:{{job.j1.salary}}K
3. toRaw 与 markRaw
1、toRaw:
- 作用:将一个由
reactive
生成的响应式对象转为普通对象。 - 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
2、markRaw: - 作用:标记一个对象,使其永远不会再成为响应式对象。
应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类库等。
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
当前求和为:{{sum}}
姓名:{{name}}
年龄:{{age}}
薪资:{{job.j1.salary}}K
座驾信息:{{person.car}}
4. customRef
1、作用:创建一个自定义的 ref
,并对其依赖项跟踪和更新触发进行显式控制。
2、实现防抖效果:
{{ keyWord }}
5. provide 与 inject
1、作用:实现祖与后代组件间通信
2、套路:父组件有一个 provide
选项来提供数据,后代组件有一个 inject
选项来开始使用这些数据
3、具体写法:
祖组件中:
setup(){ ...... let car = reactive({name:'奔驰',price:'40万'}) provide('car',car) ...... }
后代组件中:
setup(props,context){ ...... const car = inject('car') return {car} ...... }
6. 响应式数据的判断
- isRef: 检查一个值是否为一个
ref
对象 - isReactive: 检查一个对象是否是由
reactive
创建的响应式代理 - isReadonly: 检查一个对象是否是由
readonly
创建的只读代理 isProxy: 检查一个对象是否是由
reactive
或者readonly
方法创建的代理setup(){ let car = reactive({name:'奔驰',price:'40W'}) let sum = ref(0) let car2 = readonly(car) console.log(isRef(sum)) console.log(isReactive(car)) console.log(isReadonly(car2)) console.log(isProxy(car)) console.log(isProxy(sum)) return {...toRefs(car)} }
四、新的组件
1. Fragment
1、在Vue2中: 组件必须有一个根标签
2、在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment
虚拟元素中
3、好处: 减少标签层级, 减小内存占用
2. Teleport
什么是Teleport?—— Teleport
是一种能够将我们的组件html
结构移动到指定位置的技术。
我是一个弹窗
3. Suspense
1、等待异步组件时渲染一些额外内容,让应用有更好的用户体验
2、使用步骤:
异步引入组件
import {defineAsyncComponent} from 'vue' const Child = defineAsyncComponent(()=>import('./components/Child.vue')) 使用Suspense包裹组件,并配置好default 与 fallback
我是App组件
加载中.....
五、其它
1. 全局API的转移
1、Vue 2.x 有许多全局 API 和配置。
例如:注册全局组件、注册全局指令等。
//注册全局组件 Vue.component('MyButton', { data: () => ({ count: 0 }), template: '' }) //注册全局指令 Vue.directive('focus', { inserted: el => el.focus() }
2、Vue3.0中对这些API做出了调整:
- 将全局的API,即:Vue.xxx调整到应用实例(app)上
2.x 全局 API(Vue ) |
3.x 实例 API (app ) |
---|---|
Vue.config.xxxx | app.config.xxxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
2. 其他改变
1、data
选项应始终被声明为一个函数。
过度类名的更改:
.v-enter, .v-leave-to { opacity: 0; } .v-leave, .v-enter-to { opacity: 1; }
Vue3.x写法
.v-enter-from, .v-leave-to { opacity: 0; } .v-leave-from, .v-enter-to { opacity: 1; }
3、移除
keyCode
作为v-on
的修饰符,同时也不再支持config.keyCodes
4、移除v-on.native
修饰符父组件中绑定事件
子组件中声明自定义事件
5、移除过滤器(
filter
)
过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。