setup
组件中所用到的数据、方法等都需要在setup中使用
setup函数有两种返回值
1.返回一个对象,则对象里面的方法、属性、数据都能在模板中直接使用
<template>
<h1>一个人的消息</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{age }}</h2>
<button @click="sayHello">说话</button>
</template>
<script>
import { h } from 'vue';
export default {
name: 'App',
setup(){
//数据
let name='张三'
let age=30
//方法
function sayHello(){
alert(`我是${name},我${age}岁了,你好啊`)
}
//返回一个对象
return{
name,
age,
sayHello
}
}
}
</script>
2.返回一个渲染函数,可以自定义渲染内容
<template>
<h1>一个人的消息</h1>
</template>
<script>
import { h } from 'vue';
export default {
name: 'App',
setup(){
return ()=>{
return h ('h1','尚硅谷')
}
}
}
</script>
但是我们需要注意
vue3中不能使用vue2中定义的属性,但是vue2中能使用
<template>
<h1>一个人的消息</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{age }}</h2>
<h2>a:{{a }}</h2>
<button @click="sayHello">说话1</button>
<button @click="sayWelcome">说话2</button>
<button @click="test1">测试在vue2中调用vue3的数据</button>
<button @click="test2">测试在vue3中调用vue2的数据</button>
</template>
<script>
import { h } from 'vue';
export default {
name: 'App',
data(){
return{
sex:'男',
a:200
}
},
methods:{
sayWelcome(){
alert('欢迎来到vue3')
},
test1(){
console.log(this.age)
console.log(this.name)
console.log(this.sayHello)
}
},
setup(){
//数据
let name='张三'
let age=30
let a=300
//方法
function sayHello(){
alert(`我是${name},我${age}岁了,你好啊`)
}
function test2(){
console.log(this.sex)
console.log(this.sayHello)
}
//返回一个对象
return{
name,
age,
sayHello,
test2
}
}
}
</script>
控制台显示为
而且如果vue3和vue2数据相同时,会优先使用vue3的数据
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ref
如果我们需要实现数据的响应式,就需要在数据创建的时候,使用ref函数,在修改时,使用ref.value,在组件中使用的时候,vue3会自动的调用·.value
<template>
<h1>一个人的消息</h1>
<h2>姓名:{{ name }}</h2> <!-- vue3会自动的调用.value -->
<h2>年龄:{{age }}</h2>
<button @click="changeInfo">改变人的信息</button>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'App',
setup(){
//数据
let name=ref('张三')
let age=ref(30)
function changeInfo(){
name.value='李四',
age.value='48'
}
//返回一个对象
return{
name,
age,
changeInfo
}
}
}
</script>
<style>
</style>
ref在处理基本的数据类型的时候,作为一个refimpl对象,使用的就是set与get
ref在处理对象类型数据的时候,将其作为一个proxy对象来使用的,但是reacitive中里面封装了具体的proxy操作的内容
如果ref中使用了对象类型,那就是ref求助了reactive,将其变为proxy类型
<template>
<h1>一个人的消息</h1>
<h2>工作种类:{{job.type }}</h2>
<h2>工作薪水:{{job.salary }}</h2>
<button @click="changeInfo">改变人的信息</button>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'App',
setup(){
//数据
let job=ref({
type:'前端',
salary:'30k'
})
function changeInfo(){
job.value.type='后端',
job.value.salary='60K'
console.log(job.value)
}
//返回一个对象
return{
changeInfo,
job
}
}
}
</script>
<style>
</style>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
reactive
定义一个对象类型的响应式数据,基本类型使用ref
<template>
<h1>一个人的消息</h1>
<h2>姓名:{{ name }}</h2> <!-- vue3会自动的调用.value -->
<h2>年龄:{{age }}</h2>
<h2>工作种类:{{job.type }}</h2>
<h2>工作薪水:{{job.salary }}</h2>
<h2>测试的对象:{{job.a.b.c }}</h2>
<button @click="changeInfo">改变人的信息</button>
</template>
<script>
import { ref,reactive } from 'vue';
export default {
name: 'App',
setup(){
//数据
let name=ref('张三')
let age=ref(30)
let job=reactive({
type:'前端',
salary:'30k',
a:{
b:{
c:300
}
}
})
let hobby=reactive(['抽烟','喝酒','烫头'])
function changeInfo(){
name.value='李四',
age.value='48',
job.type='后端',
job.salary='60K'
job.a.b.c=999
hobby[0]='学习'
console.log(`output-job`,job)
console.log(hobby[0])
}
//返回一个对象
return{
name,
age,
changeInfo,
job
}
}
}
</script>
<style>
</style>
我们使用reactive去标识引用数据类型的时候,可以省去.value
reactive与ref对比
1.ref用来定义基本数据类型,reactive用来定义对象(数组)类型数据
ref能定义对象类型,但是会调用reactive将其转化为带来对象
2.ref使用Object.defineProperty( )的get与set来实现响应式数据
reactive通过proxy来实现响应式,使用Reflect来操作源对象数据
ref操作数据需要使用.value,而reactive不需要
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
computed
存在两种书写形式
<template>
<h1>一个人的消息</h1>
姓:<input type="text" v-model="person.firstName">
<br>
名:<input type="text" v-model="person.lastName">
<br>
<span>全名:{{ person.fullName }}</span>
<br>
全名:<input type="text" v-model="person.fullName">
</template>
<script>
import { reactive, computed } from 'vue';
export default {
name: 'Demo',
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.lastName = nameArr[1];
}
});
// 返回一个对象,包括person
return {
person,
};
}
}
</script>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Watch
vue3中可以调用多次watch函数,如我们需要监视多个值的时候
watch检查ref
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<br>
<h2>当前的消息为:{{ msg }}</h2>
<button @click="msg+='!'">修改信息</button>
</template>
<script>
import { ref, watch } from 'vue';
export default {
name: 'Demo',
setup() {
let sum = ref(0);
let msg=ref('你好啊')
//情况1,监视ref定义的一个响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum的值发生了变化',newValue,oldValue)
})
watch(msg,(newValue,oldValue)=>{
console.log('sum的值发生了变化',newValue,oldValue)
})
return {
sum,
msg
};
}
}
</script>
<style>
</style>
我们可以将其合并到东一个数组中,还能添加其他配置属性
//情况2,监视ref定义的多个响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum的值发生了变化',newValue,oldValue)
})
//情况2,监视ref定义的多个响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum的值发生了变化',newValue,oldValue)
},{immediate:true})
监视reactive
1.无法获取之前的oldvalue
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<br />
<h2>当前的消息为:{{ msg }}</h2>
<button @click="msg += '!'">修改信息</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';
export default {
name: 'Demo',
setup() {
let sum = ref(0);
let msg=ref('你好啊')
let person=reactive({
name:'张三',
age:18,
})
//监视reactive数据,无法获得正确的oldValue
watch(person,(newValue,oldValue)=>{
console.log('person发生了变化',newValue,oldValue)
})
return{
sum,
msg,
person
}
}
}
</script>
2.默认开启了深度监视
3.可以监视某一个属性的变化或是某些数据,此时的oldValue奏效
//监视reactive数据,无法获得正确的oldValue
watch(()=>person.age,(newValue,oldValue)=>{
console.log('person.age发生了变化',newValue,oldValue)
},{deep:false})
//监视reactive数据,无法获得正确的oldValue
watch([()=>person.age,()=>person.name],(newValue,oldValue)=>{
console.log('person.age发生了变化',newValue,oldValue)
},{deep:false})
4.如果监视一个不是一层的层级,需要开启deep监视
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<br />
<h2>当前的消息为:{{ msg }}</h2>
<button @click="msg += '!'">修改信息</button>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>薪资:{{ person.job.j1.salary+'K' }}</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">修改年龄</button>
<button @click="person.job.j1.salary++">涨工资</button>
</template>
<script>
import { ref, watch,reactive } from 'vue';
export default {
name: 'Demo',
setup() {
let sum = ref(0);
let msg=ref('你好啊')
let person=reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
//监视reactive数据,无法获得正确的oldValue
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person.job发生了变化',newValue,oldValue)
},{deep:true})
return{
sum,
msg,
person
}
}
}
</script>
<style>
</style>
监视是否需要使用.value
如果我们监测一个是ref类型的对象,watch监测的是ref这个对象本身,因为ref中包装了一个值,需要使用.value才能防止这个对象的改变
添加了.value之后,person的值发生了变化,watch才会生效
当我们使用{deep:true}开启深度监视之后,也能实现ref对对象类型的监视
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
WatchEffect
watch用于观察特定的数据源、并且在发生变化是执行回调函数,需要指定监测源,可以指定监测选项(deep等),可以访问新旧值
watchEffect会自动追踪响应式数据,回调中用到那个属性就监测那个属性,类似于无返回值的cpmputed
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<br />
<h2>当前的消息为:{{ msg }}</h2>
<button @click="msg += '!'">修改信息</button>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>薪资:{{ person.job.j1.salary+'K' }}</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">修改年龄</button>
<button @click="person.job.j1.salary++">涨工资</button>
</template>
<script>
import { ref, watch,reactive,watchEffect } from 'vue';
export default {
name: 'Demo',
setup() {
let sum = ref(0);
let msg=ref('你好啊')
let person=reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
watchEffect(()=>{
const x1=msg.value;
console.log('watchEffect执行了');
})
return{
sum,
msg,
person
}
}
}
</script>
<style>
</style>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
toRef与toRefs
创建一个ref对象,改变指向
如果不适用ref,这里外部的name就需要写成person.name,而是用了toRef之后,就能简写
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{age }}</h2>
<h2>薪资:{{ salary + "K" }}</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="salary++">涨工资</button>
</template>
<script>
import {ref, reactive, toRef } from "vue";
export default {
name: "Demo",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
return {
name:toRef(person,'name'),
age:toRef(person,'age'),
salary:toRef(person.job.j1,'salary')
};
},
};
</script>
<style>
</style>
toRefs能够拆分最外面的那一层,但是多层的还是需要我们去手动指向
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{age }}</h2>
<h2>薪资:{{ job.j1.salary+ "K" }}</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.j1.salary++">涨工资</button>
</template>
<script>
import {ref, reactive, toRef,toRefs } from "vue";
export default {
name: "Demo",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
return {
// name:toRef(person,'name'),
// age:toRef(person,'age'),
// salary:toRef(person.job.j1,'salary')
...toRefs(person)
};
},
};
</script>
<style>
</style>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
shallReactive与shallRef
shallReactive只处理对象最外层的响应式,也就是多层级的就不会再由响应式
shallRef只处理基本数据类型的响应式,不会对对象类型进行处理
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{age }}</h2>
<h2>薪资:{{ job.j1.salary+ "K" }}</h2>
<h4>当前的x.y是:{{ x.y }}</h4>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.j1.salary++">涨工资</button>
<button @click="x.y++">x修改</button>
<br>
</template>
<script>
import {ref, reactive, toRef,toRefs,shallowReactive,shallowRef } from "vue";
export default {
name: "Demo",
setup() {
let person = shallowReactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
let x=shallowRef({
y:0
})
return {
x,
...toRefs(person)
};
},
};
</script>
<style>
</style>
此时这里对薪资与x.y的修改无效
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
readonly与shallreadonly
使用readonly函数修饰之后的对象,是不能进行数值的修改的,数据都没有资格去修改
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
//此时的person的数值都不能修改
person=readonly(person)
如这里之后的person就不再是能响应数据的了
使用shallreadonly修饰之后,第一层的数据是不能再修改的,但是其他更为深层的数据可以进行修改
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
//此时的person的数值都不能修改
person=shallowReadonly(person)
这里的person的name,age不能进行修改了,但是j1里面的数据是能修改的
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
toRaw与markRaw
toRaw是将响应式对象转化为普通对象,reactive与ref都是一致的
let sum=ref(0)
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
function showRawPerson(){
const p=toRaw(person)
p.age++
console.log(p);
const pp=toRaw(sum)
console.log(pp);
}
markRaw是标记一个对象,使其永远不会成为响应式对象
也就是值会改变,但是不会再页面不会更新
function addCar(){
let car={name:'奔驰',price:'40'}
person.car=markRaw(car)
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
customRef
创建一个自定义的ref,并对其依赖项解析跟踪
需要使用customRef来创建
<template>
<input v-model="keyword" type="text">
<h3>{{ keyword }}</h3>
</template>
<script>
import { ref,customRef } from 'vue';
export default {
name: 'App',
setup(){
//自定义一个Ref
function myRef(value){
return customRef((track,trigger)=>{
let timer
return {
get(){
console.log('有人从myRef中读取数据了',value);
track()//通知Vue追踪vue的变化
return value
},
set(newValue){
console.log('有人修改了myRef中数据',newValue);
clearTimeout(timer)
timer= setTimeout(()=>{
value=newValue
trigger()//通知vue重新解析模板
},500)
}
}
})
}
// let keyword=ref('hello')//使用vue提供的ref
let keyword=myRef('hello')//使用vue提供的ref
return {
keyword
}
}
}
</script>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
provide与inject
实现祖与后代组件之间的通信
如祖组件App.vue
<template>
<div class="app">
<h3>我是App组件(祖),{{ name }}---{{ price }}</h3>
<Child></Child>
</div>
</template>
<script>
import { provide, reactive,toRefs } from 'vue';
import Child from './components/Child.vue';
export default {
name:'name',
components:{Child},
setup(){
let car=reactive({
name:'奔驰',
price:'4W'
})
//给自己的后代组件传递数据
provide('car',car)
return{
...toRefs(car)
}
}
}
</script>
<style>
.app{
background-color: gray;
padding: 10ps;
}
</style>
子组件Child.vue
<template>
<div class="child">
<h3>我是Child组件(子){{ car.name }}---{{ car.price }}</h3>
<Son></Son>
</div>
</template>
<script>
import { inject } from 'vue';
import Son from './Son.vue';
export default {
name:'Child',
setup(){
let car= inject('car')
return{car}
},
components:{Son}
}
</script>
<style>
.child{
background-color: skyblue;
padding: 10ps;
}
</style>
孙组件 Son.vue
<template>
<div class="son">
<h3>我是son组件(孙)</h3>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
name:'Son',
setup(){
let car= inject('car')
console.log('为Son组件生成的car',car);
}
}
</script>
<style>
.son{
background-color: orange;
padding: 10ps;
}
</style>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
响应式数据的判断
isRef:是否为一个Ref对象
isReactivie:是否为一个Reative响应式代理
isReadonly:是否为readonly代理
isProxy:是否为reactive或是readonly方法创建的代理
<template>
<div class="app">
<h3>我是App组件(祖)</h3>
</div>
</template>
<script>
import { isProxy, isReactive, isReadonly, isRef, reactive, readonly, ref, toRefs } from 'vue';
export default {
name:'name',
setup(){
let car=reactive({name:'奔驰',price:'40w'})
let sum=ref(0)
let car2=readonly(car)
console.log(isRef(car));//false
console.log(isReactive(car));//true
console.log(isReadonly(car2));//true
console.log(isProxy(car));//true
console.log(isProxy(car2));//true
return{
}
}
}
</script>
<style>
.app{
background-color: gray;
padding: 10ps;
}
</style>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Teleport
可以将我们的组件html结构移动到指定位置
<template>
<div>
<button @click="isShow = true">点我弹窗</button>
<Teleport to="body">
<div v-if="isShow" class=mask>
<div class="dialog">
<h3>我是一个弹窗</h3>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<button @click="isShow = false">关闭按钮</button>
</div>
</div>
</Teleport>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Dialog",
setup() {
let isShow = ref(false);
return { isShow };
},
};
</script>
<style>
.dialog {
position: absolute;
text-align: center;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width: 300ps;
height: 300ps;
background-color: green;
}
.mask{
position:absolute;
top: 0;bottom: 0;left:0;right: 0;
background-color: rgb(0,0,0,0.5);
}
</style>
<script setup>的作用
简化组合式API的写法,如不需要进行return
<template>
<h1>{{ msg }}</h1>
<button @click="logMessage">点击</button>
</template>
<script setup>
name: "App";
const msg = "this is message";
function logMessage() {
console.log(msg);
}
</script>
<style>
</style>