setup 作为组合式 API 的入口点,也就是说,组合式 API 都必须只能在 setup 中使用
<template>
<div>
<h1>setup - 组件内使用 Composition API 的入口点</h1>
<p>{{username}}</p>
</div>
</template>
<script>
export default {
name: "Setup",
props: {
username: { type: String, default: "guao" },
},
//setup 先与 beforeCreate。
setup(props, ctx) {
console.log("setup");
console.log(props, ctx);
//props里面使用 父组件传来的props
console.log(props.username, ctx);
//由于 setup 里面不能使用 this,
//所以不能像 vue2.x 一样使用 this.$emit(‘emitFun’, val),
//setup 里面有两个参数,第二个参数可以进行结构得到 emit,
//也可以直接直接使用 ctx.emit 进行 emit 事件
ctx.emit('emitFun', {emit: true})
},
beforeCreate() {
console.log("beforeCreate");
},
};
</script>
创建组件实例,然后初始化 props ,紧接着就调用setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用。
reactive - 对象数据响应式
接收一个普通对象然后返回该普通对象的响应式代理。
<template>
<div>
<p>{{data.msg}}</p>
<button @click="updateData">更新数据</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "ReactiveObject",
setup() {
const data = reactive({ msg: "hello world" });
const updateData = () => {
data.msg= "hello world " + new Date().getTime();
};
return { data, updateData };
},
};
</script>
ref - 单值数据响应式
接受一个参数值并返回一个响应式且可改变的 ref 对象。
<template>
<div>
<h1>单值数据响应式</h1>
<p>{{msg}}</p>
<button @click="updateMessage">更新数据</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "ReactiveSingleValue",
setup() {
const msg= ref("hello world");
const updateMessage = () => {
msg.value = "hello world " + new Date().getTime();
};
return { msg, updateMessage };
},
};
</script>
只传 getter
返回一个默认不可手动修改的 ref 对象。
<template>
<div>
<h1>computed - 计算属性</h1>
<p>{{username}}</p>
</div>
</template>
<script>
import { reactive, computed } from "vue";
export default {
name: "Computed",
setup() {
const user = reactive({ firstname: "chen", lastname: "haihong" });
const username = computed(() => user.firstname + " " + user.lastname);
username.value = "hello world"; // 报警告,computed value is readonly
return { username };
},
};
</script>
同时传 getter、setter
创建一个可手动修改的计算状态。
<template>
<div>
<h1>computed - 计算属性</h1>
<p>firstname: <input v-model="user.firstname" /></p>
<p>lastname: <input v-model="user.lastname" /></p>
<p>username: <input v-model="username" /></p>
</div>
</template>
<script>
import { reactive, computed } from "vue";
export default {
name: "Computed2",
setup() {
const user = reactive({ firstname: "Chen", lastname: "Haihong" });
const username = computed({
get: () => user.firstname + " " + user.lastname,
set: (value) => {
const [firstname, lastname] = value.trim().split(" ");
user.firstname = firstname;
user.lastname = lastname;
},
});
return { user, username };
},
};
</script>
watchEffect
立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。
<template>
<div>
<h1>watchEffect - 侦听器</h1>
<p>{{data.count}}</p>
</div>
</template>
<script>
import { reactive, watchEffect } from "vue";
export default {
name: "WatchEffect",
setup() {
const data = reactive({ count: 1 });
watchEffect(() => console.log(`侦听器:${data.count}`));
setInterval(() => {
data.count++;
}, 1000);
return { data, stop };
},
};
</script>
watch
对比watchEffect,watch允许我们:
• 懒执行副作用,也就是说仅在侦听的源变更时才执行回调;
• 更明确哪些状态的改变会触发侦听器重新运行副作用;
• 访问侦听状态变化前后的值。
<template>
<div>
<h1>watch - 侦听器</h1>
<p>count1: {{data.count1}}</p>
<p>count2: {{data.count2}}</p>
<button @click="stopAll">Stop All</button>
</div>
</template>
<script>
import { reactive, watch } from "vue";
export default {
name: "Watch",
setup() {
const data = reactive({ count1: 0, count2: 0 });
// 侦听单个数据源
const stop1 = watch(data, () =>
console.log("watch1", data.count1, data.count2)
);
// 侦听多个数据源
const stop2 = watch([data], () => {
console.log("watch2", data.count1, data.count2);
});
setInterval(() => {
data.count1++;
}, 1000);
return {
data,
stopAll: () => {
stop1();
stop2();
},
};
},
};
</script>
传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
<template>
<div>
<h1>readonly - “深层”的只读代理</h1>
<p>original.count: {{original.count}}</p>
<p>copy.count: {{copy.count}}</p>
</div>
</template>
<script>
import { reactive, readonly } from "vue";
export default {
name: "Readonly",
setup() {
const original = reactive({ count: 0 });
const copy = readonly(original);
setInterval(() => {
original.count++;
copy.count++; // 报警告,Set operation on key "count" failed: target is readonly. Proxy {count: 1}
}, 1000);
return { original, copy };
},
};
</script>
toRef 可以用来为一个 reactive 对象的属性创建一个 ref。这个 ref 可以被传递并且能够保持响应性。
setup() {
const user = reactive({ age: 1 });
const age = toRef(user, "age");
age.value++;
console.log(user.age); // 2
user.age++;
console.log(age.value); // 3
}
当您要将一个 prop 中的属性作为 ref 传给组合逻辑函数时,toRef 就派上了用场:
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
},
}
把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref ,和响应式对象 property 一一对应。
<template>
<div>
<h1>解构响应式对象数据</h1>
<p>Username: {{username}}</p>
<p>Age: {{age}}</p>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
name: "DestructReactiveObject",
setup() {
const user = reactive({
username: "haihong",
age: 10000,
});
return { ...toRefs(user) };
},
};
</script>
检查一个值/对象是否为一个 ref / proxy / reactive / readonly 对象。