Composition API 使用
1. setup
setup
函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。
创建组件实例,然后初始化 props
,紧接着就调用setup
函数。从生命周期钩子的视角来看,它会在 beforeCreate
钩子之前被调用
2. ref
接受一个参数值并返回一个响应式且可改变的 ref 对象
ref 对象拥有一个指向内部值的单一属性 value
如果传入 ref 的是一个对象,将调用 reactive
方法对内部的 value 进行深层响应转换。
当 ref 作为渲染上下文的属性返回(即在setup()
返回的对象中)并在模板中使用时,它会自动解套,无需在模板内额外书写 .value
vue
<template>
<div class="about">
<h2>{{ count }}</h2>
<hr />
<button @click="increment">加1</button>
</div>
</template>
<script lang="ts">
import { ref } from "vue";
export default {
beforeCreate() {
console.log("beforeCreate()");
},
// 在beforeCreate()之前执行, 不能通过this访问组件对象
setup() {
console.log("setup()", this);
// 包含响应式数据的引用对象
const count = ref(0); // count是一个引用对象, 内部包含存储数据的value属性
console.log(count, count.value);
// 更新响应式数据的函数
const increment = () => {
count.value++;
};
return {
// 对象中的属性和方法, 模板可以直接访问
count,
increment,
};
},
};
</script>
3. computed
使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。
或者,它可以使用具有 get
和 set
函数的对象来创建可写的 ref 对象。
js
<template>
<div class="about">
<h2>count: {{count}}</h2>
<h2>double: {{double}}</h2>
<h2>double2: {{double2}}</h2>
<hr>
<button @click="increment">加1</button>
</div>
</template>
<script lang="ts">
import {
computed,
ref
} from "vue"
export default {
setup() {
const count = ref(0) // count是一个ref/引用对象, 内部包含存储数据的value属性
// 只有getter的计算属性
const double = computed(() => { // 计算属性本质上也是一个ref对象
console.log('double computed', count.value)
return count.value * 2
})
// 包含getter与setter的计算属性
const double2 = computed({
get () {
return count.value * 2
},
set (value: number) {
count.value = value/2
}
})
// 更新响应式数据的函数
const increment = () => {
count.value++
setTimeout(() => {
double2.value += 2
}, 1000);
}
return {
count,
increment,
double,
double2
}
}
}
</script>
4. reactive
接收一个普通对象然后返回该普通对象的响应式代理器对象
响应式转换是“深层的”:会影响对象内部所有嵌套的属性
基于 ES2015 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的
5. toRefs
问题: reactive 对象取出的所有属性值都是非响应式的
解决: 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性
6. watch
与选项 API this.$watch (以及相应的 watch 选项) 完全等效
侦听一个数据: ref 或 reactive 属性值(getter 函数)
侦听多个数据
vue
<template>
<div class="about">
<h2>msg: {{ msg }}</h2>
<h2>person.name: {{ person.name }}</h2>
<h2>numbers[1]: {{ numbers[1] }}</h2>
<h2>count: {{ count }}</h2>
<hr />
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import { reactive, toRefs, ref, watch } from "vue";
interface State {
msg: string;
person: {
name?: string;
};
numbers: number[];
}
export default {
setup() {
// 定义一个深度响应式对象
const state: State = reactive({
msg: "haha",
numbers: [1, 2, 3],
person: {
// name: 'tom'
},
});
const stateRefs = toRefs(state);
const count = ref(0);
// 监视一个ref
watch(count, (newVal, oldVal) => {
console.log("ref count变化了", newVal);
});
// 监视reactive中的某个属性
watch(
() => state.msg,
(value) => {
console.log("state中的msg变化了", value);
}
);
// 监视多个响应式数据
watch([count, stateRefs.msg, () => state.msg], (values) => {
console.log("多监视数据变化了", values);
});
const update = () => {
state.msg += "--";
// 给对象添加新属性 ==> 3.0自动更新,2.0不可以
state.person.name += "++";
// 通过下标直接替换数组元素 ==> 3.0自动更新,2.0不可以
state.numbers[1] = Date.now();
count.value++;
};
return {
// 对象中的属性和方法, 模板可以直接访问
// state // 模板表达式需要多写一层
// ...state // 对象属性不是响应式的
...stateRefs,
count,
update,
};
},
};
</script>