vue3学习笔记之响应式状态
响应式状态
src/views/basic/Reactive.vue
<script setup>
import { ref, reactive, computed, watch, watchEffect } from "vue";
//reactive 响应式对象 只能用于对象、数组和集合类型
const author = reactive({
name: "John Doe",
books: ["Vue 2 - Advanced Guide", "Vue 3 - Basic Guide", "Vue 4 - The Mystery"],
});
//计算属性 值会基于其响应式依赖被缓存。计算属性仅会在其响应式依赖更新时才重新计算。
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? "Yes" : "No";
});
// 声明响应式状态
const firstName = ref("John");
const lastName = ref("Doe");
const fullName = computed({
get() {
return firstName.value + " " + lastName.value;
},
set(newValue) {
[firstName.value, lastName.value] = newValue.split(" "); // 解构赋值语法
},
});
const fullname_text = ref(null);
const fullname_num_text = ref(null);
const num = ref(5);
// 侦听器 使用 watch 函数在每次响应式状态发生变化时触发回调函数
// 可以直接侦听一个 ref
watch(num, (newnum, oldnum) => {
if (newnum > 30) {
num.value = 0;
}
});
// getter 函数
watch(
() => firstName.value + " " + lastName.value,
(full_name) => {
fullname_text.value.textContent = `Full name is: ${full_name}`;
}
);
// 多个来源组成的数组
watch([num, () => firstName.value + " " + lastName.value], ([newnum, full_name]) => {
fullname_num_text.value.textContent = `Full name is: ${full_name},num is:${newnum}`;
});
const todoId = ref(1);
const todoData = ref(null);
// watchEffect 自动跟踪回调的响应式依赖。
watchEffect(async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`);
todoData.value = await response.json();
});
</script>
<template>
<div>
<!-- 计算属性 -->
<div>
<p>
Has published books:<span>{{ publishedBooksMessage }}</span>
</p>
</div>
<div>
<p>num: <input v-model.number="num" /></p>
<p>名:<input v-model.trim="firstName" />姓:<input v-model.trim="lastName" /></p>
<p>姓名:<input v-model.trim="fullName" /></p>
<p ref="fullname_text">Full name is: {{ fullName }}</p>
<p ref="fullname_num_text">Full name is: {{ fullName }} , num is: {{ num }}</p>
</div>
<!-- 侦听器 -->
<div>
<p>Todo id: {{ todoId }}</p>
<button @click="todoId++">Fetch next todo</button>
<p v-if="!todoData">Loading...</p>
<pre v-else>{{ todoData }}</pre>
</div>
</div>
</template>
<style scoped></style>
src/components/simple/DemoComp.vue
<script setup>
import { ref, inject } from "vue";
defineOptions({
inheritAttrs: false, //禁用 Attributes 继承
});
const props = defineProps({
title: String,
greetingMessage: String,
likes: Number,
isPublished: Boolean,
author: Object,
comments: Array,
});
const emits = defineEmits(["enlargeText"]);
const count = ref(0);
// 注入上层组件提供的数据
const api_url = inject("api_url");
const module_name = inject("module_name");
const { location, updateLocation } = inject("location");
let read_only_count = inject("read_only_count");
function updateCount() {
read_only_count.value++;
alert("read_only_count的值为:" + read_only_count.value);
}
</script>
<template>
<div>
<p :class="$attrs.class">
<span>msg:{{ title }}</span>
<span>greetingMessage:{{ greetingMessage }}</span>
<span>likes:{{ likes }}</span>
<span>is-published:{{ isPublished ? "是" : "否" }}</span>
<span>author:{{ author.name + "|" + author.company }}</span>
</p>
<button type="button" @click="count++">count is {{ count }}</button>
<button @click="$emit('enlargeText')">Enlarge text</button>
<p>
<slot><span>default slot </span></slot>
<slot name="slot2"><span>slot2</span></slot>
<slot name="slot3"><span>slot3</span></slot>
<slot name="slot4">
<span>slot4</span>
</slot>
</p>
<!-- 作用域插槽,子组件传值item给父组件 -->
<p>
comments:
<span v-for="(item, index) in comments" :key="index">
<slot name="item" v-bind="item"></slot>
</span>
</p>
<p>
App.vue注入:
<span>{{ api_url }}</span>
</p>
<p>
父级组件注入(允许修改):
<span>{{ module_name }}</span>
<button @click="updateLocation">{{ location }}</button>
</p>
<p>
父级组件注入(不允许修改):
<span>{{ read_only_count }}</span>
<button @click="updateCount">update count</button>
</p>
</div>
</template>
<style scoped>
span {
margin-left: 1rem;
}
button,
a {
border: 1px solid blue;
margin-left: 1rem;
}
</style>

浙公网安备 33010602011771号