computed

01_computed的使用.vue
<template>
<div>
<h2>{{ fullName }}</h2>
<button @click="changeName">修改firstName</button>
</div>
</template>
<script>
import { ref, computed } from "vue";
export default {
setup() {
const firstName = ref("Kobe");
const lastName = ref("Bryant");
// 1.用法一: 传入一个getter函数
// computed的返回值是一个ref对象
const fullName = computed(() => firstName.value + " " + lastName.value);
// 2.用法二: 传入一个对象, 对象包含getter/setter
const fullName = computed({
get: () => firstName.value + " " + lastName.value,
set(newValue) {
const names = newValue.split(" ");
firstName.value = names[0];
lastName.value = names[1];
// [firstName.value, lastName.value] = names
},
});
const changeName = () => {
// firstName.value = "James"
fullName.value = "haha xixi";
};
return {
fullName,
changeName,
};
},
};
</script>
<style scoped></style>
侦听数据的变化

watchEffect

02_watchEffect基本使用.vue
<template>
<div>
<h2>{{ name }}-{{ age }}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
const changeName = () => (name.value = "kobe");
const changeAge = () => age.value++;
// watchEffect会立即执行一次
watchEffect(() => {
console.log("name:", name.value, "age:", age.value);
});
return {
name,
age,
changeName,
changeAge,
};
},
};
</script>
<style scoped></style>
watchEffect的停止侦听

03_watchEffect停止侦听.vue
<template>
<div>
<h2>{{ name }}-{{ age }}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
// 【停止监听,但是界面数据继续更新】
// watchEffect():返回的是一个函数
const stop = watchEffect(() => {
console.log("name:", name.value, "age:", age.value);
});
const changeName = () => (name.value = "kobe");
const changeAge = () => {
age.value++;
if (age.value > 25) {
stop(); // age.value > 25时,停止监听
}
};
return {
name,
age,
changeName,
changeAge,
};
},
};
</script>
<style scoped></style>
watchEffect清除副作用

04_watchEffect清除副作用.vue
<template>
<div>
<h2>{{ name }}-{{ age }}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
const stop = watchEffect((onInvalidate) => {
// 【这里用定时器模拟网络请求】
const timer = setTimeout(() => {
console.log("网络请求成功~");
}, 2000);
// 根据name和age两个变量发送网络请求
// 在这个函数中清除额外的副作用
// 【组件销毁,监听器也随着销毁,并执行onInvalidate的回调函数,可在这里做清理相关工作。】
onInvalidate(() => {
// request.cancel() // 【取消上次的网络请求】
clearTimeout(timer);
console.log("onInvalidate---------");
});
console.log("name:", name.value, "age:", age.value);
});
const changeName = () => (name.value = "kobe");
const changeAge = () => {
age.value++;
if (age.value > 25) {
stop();
}
};
return {
name,
age,
changeName,
changeAge,
};
},
};
</script>
<style scoped></style>
setup中使用ref

watchEffect的执行时机

调整watchEffect的执行时机

05_watchEffect执行时机ref引用.vue
<template>
<div>
<h2 ref="title">哈哈哈</h2>
</div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
setup() {
// 【常量名要和ref="title"中的title一致,否则打印的值都是null。】
const title = ref(null);
watchEffect(
// 【副作用函数】
() => {
console.log(title.value); // <h2>哈哈哈</h2>
// 哈哈哈, 通过innerHTML拿到DOM元素的值
console.log(title.value.innerHTML);
},
{
// pre: 提前执行; post:DOM挂载、更新完后执行
flush: "post",
}
);
return {
title,
};
},
};
</script>
<style scoped></style>
Watch的使用

侦听单个数据源

06_watch侦听的数据源类型.vue
<template>
<div>
<h2 ref="title">{{ info.name }}</h2>
<button @click="changeData">修改数据</button>
</div>
</template>
<script>
import { ref, reactive, watch } from "vue";
export default {
setup() {
// watchEffect是直接在函数里使用即可,不用管有哪些依赖
const info = reactive({ name: "why", age: 18 });
// 1.侦听watch时,传入一个getter函数 【() => info.name就是getter函数。】
watch(
() => info.name,
(newValue, oldValue) => {
console.log("newValue:", newValue, "oldValue:", oldValue);
}
);
// 2.传入一个可响应式对象: reactive对象/ref对象
// 情况一: reactive对象获取到的newValue和oldValue本身都是reactive对象
// watch(info, (newValue, oldValue) => {
// console.log("newValue:", newValue, "oldValue:", oldValue);
// console.log("newValue:", newValue.name, "oldValue:", oldValue.name);
// })
// 如果希望newValue和oldValue是一个普通的对象
watch(
// 简写:() => ({...info})
() => {
return { ...info };
},
(newValue, oldValue) => {
// 【此时,newValue和oldValue是一个普通的对象】
console.log("newValue:", newValue, "oldValue:", oldValue);
// console.log("newValue:", newValue.name, "oldValue:", oldValue.name);
}
);
// 情况二: ref对象获取newValue和oldValue是value值的本身
const name = ref("why");
// watch(name, (newValue, oldValue) => {
// // 【这里不是newValue.value】
// console.log("newValue:", newValue, "oldValue:", oldValue);
// })
const changeData = () => {
info.name = "kobe";
};
return {
changeData,
info,
};
},
};
</script>
<style scoped></style>
侦听多个数据源

侦听响应式对象

07_watch侦听多个数据源.vue
<template>
<div>
<h2 ref="title">{{ info.name }}</h2>
<button @click="changeData">修改数据</button>
</div>
</template>
<script>
import { ref, reactive, watch } from "vue";
export default {
setup() {
// 1.定义可响应式的对象
const info = reactive({ name: "why", age: 18 });
const name = ref("haha");
// 2.侦听器watch
// 【变成普通的对象,如果不加圆括号,编译器就不知道是要返回...info,还是{ ...info}。】
watch(
[() => ({ ...info }), name],
([newInfo, newName], [oldInfo, oldName]) => {
console.log(newInfo, newName);
console.log(oldInfo, oldName);
}
);
const changeData = () => {
info.name = "kobe";
};
return {
changeData,
info,
};
},
};
</script>
<style scoped></style>
watch的选项

08_深度监听.vue
<template>
<div>
<h2 ref="title">{{info.name}}</h2>
<button @click="changeData">修改数据</button>
</div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
setup() {
// 1.定义可响应式的对象
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
});
// 2.侦听器watch
watch(() => ({...info}), (newInfo, oldInfo) => {
console.log(newInfo, oldInfo);
}, {
// 【默认是可以深度监听的,源码中,当监听的数据源是reactive时,deep=true。】
deep: true,
immediate: true
})
const changeData = () => {
info.friend.name = "james";
}
return {
changeData,
info
}
}
}
</script>