computed的使用
定义
computed
是一个函数,用于创建计算属性(computed properties)。
计算属性是基于其他响应式数据派生出来的值,当依赖的响应式数据发生变化时,计算属性会自动重新计算。
特点
- 缓存机制:计算属性是惰性的,只有当依赖的响应式数据发生变化时,才会重新计算。
- 只读或可写:可以创建只读的计算属性,也可以创建可写的计算属性。
- 依赖响应式数据:计算属性依赖于
ref
、reactive
或其他计算属性。
语法
import { computed } from 'vue';
// 只读计算属性
const computedValue = computed(() => {
// 计算逻辑
return someReactiveData.value + 10;
});
// 可写计算属性
const computedValue = computed({
get() {
return someReactiveData.value;
},
set(newValue) {
someReactiveData.value = newValue;
}
});
示例
<template>
<div>
<p>Full Name: {{ fullName }}</p>
<input v-model="firstName" placeholder="First Name" />
<input v-model="lastName" placeholder="Last Name" />
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const firstName = ref('John');
const lastName = ref('Doe');
// 只读计算属性
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`;
});
return {
firstName,
lastName,
fullName
};
}
};
</script>
使用场景
- 当你需要基于响应式数据派生出新的值时(如格式化数据、计算总和等)。
- 当你需要优化性能,避免不必要的计算时(利用缓存机制)。
watch的使用
定义
watch
是一个函数,用于监听响应式数据的变化,并执行副作用(side effects)。它允许你对响应式数据的变化做出响应,例如发送网络请求、更新 DOM 或调用外部函数。
特点
- 监听响应式数据:可以监听
ref
、reactive
对象或计算属性。 - 立即执行:可以通过
immediate: true
选项在初始化时立即执行回调函数。 - 深度监听:可以通过
deep: true
选项监听对象内部属性的变化。 - 清理副作用:可以在回调函数中返回一个清理函数,用于清理上一次执行的副作用。
语法
import { watch } from 'vue';
// 监听单个响应式数据
watch(someReactiveData, (newValue, oldValue) => {
console.log(`New value: ${newValue}, Old value: ${oldValue}`);
});
// 监听多个响应式数据
watch([ref1, ref2], ([newValue1, newValue2], [oldValue1, oldValue2]) => {
console.log(`New value 1: ${newValue1}, Old value 1: ${oldValue1}`);
console.log(`New value 2: ${newValue2}, Old value 2: ${oldValue2}`);
});
示例
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
// 监听 count 的变化
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
});
return {
count,
increment
};
}
};
</script>
使用场景
- 当你需要对响应式数据的变化做出响应时(如发送网络请求、更新 DOM 等)。
- 当你需要监听多个响应式数据的变化时。
- 当你需要在初始化时立即执行某些逻辑时(通过
immediate: true
)。
watchEffect的补充说明
除了watch
,Vue 3 还提供了一个更高级的函数watchEffect
,用于自动收集依赖并响应变化。它类似于watch
,但不需要显式指定依赖,而是自动收集回调函数中使用的响应式数据。
语法
import { watchEffect } from 'vue';
watchEffect(() => {
console.log(`Count is now ${count.value}`);
});
特点
- 自动收集依赖,无需显式指定。
- 默认立即执行回调函数。
- 可以返回清理函数。
示例
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
// 使用 watchEffect 自动收集依赖
watchEffect(() => {
console.log(`Count changed to ${count.value}`);
});
return {
count,
increment
};
}
};
</script>
使用场景
- 当你需要自动收集依赖,而无需显式指定时。
- 当你需要更简洁的代码时。
总结
computed
:
- 用于创建基于响应式数据派生的值。
- 是惰性的,只有在依赖变化时才会重新计算。
- 适用于需要缓存的派生值。
watch
:
- 用于监听响应式数据的变化,并执行副作用。
- 可以监听单个或多个响应式数据。• 提供更多控制选项(如
immediate
、deep
)。watchEffect
: - 自动收集依赖,无需显式指定。
- 默认立即执行回调函数。
- 更适合需要自动响应依赖变化的场景。
标签中的ref使用
定义
ref
在 Vue 3 中有两种用途:
- 模板中的
ref
:用于给 DOM 元素或子组件实例添加引用,方便在 JavaScript 中访问它们。 - Composition API 中的
ref
:用于创建响应式数据(与模板无关)。
模板中的ref
使用在模板中,ref
是一个特殊的属性,用于给 DOM 元素或子组件实例添加引用。它可以在setup()
函数中通过ref
函数访问。
语法
<template>
<input ref="inputRef" />
<ChildComponent ref="childRef" />
</template>
在setup()
中访问:
import { ref, onMounted } from 'vue';
export default {
setup() {
const inputRef = ref(null); // 创建一个 ref 来存储 DOM 引用
const childRef = ref(null); // 创建一个 ref 来存储子组件实例
onMounted(() => {
console.log(inputRef.value); // 访问 DOM 元素
console.log(childRef.value); // 访用子组件实例
});
return {
inputRef,
childRef
};
}
};
特点
- 访问 DOM 元素:通过
ref
可以直接访问 DOM 元素,例如获取输入框的值或操作 DOM。 - 访问子组件实例:可以访问子组件的实例,从而调用子组件的方法或访问子组件的
props
。 - 默认值为
null
:在组件挂载之前,ref
的值为null
。
示例
<template>
<input ref="inputRef" placeholder="Enter something" />
<button @click="focusInput">Focus Input</button>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const inputRef = ref(null);
// 定义一个方法,聚焦到输入框
function focusInput() {
inputRef.value.focus(); // 访问 DOM 元素并调用 focus 方法
}
return {
inputRef,
focusInput
};
}
};
</script>
props
的使用
定义
props
是子组件接收父组件传递的数据的方式。它允许父子组件之间进行数据通信。
使用方法
- 定义
props
:在子组件中定义props
,声明需要接收的数据。 - 传递
props
:在父组件中通过子组件的属性传递数据。
语法
子组件中定义props
:
<script>
export default {
props: {
title: String, // 接收一个字符串类型的 prop
count: Number // 接收一个数字类型的 prop
}
};
</script>
父组件中传递props
:
<template>
<ChildComponent :title="headerTitle" :count="itemCount" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
headerTitle: 'Hello Vue 3!',
itemCount: 10
};
}
};
</script>
特点
- 单向数据流:
props
是单向的,只能从父组件传递到子组件,不能反向修改。 - 类型检查:可以在
props
中定义类型,Vue 会自动进行类型检查。 - 默认值:可以通过
default
属性为props
提供默认值。 - 动态绑定:使用
v-bind
(简写为:
)动态绑定props
。
示例
子组件:
<template>
<div>
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
}
};
</script>
父组件:
<template>
<ChildComponent :title="headerTitle" :count="itemCount" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const headerTitle = 'Hello Vue 3!';
const itemCount = 5;
return {
headerTitle,
itemCount
};
}
};
</script>
ref
和props
的区别
特性 | ref | props |
---|---|---|
用途 | 引用 DOM 元素或子组件实例 | 在父子组件之间传递数据 |
定义方式 | 在模板中通过 ref="name" 定义 | 在子组件中通过 props 定义 |
访问方式 | 在 setup() 中通过 ref 函数访问 | 在子组件中直接使用 |
数据流向 | 单向(父组件 -> 子组件) | 单向(子组件 -> 父组件) |
默认值 | 默认为 null | 可以通过 default 提供默认值 |
响应式 | 是(引用的 DOM 或实例是响应式的) | 是(传递的数据是响应式的) |
总结
ref
:
- 用于引用 DOM 元素或子组件实例。
- 在模板中通过
ref="name"
定义,在setup()
中通过ref
函数访问。 - 常用于操作
DOM
或调用子组件的方法。
props
:
- 用于在父子组件之间传递数据。
- 在子组件中通过
props
定义,在父组件中通过属性传递。 - 是单向数据流,只能从父组件传递到子组件。