setup 方法
Vue3中的setup 中可写data 里面的数据,methods 方法 但需要通过return 将存储的数据和方法return 出去,页面才能进行访问。
export default {
setup(){
let name="张三"
return {
name,
};
}
}
注意点:
setup执行的时机
在beforeCreate之前执行依次,this 是undefined
setup的参数
props 值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
context:上下文对象
attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.
a
t
t
r
s
s
l
o
t
s
收到的插槽内容,相当于
t
h
i
s
.
attrs slots 收到的插槽内容,相当于this.
attrsslots收到的插槽内容,相当于this.slots
emit 分发自定义事件的函数,相当于this.$emit
ref
作用: Vue2 中ref 绑定属性 ,还保持,但Vue3 是方法。 是将普通数据变为响应式数据
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-08 09:31:27
* @LastEditors: 莲白
-->
<template>
<ul>
<li>{{ name }}</li>
<li>{{ age }}</li>
<li><button @click="changInfo">修改人的信息</button></li>
</ul>
</template>
<script>
import {ref} from 'vue' //1.引入ref 方法
export default {
name: "App",
setup() {
let [name, age] = [ref(`张三`),ref(18) ]; //2 套用ref 方法
function changInfo() {
console.log(name, age);
name.value='张氏'
age.value=20
} //3.因为使用ref 方法,会将原本变量变为对象,需要通过 数据.value 进行访问
return {
name,
age,
changInfo,
};
},
};
</script>
reactive 函数
import {reactive} from 'vue' //1.引入ref 方法
let [job,] = [reactive({
type:'前端',
salary: '30k',
}), ];//2 套用reactive 方法
job.salary='20k' //修改
总结:
ref 函数 作用:定义一个响应式的数据
语法 const xxx=ref(initValue)
1.创建一个包含响应式数据的引用对象(reference 对象)
2.js 中操作数据 : xxx.value
3.模板中读取数据,不需要value ,直接:
备注:
1.接受的数据可以是:基本类型,也可以是对象类型
2.基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的
3.对象类型的数据:内部 求助了Vue3.0中的一个新函数----reactive函数
reactive 函数
作用定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
语法:const 代理对象=reactive(源对象)接收一个对象(或数组),返回一个代理对象(proxy对象简称proxy对象)
reactive定义响应式数据是深层次的
内部给予ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作。
计算属性computed 与Vue2 中的类似
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-08 11:26:42
* @LastEditors: 莲白
-->
<template>
<ul>
<li>
姓:<input type="text" v-model="person.firstName">
<br>
名:<input type="text" v-model="person.lastName">
<br>
<span>{{person.fullName}}</span>
</li>
</ul>
</template>
<script>
import { reactive,computed} from 'vue' //1.引入ref 方法
export default {
name: "App",
setup() {
let person=reactive({
firstName:'张',
lastName:'三'
})
//计算属性-完整写法 (考虑读和写)
person.fullName=computed({
get(){
return person.firstName+'-'+person.lastName
},
set(value){
const nameArr=value.split('-')
person.firstName=nameArr[0];
person.firstName=nameArr[1];
}
})
return {
person,
};
},
};
</script>
侦听器watch(与Vue2.x中的watch配置功能一致)
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-08 16:54:21
* @LastEditors: 莲白
-->
<template>
<h2> 当前求和为:{{sum}}</h2>
<button @click="sum++"> 点击加1</button>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'"> 点击加1</button>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="person.name+='@'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
</template>
<script>
import { ref, watch,reactive} from 'vue' //1.引入ref 方法
export default {
name: "App",
setup() {
let sum =ref(0)
let msg =ref('你好')
let person =reactive({
name:`莲白`,
age:18,
job:{
js:{}
}
})
// 情况1监视
// watch(sum,(newValue,oldValue)=>{
// console.log(newValue,oldValue);
// })
//情况2监视多个响应式数据
// watch([sum ,msg],(newValue,oldValue)=>{
// console.log(`sum ,msg`,newValue,oldValue);
// },{immediate:true,})
//监视reactive 所定义的一个响应式数据,注意:
/**
* 此处无法正确的获取oldValue
* 2.注意,强制开启了深度监视(deep配置无效)
*/
watch(person,(newValue,oldValue)=>{
console.log(`person`,newValue,oldValue);
},{deep:false}) //此处配置无效
/**
* 监视reactive 所定义的一个响应式数据,某个属性
*/
// watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
// console.log(`person`,newValue,oldValue);
// },) //此处配置无效
/**
* 特殊监视
*/
watch([()=>person.job,],(newValue,oldValue)=>{
console.log(`person`,newValue,oldValue);
},{deep:true}) //此处由于监视的是reactive定义的对象中的某个属性,所以deep 属性仍然有效
return {
sum,
msg,
person
};
},
};
</script>
两个小坑:
1,监视reactive定义的响应式数据时,pldValue无法正确获取,强制开启了深度监视(deep配置失效).
2.监视reactive定义的响应式数据中某个属性时,deep配置任然有效
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-08 17:09:45
* @LastEditors: 莲白
-->
<template>
<h2> 当前求和为:{{sum}}</h2>
<button @click="sum++"> 点击加1</button>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'"> 点击加1</button>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="person.name+='@'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
</template>
<script>
import { ref, watch} from 'vue' //1.引入ref 方法
export default {
name: "App",
setup() {
let sum =ref(0)
let msg =ref('你好')
let person =ref({
name:`莲白`,
age:18,
job:{
js:{}
}
})
console.log(`sum`,sum );
console.log(`msg`,msg );
console.log(`person`,person );
watch(sum,(newValue,oldValue)=>{
console.log(`newValue`, newValue,`oldValue`,oldValue);
},{immediate:true})
/**
* ref 监视对象
*/
//方法1
// watch(person.value,(newValue,oldValue)=>{
// console.log(`newValue1`, newValue,`oldValue1`,oldValue);
// },{immediate:true})
//方法2
watch(person,(newValue,oldValue)=>{
console.log(`newValue2`, newValue,`oldValue2`,oldValue);
},{immediate:true},{deep:true})
return {
sum,
msg,
person
};
},
};
</script>
watchEffect 函数
watch的套路是:既要指明监视属性,也要指明监视的回调
watchEffect的套路是:不用监视那个属性,监视的回调中用到那个属性,就监视那个属性
watchEffect 有点像computed:
但computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值
而watchEffect 更注重的是过程(回调函数的函数题),所以不用写返回值
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-08 17:28:56
* @LastEditors: 莲白
-->
<template>
<h2> 当前求和为:{{sum}}</h2>
<button @click="sum++"> 点击加1</button>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'"> 点击加1</button>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="person.name+='@'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
</template>
<script>
import { ref, reactive,watchEffect} from 'vue' //1.引入ref 方法
export default {
name: "App",
setup() {
let sum =ref(0)
let msg =ref('你好')
let person =reactive({
name:`莲白`,
age:18,
job:{
js:{}
}
})
console.log(`sum`,sum );
console.log(`msg`,msg );
console.log(`person`,person );
// watch(sum,(newValue,oldValue)=>{
// console.log(`sum`,newValue,oldValue );
// },{immediate:true,deep:true})
watchEffect(()=>{
const x1=sum.value
const x2=person.name
const x3=person.age
console.log(`watchEffect所执行的回调`,x1,x2,x3);
})
return {
sum,
msg,
person
};
},
};
</script>
生命周期
自定义hook 函数
本质是一个函数,把Setup 函数中使用的Composition API 进行封装
类似与Vue2.x 中的minxin
自定义hook的优势,复用代码,让setup 中的逻辑更清楚易懂
步骤1: 创建usePoint.js 文件 代码如下:
/*
* @Description:
* @Author: 莲白
* @Date: 2022-10-08 18:02:43
* @LastEditTime: 2022-10-08 18:06:30
* @LastEditors: 莲白
*/
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.pageX;
console.log(event.pageX, event.pageY);
}
//实现鼠标打点相关的钩子周期
onMounted(() => {
window.addEventListener("click",savePoint);
});
onBeforeUnmount(()=>{
window.removeEventListener("click",savePoint)
})
return point
}
步骤二: 引入功能封装文件
import usePoint from './hooks//usePoint'
步骤三: 声明变量接收 抛出的函数 在setup 定义
setup() {
let sum = ref(0);
let point=usePoint()
return {
sum,
point
};
},
toRef
作用:创建一个ref 对象,其value 值指向灵台一个对象中的某个属性
语法:const name=toRef(person,‘name’)
应用:要将响应式对象中的某个属性单独提供给外部使用时.
扩展:toRefs 与toRef功能一致,但可以批量创建多个ref对象语法 toRefs(person)
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-09 09:42:02
* @LastEditors: 莲白
-->
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{job.j1.salary }} K</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age += 1">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import { reactive,toRef, toRefs } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: `莲白`,
age: 20,
job: {
j1: {
salary: 20,
},
},
});
console.log(`toRef`, toRef(person,'name'));
return {
person,
// name: toRef(person,'name'),
// age:toRef(person,'age'),
// salary:toRef(person.job.j1,'salary'),
...toRefs(person)
};
},
};
</script>
其他Composition API
shallowReactive与shallowRef
shallowReactive :只处理对象最外层属性的响应式(浅响应式)
shallowRef: 只处理基本数据类型的响应式,不进行对象的响应式处理
什么时候使用
如果有一个对象数据,结构比较深,但变化时只是外层属性变化===》shallowReactive
如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换===>shallowRef
ref 和shallowRef的区别:
ref 处理对象形式的数据
shallowRef 不去处理对象形式的数据
<!--
* @Description:
* @Author: 莲白
* @Date: 2022-09-25 11:27:41
* @LastEditTime: 2022-10-09 10:10:00
* @LastEditors: 莲白
-->
<template>
<h2>x的值:{{x.x}}</h2>
<button @click="x.x ++"> 增加x的值</button>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }} K</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age += 1">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import { toRef, toRefs, shallowReactive, ref, } from "vue";
export default {
name: "App",
setup() {
let person = shallowReactive({
name: `莲白`,
age: 20,
job: {
j1: {
salary: 20,
},
},
});
//只考虑第一层数据的响应式
let x = ref({
y:0,
x:0
})
console.log(`toRef`, toRef(person, "name"));
return {
person,
...toRefs(person),
x,
};
},
};
</script>
readonly 与shallowReadonly
readonly:让一个响应式数据变为只读的(深只读)
shallowReadonly :让一个响应式数据变为只读的(浅只读)
应该场景:不希望数据被修改时
toRaw与markRaw
toRaw:作用:将一个由reactive生成的响应式对象转化为普通对象
使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新.
marRaw:
作用:标记一个对象, 使其永远不会再称为响应式对象
应用场景:
1.有些值不应该被设置为响应式的,例如复杂的第三方类库等
2.当渲染具有不可变数据元 的大列表时,跳过响应式转换可以提高性能。