一、ref(基本类型数据,对象类型数据)
1.作用:定义响应式变量
2.语法:let xxx = ref(初始值)
3.返回值:一个RefImpl的实例对象,简称ref对象,ref对象的value属性是响应式的。
4.注意:js中操作数据需要写xxx.vslue,模板上不需要.value,直接使用。let xxx = ref(初始值),xxx不是响应式的,xxx.value是响应式的。
二、reactive(对象类型数据)
1.作用:定义响应式变量
2.语法:let xxx = reactive(源对象)
3.返回值:一个Proxy的实例对象,简称响应式对象。
4.注意:reactive定义的响应式数据是深层次的。
三、ref对比reactive
1.ref 用来定义:基本类型数据,对象类型数据
reactive用来定义:对象类型数据
2.区别
ref创建的变量必须使用.value
reactive重新分配一个新对象,会失去响应式。(可以使用Object.assign去整体替换)
3.使用原则
若需要一个基本类型的响应式数据,必须使用ref。
若需要一个响应式对象,层级不深,ref,reactive都可以。
若需要一个响应式对象,层级较深,推荐使用reactive。
四、toRefs和toRef
1.作用:将一个响应式对象中的每一个属性,转换为ref对象。
2.toRefs与toRef功能一致,但toRefs可以批量转换。
<template><div>{{ name }}{{ age }}</div>
</template>
<script setup>
import { reactive, toRefs, toRef } from 'vue'
let person=reactive({name:'zs',age:18})
//解构赋值后失去响应式
let {name,age} = toRefs(person)
console.log('name,age',name.value,age.value);
let n1 = toRef(person, 'age')
console.log(n1.value);
</script>
五、computed
<template><div>姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br>全名:<span>{{ fullName }}</span>全名:<span>{{ fullName }}</span><br><button @click="changeFullName">修改名字</button></div>
</template><script setup>
import { ref,computed} from 'vue'
let firstName=ref('z')
let lastName=ref('s')
// 定义的fullName是一个计算属性,而且是只读的
// let fullName = computed(()=>{
// console.log('1');
// return firstName.value.slice(0,1).toUpperCase()+firstName.value.slice(1)+lastName.value.slice(0,1).toUpperCase()+lastName.value.slice(1)
// })
// 定义的fullName是一个计算属性,可读可写
let fullName = computed({get(){console.log('1')return firstName.value.slice(0,1).toUpperCase()+firstName.value.slice(1)+'-'+lastName.value.slice(0,1).toUpperCase()+lastName.value.slice(1)},set(val){let [str1,str2]=val.split('-');firstName.value=str1;lastName.value=str2}
})
let changeFullName = ()=>{fullName.value='li-si'
}
</script>
六、watch
1.作用:监视数据的变化
2.只能监视以下四种数据
ref定义的数据,reactive定义的数据,getter函数(一个函数,返回一个值),一个包含上述内容的数组。
a.监听ref定义的基本类型数据,对象类型数据
监视的是对象的地址值,想要监视内部属性的变化,需要deep属性为true
<template><div><p>监视ref定义的基本类型数据{{ sum }} <button @click="sum+=1">+1</button></p><p>监视ref定义的对象类型数据{{ person.name }} {{ person.age }}<button @click="person.name+='~'">changeName</button><button @click="person.age+=1">changeAge</button><button @click="changePerson">changePerson</button></p></div>
</template><script setup>
import { ref,watch} from 'vue'
let sum=ref(0)
const stopWatch= watch(sum,(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);if(newVal>10){stopWatch()}
})
let person=ref({name:'zs',age:18
})
let changePerson = ()=>{person.value={name:'ls',age:90}
}
//监视的是person的地址值,想要监视内部属性的变化,需要deep属性为true
watch(person,(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);
},{deep:true,immediate:true
})
</script>
b.监听reactive定义的对象类型数据
监视的是reactive定义的对象类型数据,默认开启深度监听,该深度监听不能关闭
<template><div><p>监视reactive定义的对象类型数据{{ person.name }} {{ person.age }}<button @click="person.name+='~'">changeName</button><button @click="person.age+=1">changeAge</button><button @click="changePerson">changePerson</button></p></div>
</template><script setup>
import { reactive,watch} from 'vue'
let person=reactive({name:'zs',age:18
})
let changePerson = ()=>{Object.assign( person,{name:'ls',age:90})
}
//监视的是reactive定义的对象类型数据,默认开启深度监听,该深度监听不能关闭
watch(person,(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);
},{// deep:false,immediate:true
})
</script>
c.监视ref或reactive定义的对象类型数据中的某个属性
<template><div><p>监视响应式对象的的某个属性{{person.name}}{{ person.car.c1 }} {{ person.car.c2 }}<button @click="person.name='ls'">changeName</button><button @click="person.car.c1='大宝马'">changeC1</button><button @click="person.car.c2='大奔驰'">changeC2</button><button @click="changeCar">changeCar</button></p></div>
</template>
<script setup>
import { reactive,watch} from 'vue'
let person=reactive({name:'zs',age:18,car:{c1:'宝马',c2:'奔驰'}
})
let changeCar = ()=>{person.car={c1:'爱玛',c2:'绿驹'}
}
//监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
watch(()=>person.name,(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);
})
//监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也可以写成函数式,更推荐写函数式,对象监视的是地址值,对象内部需要手动开启深度监听。
watch(()=>person.car,(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);
},{deep:true
})
</script>
4.监视多个对象
<template><div><p>监视多个数据{{person.name}}{{ person.car.c1 }} {{ person.car.c2 }}<button @click="person.name='ls'">changeName</button><button @click="person.car.c1='大宝马'">changeC1</button><button @click="person.car.c2='大奔驰'">changeC2</button><button @click="changeCar">changeCar</button></p></div>
</template>
<script setup>
import { reactive,watch} from 'vue'
let person=reactive({name:'zs',age:18,car:{c1:'宝马',c2:'奔驰'}
})
let changeCar = ()=>{person.car={c1:'爱玛',c2:'绿驹'}
}
//监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也可以写成函数式,更推荐写函数式,对象监视的是地址值,对象内部需要手动开启深度监听。
watch([()=>person.name,()=>person.car],(newVal,oldVal)=>{console.log('newVal,oldVal', newVal,oldVal);
},{deep:true
})
</script>
七、watchEffect
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更新时重新执行该函数。
watch对比watchEffect
都能监听响应式数据的变化,不同的是监听数据变化的方式不同
watch需要明确指出监视的数据
watchEffect不用明确指出监视的数据,函数中用到哪些属性,就会监听哪些属性。
<template><div><p>watchEffect{{water.temp}}{{ water.height }}<button @click="water.temp+=10">温度+10</button><button @click="water.height+=10">高度+10</button></p></div>
</template>
<script setup>
import { reactive,watchEffect} from 'vue'
let water=reactive({temp:0,height:0,
})
watchEffect(()=>{if(water.temp>=60||water.height>=80)console.log('water.temp,water.height',water.temp,water.height);
})
</script>
八、标签的ref属性
//父组件
<template><HelloWorld ref="helloRef" /><button @click="logHelloRef">test</button>
</template>
<script setup>
import { ref } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
const helloRef = ref(null);
const logHelloRef = () => {console.log('helloRef', helloRef.value);
};
</script> //子组件
<template><div><p>watchEffect{{water.temp}}{{ water.height }}<button @click="water.temp+=10">温度+10</button><button @click="water.height+=10">高度+10</button></p></div>
</template>
<script setup>
import { reactive,watchEffect,defineExpose} from 'vue'
let water=reactive({temp:0,height:0,
})
watchEffect(()=>{if(water.temp>=60||water.height>=80)console.log('water.temp,water.height',water.temp,water.height);
})
defineExpose({water})
</script>
九、props
defineProps可以省略不引入
//父组件
<template><HelloWorld :a="a" :b="list" c=123 />
</template>
<script setup>
import { ref,reactive } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
let a=ref('aaaaaaaaaaa');
let list=reactive([{msg:'aa',num:0},{msg:'bb',num:1},
]);
</script>
//子组件
<template><div>{{ props.a }}{{ props.c }}<ul><li v-for="item in b" :key="item.num">{{ item.num }}{{ item.msg }}</li></ul></div>
</template>
<script setup>
import { defineProps} from 'vue'
const props=defineProps({a:{type:String,required:true,default:'abc'},b:{type:Array,required:true,default:[]},c:{type:Number,required:true,default:0}
})
</script>
十、生命周期
<template><HelloWorld v-if="isShow"/><button @click="isShow=!isShow">flag</button>
</template>
<script setup>
import { ref } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
let isShow = ref(true)
</script><template><div>{{ sum }}<button @click="sum+=1">+1</button></div>
</template>
<script setup>
import {ref, onBeforeMount, onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
let sum = ref(0)
console.log('创建');
onBeforeMount(()=>{console.log('挂载前');
})
onMounted(()=>{console.log('挂载完毕');
})
onBeforeUpdate(()=>{console.log('更新前');
})
onUpdated(()=>{console.log('更新完毕');
})
onBeforeUnmount(()=>{console.log('卸载前');
})
onUnmounted(()=>{console.log('卸载完毕');
})
</script>
十一、hooks
组合式函数约定用驼峰命名法命名,并以“use”作为开头
<template><div>{{ sum }}{{ bigSum }}<button @click="add">+1</button></div>
</template>
<script setup>
import useSum from '../hooks/useSum'
let {sum,add,bigSum}=useSum()
</script>useSum.js
import { onMounted, ref, computed } from 'vue'
export default function() {//数据let sum = ref(0);//方法const add = () => {sum.value += 1};//计算属性let bigSum = computed(() => {return sum.value * 10});//钩子onMounted(() => {add()})return { sum, add, bigSum }
}