创建vue3项目
1.首先node的版本在4.5以上
2.直接用vue-cli来创建vue3项目vue create project_name
正式学习
一、常用Componention(组合式) Api
setup
-
组件中所用到的数据,方法,对象中的属性都写在setup中
-
setup中有两种返回值:对象和函数
-
若返回一个对象,则对象中的属性、方法、在模板中均可以直接使用
-
若返回一个渲染函数:则可以自定义渲染内容。 //返回一个对象 return { name, age, sayHello }
javascript// 返回一个函数 return ()=>{ // h是渲染哈描述,要是用的花,需要引入 return h('h1','张三') } ```
-
setup不是async函数,因为返回值不再是return,而是promise.
-
setup的参数
- props:值为对象,包含组件外部传递过来,且组件内部声明接受了的属性
- context:上下文对象
- attrs:值为对象,包含:组件外部传递过来,但没有props配置中声明的属性
- slots:接受插槽内容,相当于this.$slot.
- emit:分发自定义事件的函数,相当于this.$emit
- 注意点:
- 尽量不要和vue2混用
- vue2配置(data,methods,computed...)中可以访问到setup中的属性,反之不行
- 如果重名,setup优先级高
- setup比beforeCreate先执行,this是undefined.
ref (实现vue3的响应式)
- ref的返回体
2. ref的代码使用
angular2html
<template>
<div>
<h1>一个人的信息</h1>
<h2>名字:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>工作:{{job.type}}</h2>
<h2>薪资:{{job.salary}}</h2>
<button @click="changeInfo">改变信息</button>
</div>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
props: {
},
setup(){
let name = ref('张三')
let age = ref(18)
let job = ref({
type :'前端开发',
salary:'30k'
})
// 返回一个对象
function changeInfo(){
// name.value = '李四'
// age.value = 38
console.log(job.value)
job.value.type = 'java开发'
job.value.salary = '40k'
}
return {
name,
age,
changeInfo,
job
}
}
}
</script>
```
3. ref 可以接受基本类型,对象类型
* 对基数据类型使用数据劫持(object.defineProperty()中的get set )来实现响应式;
* 对于对象类型的数据(复杂数据类型)使用了新的特性------ reactive函数。
4. reactive 函数
* 作用:定义一个**对象类型**的响应式数据(基本类型用ref)
* 代码使用
```vue
let job = reactive({
type :'前端开发',
salary:'30k'
})
console.log(job)
job.type = 'java开发'
job.salary = '40k'
Vue3.0中的响应式原理
- vue2.0的响应式原理
-
实现原理
- 对象类型:通过object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
- 数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更进行了包裹)
javascript// 模拟数据 let person={ name:'张三', age:10 } //模拟vue2中实现响应式 let p = {} Object.defineProperty(p,'name',{ get(){ return person.name }, set(value){ console.log('有人修改了name属性,我去更新') return person.name = value } }) Object.defineProperty(p,'age',{ get(){ return person.age }, set(value){ console.log('有人修改了age属性,我去更新') return person.age = value } })
- 存在的问题:
- 新增属性、删除属性、界面不会更新(使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> s e t 和 set和 </math>set和delete解决)
- 直接通过下标修改数组、界面不会自动更新($set,splice)
- Vue3.0的响应式
- 实现原理:
- 通过proxy(代理):拦截对象中任意属性的变化,包括:属性的读写、属性的添加、属性的删除等
- 通过Reflect(反射): 对代理对象的属性进行操作
- 代码:
angular2html
//模拟vue3中实现响应式
//window.proxy
const p = new Proxy(person,{
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return Reflect.get(target,propName)
},
//修改和追加某个属性时会调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新页面`)
Reflect.set(target,propName,value)
},
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要去更新页面`)
return Reflect.deleteProperty(target,propName)
}
})
vue3.0计算属性与监视
- 与vue2中computed配置功能一致
- 代码
javascript
setup(){
let person = reactive({
firstName : '张',
lastName :'三',
})
//计算属性-简写(没有考虑计算属性被修改的情况)
person.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]
}
})
watch函数
- 与Vue2.x中watch配置功能一致
- 代码
vue
//情况一:监视ref所定义的一个响应式数据
/* watch(sum,(newValue,oldValue)=>{
/ console.log('sum或者msg变了',newValue,oldValue)
},{immediate:true,deep:true})*/
//情况二:监视ref所定义的多个响应式数据
/* watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或者msg变了',newValue,oldValue)
},{immediate:true,deep:true})
*/
//情况三:监视reactive所定义的一个响应式数据,
// 注意:1.此处无法正确的获取oldValue 2.强制开启了深度监视,deep:false无效
// watch(person,(newValue,oldValue)=>{
// console.log('person变化了',newValue,oldValue)
// })
//情况四:监视reactive所定义的响应式数据中的某个属性
watch(()=>person.name,()=>person.age,(newValue,oldValue)=>{
console.log('person的name变化了',newValue,oldValue)
3.注意
- 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失败)
- 监视reactive定义的响应式数据中的某个属性时:deep配置有效
watchEffect函数
- watch:既要指明监视的属性,也要指明监视的回调
- watchEffect:不用指明监视哪个属性,监视的回调用到哪个属性,那就监视哪个属性。
- watchEffect有点像computed
- 代码
vue
watchEffect(()=>{
const x1 = sum.value
const x2 = person.job.j1.salary
console.log('watchEffect所指的回调函数执行了')
})
生命周期
- beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、mounted
- 组合式api所对应的名称:setup(),setup(),onBeforeMount,onMounted,onBeforeUpdate,onUpdate,onBeforeUnmount,onUmounted
- 组合式api的优先级更大一点。
自定义hook函数
- hooks:本质上是一个函数,把setup函数中使用的Composition API进行了封装。
- 类似于vue2中的mixin
- hooks的优势:复用代码,让setup中的逻辑清晰易懂。
toRef(把什么变成ref)
- 作用:创建一个ref对象,其value指向另一个对象中的某个属性
- 语法:const name = toRef(person,'name')
- 应用将响应式对象中的某个属性单独提供给外部使用
- toRefs与toRef功能一致,但可以创建多个ref对象,语法toRefs(person)
二、其它Componention(组合式) Api
shallowReactive 和shallowRef
1.shallowReactive:只能处理对象最外层属性的响应式(浅响应式) 2.shallowRef:只能处理基本数据类型的响应式,不进行对象的响应式处理 3.when to use?
- 如果有一个对象数据,结构比较深,但是变化时只是外部属性变化===》shallowReactive
- 如果有一个对象数据,后续功能不会修改对象中的属性,而是生新的对象来替换===》shallowRef
readonly 和 shallowReadonly
1.readonly:让一个响应式数据变为只读(深只读) 2.shallowReadonly:让一个响应式数据变为只读(浅只读)
toRaw 与 markRow
- toRaw:
- 作用:将一个由reactive生成的响应式对象转为普通对象
- 使用场景:用于读取响应式对象的普通对象,对这个普通对象的所有操作,不会引起页面更新
- markRow:
- 标记一个对象,使其永远不会在成为响应式对象
- 应用场景:
- 有些值不应设置为响应式的,例如复杂的第三方类库等
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以调高性能
customRef
- 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制。
- 实现防抖效果:
vue
function myRef(value,delay){
let timer
// console.log('---myRef---',value)
return customRef((track,trigger)=>{
return{
get(){
console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`)
track()//通知vue追踪value的变化
return value
},
set(newValue){
console.log(`有人把myRef这个容器中数据改为了${newValue}`)
clearTimeout(timer)
setTimeout(()=>{
value = newValue
trigger()//通知vue重新解析模板
},delay)
}
}
})
}
let keyWord = myRef('hello',500)
return {
keyWord
}
provide与inject
- 作用:实现祖孙组件之间的通信
- 代码
vue
//父组件
setup(){
let car = reactive({
name:'奔驰',
price:'40w'
})
provide('car',car)//给自己的后代传入数据
return{
...toRefs(car)
}
}
//子组件
setup(){
let car = inject('car')
return {
car
}
}
}
三、Componention(组合式) Api 的优势
- Option Api存在的问题:使用传统的配置式的api,新增或者修改一个需求,就需要分别在data,methods,computed里修改。
- Composition API优势:更加优雅的组织代码,函数。让相关功能的代码更加有序的组织在一起。