Vue3疾速上手
1.Vue 3简介
- 2020年9月18日,Vue.js公布3.0版本,代号:One Piece(海贼王)
- 耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者
- github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
2.Vue3带来了什么
1.性能的晋升
- 打包大小缩小41%
- 首次渲染快55%, 更新渲染快133%
- 内存缩小54%
......
2.源码的降级
- 应用Proxy代替defineProperty实现响应式
- 重写虚构DOM的实现和Tree-Shaking
......
3.拥抱TypeScript
- Vue3能够更好的反对TypeScript
4.新的个性
Composition API(组合API)
- setup配置
- ref与reactive
- watch与watchEffect
- provide与inject
- ......
新的内置组件
- Fragment
- Teleport
- Suspense
其余扭转
- 新的生命周期钩子
- data 选项应始终被申明为一个函数
- 移除keyCode反对作为 v-on 的修饰符
- ......
一、创立Vue3.0工程
1.应用 vue-cli 创立
官网文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上vue --version## 装置或者降级你的@vue/clinpm install -g @vue/cli## 创立vue create vue_test## 启动cd vue_testnpm run serve
2.应用 vite 创立
官网文档:https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网:https://vitejs.cn
- 什么是vite?—— 新一代前端构建工具。
劣势如下:
- 开发环境中,无需打包操作,可疾速的冷启动。
- 轻量疾速的热重载(HMR)。
- 真正的按需编译,不再期待整个利用编译实现。
- 传统构建 与 vite构建比照图
## 创立工程npm init vite-app <project-name>## 进入工程目录cd <project-name>## 装置依赖npm install## 运行npm run dev
二、罕用 Composition API
官网文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
1.拉开序幕的setup
- 了解:Vue3.0中一个新的配置项,值为一个函数。
- setup是所有Composition API(组合API)“ 表演的舞台 ”。
- 组件中所用到的:数据、办法等等,均要配置在setup中。
setup函数的两种返回值:
- 若返回一个对象,则对象中的属性、办法, 在模板中均能够间接应用。(重点关注!)
setup(){ //数据 let name = '张三' let age = 18 //办法 function sayHello(){ alert(`我叫${name},我${age}岁了,你好啊`) } // 返回一个对象(罕用) return { name,age,sayHello } }
2. 若返回一个渲染函数:则能够自定义渲染内容。(理解)
setup(){ //数据 let name = '张三' let age = 18 //办法 function sayHello(){ alert(`我叫${name},我${age}岁了,你好啊`) } // 返回一个函数(渲染函数) return ()=>{return h('h1','尚硅谷')} }
留神点:
尽量不要与Vue2.x配置混用
- Vue2.x配置(data、methos、computed...)中能够拜访到setup中的属性、办法。
- 但在setup中不能拜访到Vue2.x配置(data、methos、computed...)。
- 如果有重名, setup优先。
- setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(前期也能够返回一个Promise实例,但须要Suspense和异步组件的配合)
2.ref函数
ref reference 援用
impl implement 实现
- 作用: 定义一个响应式的数据
语法:
const xxx = ref(initValue)
- 创立一个蕴含响应式数据的援用对象(reference对象,简称ref对象)。
- JS中操作数据:
xxx.value
- 模板中读取数据: 不须要.value,间接:
<div>{{xxx}}</div>
备注:
- 接管的数据能够是:根本类型、也能够是对象类型。
- 根本类型的数据:响应式仍然是靠
Object.defineProperty()
的get
与set
实现的。 - 对象类型的数据:外部 “ 求助 ” 了Vue3.0中的一个新函数——
reactive
函数。
3.reactive函数
- 作用: 定义一个对象类型的响应式数据(根本类型不要用它,要用
ref
函数) - 语法:
const 代理对象= reactive(源对象)
接管一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) - reactive定义的响应式数据是“深层次的”。
- 外部基于 ES6 的 Proxy 实现,通过代理对象操作源对象外部数据进行操作。
4.Vue3.0中的响应式原理
vue2.x的响应式
实现原理:
- 对象类型:通过
Object.defineProperty()
对属性的读取、批改进行拦挡(数据劫持)。 - 数组类型:通过重写更新数组的一系列办法来实现拦挡。(对数组的变更办法进行了包裹)。
- 对象类型:通过
Object.defineProperty(data, 'count', { get () {}, set () {}})
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 间接通过下标批改数组, 界面不会自动更新。
Vue3.0的响应式
实现原理:
- 通过Proxy(代理): 拦挡对象中任意属性的变动, 包含:属性值的读写、属性的增加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作。
MDN文档中形容的Proxy与Reflect:
- Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
- Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
new Proxy(data, { // 拦挡读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦挡设置属性值或增加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦挡删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) }})proxy.name = 'tom'
5.reactive比照ref
从定义数据角度比照:
- ref用来定义:根本类型数据。
- reactive用来定义:对象(或数组)类型数据。
- 备注:ref也能够用来定义对象(或数组)类型数据, 它外部会主动通过
reactive
转为代理对象。
从原理角度比照:
- ref通过
Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。 - reactive通过应用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象外部的数据。
- ref通过
从应用角度比照:
- ref定义的数据:操作数据须要
.value
,读取数据时模板中间接读取不须要.value
。 - reactive定义的数据:操作数据与读取数据:均不须要
.value
。
- ref定义的数据:操作数据须要
6.setup的两个留神点
setup执行的机会
- 在beforeCreate之前执行一次,this是undefined。
setup的参数
- props:值为对象,蕴含:组件内部传递过去,且组件外部申明接管了的属性。
context:上下文对象
- attrs: 值为对象,蕴含:组件内部传递过去,但没有在props配置中申明的属性, 相当于
this.$attrs
。 - slots: 收到的插槽内容, 相当于
this.$slots
。 - emit: 散发自定义事件的函数, 相当于
this.$emit
。
- attrs: 值为对象,蕴含:组件内部传递过去,但没有在props配置中申明的属性, 相当于
7.计算属性与监督
1.computed函数
- 与Vue2.x中computed配置性能统一
- 写法
import {computed} from 'vue'setup(){ ... //计算属性——简写 let fullName = computed(()=>{ return person.firstName + '-' + person.lastName }) //计算属性——残缺 let fullName = computed({ get(){ return person.firstName + '-' + person.lastName }, set(value){ const nameArr = value.split('-') person.firstName = nameArr[0] person.lastName = nameArr[1] } })}
2.watch函数
- 与Vue2.x中watch配置性能统一
两个小“坑”:
- 监督reactive定义的响应式数据时:oldValue无奈正确获取、强制开启了深度监督(deep配置生效)。
- 监督reactive定义的响应式数据中某个属性时:deep配置无效。
//状况一:监督ref定义的响应式数据watch(sum,(newValue,oldValue)=>{ console.log('sum变动了',newValue,oldValue)},{immediate:true})//状况二:监督多个ref定义的响应式数据watch([sum,msg],(newValue,oldValue)=>{ console.log('sum或msg变动了',newValue,oldValue)}) /* 状况三:监督reactive定义的响应式数据 若watch监督的是reactive定义的响应式数据,则无奈正确取得oldValue!! 若watch监督的是reactive定义的响应式数据,则强制开启了深度监督 */watch(person,(newValue,oldValue)=>{ console.log('person变动了',newValue,oldValue)},{immediate:true,deep:false}) //此处的deep配置不再见效//状况四:监督reactive定义的响应式数据中的某个属性watch(()=>person.job,(newValue,oldValue)=>{ console.log('person的job变动了',newValue,oldValue)},{immediate:true,deep:true}) //状况五:监督reactive定义的响应式数据中的某些属性watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{ console.log('person的job变动了',newValue,oldValue)},{immediate:true,deep:true})//非凡状况watch(()=>person.job,(newValue,oldValue)=>{ console.log('person的job变动了',newValue,oldValue)},{deep:true}) //此处因为监督的是reactive素定义的对象中的某个属性,所以deep配置无效
3.watchEffect函数
- watch的套路是:既要指明监督的属性,也要指明监督的回调。
- watchEffect的套路是:不必指明监督哪个属性,监督的回调中用到哪个属性,那就监督哪个属性。
watchEffect有点像computed:
- 但computed重视的计算出来的值(回调函数的返回值),所以必须要写返回值。
- 而watchEffect更重视的是过程(回调函数的函数体),所以不必写返回值。
//watchEffect所指定的回调中用到的数据只有发生变化,则间接从新执行回调。watchEffect(()=>{ const x1 = sum.value const x2 = person.age console.log('watchEffect配置的回调执行了')})
8.生命周期
- Vue3.0中能够持续应用Vue2.x中的生命周期钩子,但有有两个被更名:
beforeDestroy
改名为beforeUnmount
destroyed
改名为unmounted
Vue3.0也提供了 Composition API 模式的生命周期钩子,与Vue2.x中钩子对应关系如下:
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
9.自定义hook函数
- 什么是hook?—— 实质是一个函数,把setup函数中应用的Composition API进行了封装。
- 相似于vue2.x中的mixin。
- 自定义hook的劣势: 复用代码, 让setup中的逻辑更分明易懂。
10.toRef
- 作用:创立一个 ref 对象,其value值指向另一个对象中的某个属性。
- 语法:
const name = toRef(person,'name')
- 利用: 要将响应式对象中的某个属性独自提供给内部应用时。
- 扩大:
toRefs
与toRef
性能统一,但能够批量创立多个 ref 对象,语法:toRefs(person)
三、其它 Composition API
1.shallowReactive 与 shallowRef
- shallowReactive:只解决对象最外层属性的响应式(浅响应式)。
- shallowRef:只解决根本数据类型的响应式, 不进行对象的响应式解决。
什么时候应用?
- 如果有一个对象数据,构造比拟深, 但变动时只是外层属性变动 ===> shallowReactive。
- 如果有一个对象数据,后续性能不会批改该对象中的属性,而是生新的对象来替换 ===> shallowRef。
2.readonly 与 shallowReadonly
- readonly: 让一个响应式数据变为只读的(深只读)。
- shallowReadonly:让一个响应式数据变为只读的(浅只读)。
- 利用场景: 不心愿数据被批改时。
3.toRaw 与 markRaw
toRaw:
- 作用:将一个由
reactive
生成的响应式对象转为一般对象。 - 应用场景:用于读取响应式对象对应的一般对象,对这个一般对象的所有操作,不会引起页面更新。
- 作用:将一个由
markRaw:
- 作用:标记一个对象,使其永远不会再成为响应式对象。
利用场景:
- 有些值不应被设置为响应式的,例如简单的第三方类库等。
- 当渲染具备不可变数据源的大列表时,跳过响应式转换能够进步性能。
4.customRef
- 作用:创立一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式管制。
- 实现防抖成果:
<template> <input type="text" v-model="keyword"> <h3>{{keyword}}</h3></template><script> import {ref,customRef} from 'vue' export default { name:'Demo', setup(){ // let keyword = ref('hello') //应用Vue筹备好的内置ref //自定义一个myRef function myRef(value,delay){ let timer //通过customRef去实现自定义 return customRef((track,trigger)=>{ return{ get(){ track() //通知Vue这个value值是须要被“追踪”的 return value }, set(newValue){ clearTimeout(timer) timer = setTimeout(()=>{ value = newValue trigger() //通知Vue去更新界面 },delay) } } }) } let keyword = myRef('hello',500) //应用程序员自定义的ref return { keyword } } }</script>
5.provide 与 inject
- 作用:实现祖与后辈组件间通信
- 套路:父组件有一个
provide
选项来提供数据,后辈组件有一个inject
选项来开始应用这些数据 具体写法:
- 祖组件中:
setup(){ ...... let car = reactive({name:'飞驰',price:'40万'}) provide('car',car) ......}
2. 后辈组件中:
setup(props,context){ ...... const car = inject('car') return {car} ......}
6.响应式数据的判断
- isRef: 查看一个值是否为一个 ref 对象
- isReactive: 查看一个对象是否是由
reactive
创立的响应式代理 - isReadonly: 查看一个对象是否是由
readonly
创立的只读代理 - isProxy: 查看一个对象是否是由
reactive
或者readonly
办法创立的代理
四、Composition API 的劣势
1.Options API 存在的问题
应用传统OptionsAPI中,新增或者批改一个需要,就须要别离在data,methods,computed里批改 。
2.Composition API 的劣势
咱们能够更加优雅的组织咱们的代码,函数。让相干性能的代码更加有序的组织在一起。
五、新的组件、
1.Fragment
- 在Vue2中: 组件必须有一个根标签
- 在Vue3中: 组件能够没有根标签, 外部会将多个标签蕴含在一个Fragment虚构元素中
- 益处: 缩小标签层级, 减小内存占用
2.Teleport
- 什么是Teleport?——
Teleport
是一种可能将咱们的组件html构造挪动到指定地位的技术。
<teleport to="挪动地位"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <button @click="isShow = false">敞开弹窗</button> </div> </div></teleport>
3.Suspense
- 期待异步组件时渲染一些额定内容,让利用有更好的用户体验
应用步骤:
- 异步引入组件
import {defineAsyncComponent} from 'vue'const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
- 应用
Suspense
包裹组件,并配置好default
与fallback
<template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template v-slot:default> <Child/> </template> <template v-slot:fallback> <h3>加载中.....</h3> </template> </Suspense> </div></template>
六、其余
1.全局API的转移
Vue 2.x 有许多全局 API 和配置。
- 例如:注册全局组件、注册全局指令等。
//注册全局组件Vue.component('MyButton', { data: () => ({ count: 0 }), template: '<button @click="count++">Clicked {{ count }} times.</button>'})//注册全局指令Vue.directive('focus', { inserted: el => el.focus()}
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.其余扭转
- data选项应始终被申明为一个函数。
适度类名的更改:
- Vue2.x写法
.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;}
- 移除keyCode作为 v-on 的修饰符,同时也不再反对
config.keyCodes
移除
v-on.native
修饰符- 父组件中绑定事件
<my-component v-on:close="handleComponentEvent" v-on:click="handleNativeClickEvent"/>
- 子组件中申明自定义事件
<script> export default { emits: ['close'] }</script>
- 移除过滤器(filter)
过滤器尽管这看起来很不便,但它须要一个自定义语法,突破大括号内表达式是 “只是 JavaScript” 的假如,这不仅有学习老本,而且有实现老本!倡议用办法调用或计算属性去替换过滤器。
- .......