目录
2.1 reactive 只能用于对象或者数组这样的复杂类型数据(不可以为 String、Number、Boolean)
1.1 默认情况下,在template 中使用ref 时,vue 会自动对其进行解包(取出其中的value)
3.1 默认reactive 和 readonly 都是深度监听的
1. reactive 更多的用于对象和数组,用于本地定义的数据
4.1 默认reactive 和 readonly 都是深度监听的
2.1 解构完成之后仍然具有响应式,可以将reactive 返回的对象中的属性转为ref
3.1 解构完成之后仍然具有响应式,可以将reactive 返回的对象中的属性转为ref
1. beforeCreate 和 created 被setup 替代
2.3 可以监听多个依赖,只要有一个依赖变化,就会执行回调函数
一. reactive
1. 非响应式数据
1.1 数据不是响应式的,可以修改,但是不显示修改的数据
setup() {
let message = "Hello"
function changeMessage() {
// 数据不是响应式的
// 可以修改,但是不显示修改的数据
message = "World";
}
return {
message,
changeMessage
}
}
2. reactive API 定义响应式数据
2.1 reactive 只能用于对象或者数组这样的复杂类型数据(不可以为 String、Number、Boolean)
<div> {{ account.name }} - {{ account.age }} </div>
import { reactive } from 'vue'
setup() {
const account = reactive({
name: "why",
age: 18
})
function changeAccount() {
account.name = "coder";
}
return {
account,
changeAccount
}
}
二. ref
1. ref 的使用
1.1 默认情况下,在template 中使用ref 时,vue 会自动对其进行解包(取出其中的value)
<template> {{ counter }} </template>
setup() {
const counter = ref(0);
function increment() {
counter.value++
}
return {
counter,
increment
}
}
2. ref 的浅层解包
2.1 直接的ref 可以进行解包
<div>{{ counter }}</div>
<button @click="counter++"></button>
setup() {
const counter = ref(0);
return {
counter
}
}
2.2 对象包裹的ref 的浅层解包
// 只显示时,可以自动解包(对象中的ref)
<div>{{ info.counter }}</div>
// 需要对值进行操作时,不能自动解包(对象中的ref)
<button @click="info.counter.value++">+1</button>
setup() {
counst counter = ref(0);
const info = {
counter
}
return {
info
}
}
3. reactive 的深度监听
3.1 默认reactive 和 readonly 都是深度监听的
// 当info.friend.name 修改时,也会响应式监听
const info = reactive({
name: "why",
friend: {
name: "kobe"
}
})
三. reactive 和 ref 的使用场景
1. reactive 更多的用于对象和数组,用于本地定义的数据
const account = reactive({
username: "why",
password: "coder"
})
2. ref 更多的用于基本数据类型,用于请求的数据
const music = ref([]);
onMounted(() => {
const serverMusic = ["a", "b"];
music.value = serverMusic;
})
四. 父子间的通信
1. 父传子
// 父组件
<show-info :info = "info"></show-info>
// 子组件
props: {
info: {
type: Object,
default: () => ({})
}
}
2. 子传父
emits: ["changeInfoName"]
setup(props, context) {
function changeInfobtnClick() {
context.emit("changeInfoName", "kobe")
}
return {
changeInfobtnClick
}
}
五. readonly
1. 可传的参数
- 普通对象
- reactive 返回的对象
- ref 的对象
2. readonly 的本质
readonly 返回的对象的setter 方法被劫持了
3. 使用
- 父传子时,可以将roInfo(readonly) 传给子组件
- 子组件无法修改roInfo
- 可以通过emit 事件修改父组件的info 值
- 进而修改roInfo
const info = reactive({
name: "why"
})
const roInfo = readonly(info)
4. readonly 的深度监听
4.1 默认reactive 和 readonly 都是深度监听的
// 当info.friend.name 修改时,也会响应式监听
const info = reactive({
name: "why",
friend: {
name: "kobe"
}
})
六. isProxy
检查对象是否是由reactive 或 readonly 创建的proxy
七. isReactive
检查对象是否是由reactive 创建的响应式代理,如果该代理是由readonly 创建的,但包裹了由reactive 创建的另一个代理,它也会返回true
// 1.
const info = reactive({
name: "why"
})
isReactive(info) // true
// 2.
const obj = readonly({
name: "kobe"
})
isReactive(obj) // false
// 3.
const roInfo = readonly(info)
isReactive(roInfo) // true
八. isReadonly
检查对象是否是由readonly 创建的只读代理
九. toRaw
返回reactive 或 readonly 代理的原始对象
const info = Proxy({})
import { toRaw } from 'vue'
toRaw(info)
十. shallowReactive
创建一个响应式代理,它跟踪其自身property 的响应性,但不执行嵌套对象的深层响应式转换(深层还是原生对象)
reactive 创建的是深层的响应式对象
十一. shallowReadonly
创建一个proxy,使其自身的property 为只读,但不执行嵌套对象的深度只读转换(深层还是可读、可写的)
十二. toRefs 和 toRef
1. 响应式对象在解构之后,其结构出来的值不具有响应式
const info = reactive({
name: "why",
age: 18
})
const { name, age } = info
// name 和 age 是reactive 对象解构后的值
// 失去了响应式
2. toRefs 解构reactive 对象的多个属性
2.1 解构完成之后仍然具有响应式,可以将reactive 返回的对象中的属性转为ref
const info reactive({
name: "why",
age: 18
})
const { name, age } = toRefs( info )
3. toRef 解构reactive 对象的一个属性
3.1 解构完成之后仍然具有响应式,可以将reactive 返回的对象中的属性转为ref
const info reactive({
name: "why",
age: 18
})
const name = toRef( info, "name" );
十三. unref
- 如果我们想要获取一个ref 引用中的value, 那么也可以通过unref 方法:
- 如果参数是一个ref ,则返回内部值,否则返回参数本身
- 这是 val = isRef( val ) ? val.value : val 的值语法糖函数
十四. isRef
判断是否是一个ref 对象
十五. shallowRef
创建一个浅层的ref 对象
const info = shallowRef({
name: "why"
})
info.value.name = "kobe"
十六. triggerRef
手动触发和shallowRef 相关联的副作用
const info = shallowRef({ name: "why" });
// 下面的修改不是响应式的
const changeInfo = () => {
info.value.name = "coderwhy"
// 手动触发
triggerRef(info)
}
十七. computed
1. reactive
import { computed } from 'vue'
const names = reactive({
firstName = "kobe",
lastName = "bryant"
})
const fullName = computed(() => {
return names.firstName + names.lastName
})
2. ref
import { computed } from 'vue'
const score = ref(80)
const scoreLevel = computed(() => {
return score.value >= 60 ? 及格 : 不及格
})
3. 对象写法
import { computed } from 'vue'
const fullName = computed({
set: function(newValue) {
const tempNames = newValue.split(" ")
names.firstName = tempNames[0]
names.lastName = tempNames[1]
},
get: function() {
return names.firstName + lastName
}
})
十八. ref 获取元素和组件
1. ref 获取元素
<h2 ref="titleRef"></h2>
setup() {
const titleRef = ref(null)
onMounted(() => {
console.log(titleRef.value)
})
}
2. ref 获取组件
<show-info ref="showInfoRef"/>
const showInfoRef = ref(null)
3. 使用 ref 在父组件中调用子组件的方法
<show-info ref="showInfoRef"/>
const showInfoRef = ref(null)
showInfoRef.value.showInfoFoo()
十九. 生命周期
1. beforeCreate 和 created 被setup 替代
( setup 函数即表示beforeCreate 和 created )
v2. v3.
beforeCreate 无
created 无
beforeMount onBeforeMount
mounted onBeforeMount
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unMounted onUnmounted
activated onActivated
deactivated onDeactivated
二十. provide 和inject
// 父组件
import { provide } from 'vue'
setup(){
const counter = ref(100)
const info = reactive({
name: "why",
age: 18
})
provide("counter", counter)
provide("info", info)
}
// 子组件
import { inject } from 'vue'
setup() {
// (key, default)
const name = inject("name", coder)
}
二十一. watch 侦听器
1. 监听基本数据类型
1.1监听一个数据
const name = ref("why")
watch(name, (newValue, oldValue) => {})
1.2 监听多个数据
const name = ref("why")
const age = ref(18)
watch([name,age], (newValue, oldValue) => {})
2. 监听引用数据类型
2.1 监听被proxy 代理的对象
const info = reactive({
name: "why",
friend: {
name: "coder"
}
})
watch(info, (newValue, oldValue) => {
{
immediate: true,
deep: true
}
}
2.2 监听原始对象本身 (通过解构拿到原始对象本身)
watch(() => (
{...info}),
(newValue, oldValue) => {},
{
immediate: true,
deep: true
}
)
二十二. watchEffect
1. 特点
- 会立即执行一次, 不管是否有依赖
- 会自动收集依赖
2. 是否有依赖、监听多个依赖、停止监听
2.1 没有依赖(也会立即执行一次)
import { watchEffect } from 'vue'
setup() {
watchEffect(() => {
console.log("abc")
})
}
2.2 有依赖时,自动监听
import { watchEffect } from 'vue'
setup() {
const counter = ref(0)
watchEffect(() => {
console.log(counter.value)
})
}
2.3 可以监听多个依赖,只要有一个依赖变化,就会执行回调函数
import { watchEffect } from 'vue'
setup() {
const counter = ref(0)
const name = ref("why")
watchEffect(() => {
console.log(counter.value, name.value)
})
}
2.4 停止侦听
import { watchEffect } from 'vue'
setup() {
const counter = ref(0)
const stopWatch = watchEffect(() => {
console.log(counter.value)
})
if( counter.value > 10 ) {
stopWatch()
}
}
二十三. <script setup>
1. 定义props
<script setup>
// 定义props
const props = defineProps({
name: {
type: String,
default: "默认值"
},
age : {
type: Number,
default: 0
}
})
</script>
2. 绑定函数, 并发出事件
<script setup>
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
// (事件名, 传递的参数)
emits("infoBtnClick", "发生了点击")
}
</script>
3. defineExpose()
使用<script setup> 的组件是默认关闭的
通过模板ref 或者$parent 链获取到组件的公开实例,不会暴露任何在<script setup>中声明的绑定
通过defineExpose 编译器宏来显式指定在<script setup> 组件中要暴露出去的property
function foo() {
console.log("foo")
}
defineExpose({
foo
})
const showInfoRef = ref(null)
function callShowInfo() {
showInfoRef.value.foo()
}
附:
1. 浏览器插件
1.1 vue devtool
yarn install
yarn build