1.vue3带来了什么
-
性能的提升:
打包大小减少,内存减少,初次渲染和更新渲染快 -
源码的升级
使用proxy代替defineProperty实现响应式
重写虚拟dom的实现和tree-shaking -
拥抱TypeScript
更好的支持ts -
新的特性
composition API(组合API)1.setup配置 2.ref与reactive 3.watch与watchEffect 4.provide与inject
新的内置组件
1.Fragment 2.Teleport 3.Suspense
其他改变
1.新的生命周期钩子 2.data选项应始终被声明为一个函数 3.移除keyCode支持作为v-on的修饰符
2.创建Vue3.0工程
1.使用vue-cli创建
2.使用vite创建
## 使用vue-cli创建
//查看版本 确保@vue/cli的版本在4.5.0以上
1.vue --version
//安装或者升级你的vue/cli
2.npm install -g @vue/cli
//创建
3.vue create vue_test
//启动
4.cd vue_test npm run serve
## 使用vite创建(新一代前端构建工具)
vite的优点
1.开发环境中,无需打包操作,可快速的冷启动
2.轻量快速的热重载
3.真正的按需编译,不再等待整个应用编译完成
vite创建项目步骤
1.npm init vite-app <project-name>
2.cd <project-name>
3.npm install
4.npm run dev
3.常见composition API(组合API)
3.1 拉开序幕的setUp
- 理解:vue3中一个新的配置项,值为一个函数
- setup是所有Composition(组合API)的基础
- 组件中所用到的:数据、方法,计算属性、监听器、生命周期都需要配置在setup中
- setup函数的两种返回值
1.若返回一个对象,则对象中的属性方法,在模版中都可以使用
2.若返回一个渲染函数,则可以自定义渲染内容 - 注意点
1.尽量不要与vue2混用
vue2中可以访问到3种的方法、属性
vue3中不能访问到2的方法、属性
如果有重名,vue3优先
2.setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模版看不到return对象中的属性
<template>
<h1>{{name}}</h1>
<div @click="sayHello">说话</div>
</template>
<script>
export default {
name: 'App',
//此处只测试setUp,暂时不考虑响应项
setup(){
//数据
let name = '张三'
let age = 18
//方法
function sayHello(){
alert(`我叫${name},我${age}岁了,你好啊`)
}
//返回对象(常用)
return {
name,
age,
sayHello
}
//返回一个函数(渲染函数)
return ()=>{return h('h1','乐一吖')}
},
}
</script>
3.2 ref函数
- 作用:定义一个响应式的数据
- 语法:let xxx = ref(‘初始值’)
创建一个包含响应式数据的引用对象
更改数据的值 xxx.value
模版中读取数据 直接 xxx - 备注:
ref接收的数据可以是数字、字符串也可以是对象
基本数据类型的响应:利用Object.defineProperty的get与set方法完成
对象数据类型的数据:内部求助Vue3的一个新函数——reactive函数,生成一个proxy代理对象
<template>
<!-- <img alt="Vue logo" src="./assets/logo.png"> -->
<h1>{{name}}</h1>
<h1>{{age}}</h1>
<h1>{{obj.type}}</h1>
<h1>{{obj.salary}}</h1>
<div @click="changeInfo">修改一个人的信息</div>
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
setup(){
//数据
let name = ref('张三')
let age = ref(18)
let obj = ref({
type:'前端工程师',
salary:'12k'
})
function changeInfo(){
name.value = '里斯'
age.value = 78
obj.value.type = 'UI设计师'
obj.value.salary = '15K'
}
return {
name,
age,
obj,
changeInfo
}
},
}
</script>
3.3 reactive函数
- 作用:定义一个对象类型的响应式数据(基本数据类型不要用它,用ref函数)
- 语法:let 代理对象 = reactive(源对象)接收一个对象或数组,返回一个代理对象
- reactive定义的响应式数据是深层次的
- 内部基于ES6的Proxy实现,通过代理队形操作源对象内部数据进行操作
<template>
<!-- <img alt="Vue logo" src="./assets/logo.png"> -->
<h1>{{name}}</h1>
<h1>{{age}}</h1>
<h1>{{obj.type}}</h1>
<h1>{{obj.salary}}</h1>
<h1>{{obj.a.b.c}}</h1>
<h1>{{hobby}}</h1>
<div @click="changeInfo">修改一个人的信息</div>
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: 'App',
setup(){
//数据
let name = ref('张三')
let age = ref(18)
let obj = reactive ({
type:'前端工程师',
salary:'12k',
a:{
b:{
c:666
}
}
})
let hobby = reactive(['抽烟','喝酒','玩游戏'])
function changeInfo(){
name.value = '里斯'
age.value = 78
obj.type = 'UI设计师'
obj.salary = '15K'
obj.a.b.c = 999
hobby[0] = '学习'
}
//更好的简写
let person = reactive({
name:'张三',
age:18,
job:{
type:'前端工程师',
salary:'12k',
a:{
b:{
c:666
}
}
}
})
return {
name,
age,
obj,
hobby,
person,
changeInfo
}
},
}
</script>
4.vue3.0中的响应式原理
1. vue2.x的响应式
-
实现原理
对象类型:通过Object.definProperty对属性的读取、修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹) -
存在问题
新增属性、删除属性,界面不会更新
直接通过下标修改数组,界面不会自动更新
2.vue3.0的响应式
- 实现原理
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等
通过Reflect(反射):对被代理的对象的属性进行操作
<template>
</template>
<script>
export default {
setup(){
//源数据
let person = {
name:'张三',
age:18
}
const p = new Proxy(person,{
// vue3.0的底层并没有直接去用这个
get(target,propName){
console.log(target,'源数据');
console.log(propName,'属性名');
console.log('有人读取了p上面的某个属性');
return target[propName]
},
set(target,propName,value){
console.log('有人修改或增加了p上面的某个属性');
target[propName] = value
},
deleteProperty(target,propName){
console.log('有人删除了p上面的某个属性');
return delete target[propName]
}
})
// vue3.0底层逻辑 es6新增的一个属性 reflect
const p1 = new Proxy(person,{
// vue3.0的底层并没有直接去用这个
get(target,propName){
console.log(target,'源数据');
console.log(propName,'属性名');
console.log('有人读取了p上面的某个属性');
return Reflect.get(target,propName)
},
set(target,propName,value){
console.log('有人修改或增加了p上面的某个属性');
Reflect.set(target,propName,value)
},
deleteProperty(target,propName){
console.log('有人删除了p上面的某个属性');
return Reflect.deleteProperty(target,propName)
}
})
//通过reflect可以得到一个返回值,更好的去处理发生异常的情况 不至于代码报错 后面的代码就都不能执行了
const x1 = Reflect.defineProperty(obj,'c',{
get(){
return 3
}
})
const x2 = Reflect.defineProperty(obj,'c',{
get(){
return 4
}
})
return{
p
}
}
}
</script>
5.reactive与ref的对比
- 从定义数据出发、
ref用来定义:基本数据类型
reactive用来定义:对象(或数组)
备注:ref也可以用来定义对象或数组,它内部自动通过reactive转为代理对象 - 从原理角度出发
ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)
reactive通过使用Proxy来实现响应式,并通过reflect操作源对象内部的数据 - 从使用角度出发
ref定义的数据:操作数据需要.value,读取的时候不需要value
reactive定义的数据:不需要.value
6. setup的两个注意点
-
setup执行的时机
在beforeCreate之前执行一次,this是undefined -
setup的参数
1.props:值为对象,包含:组件外部传递过来,且组件内部声明接受了的属性
2.context:上下文对象
attrs
slots
emit