🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来vue篇专栏内容:vue3-组件传参及计算属性
目录
vue3中的组件传参
1、父传子
2、子传父
toRef 与 toRefs
vue3中的计算属性
vue3 中的 watch监听器
vue3中的组件传参
组件关系:
父子 props、$panrent
子父 emit自定义事件 $children $refs
兄弟 eventbus中央事件总线 vue3如果需要实现eventbus 安装第三方库mitt
跨层级 provider inject
组件状态共享工具: vuex pinia
1、父传子
-
在父组件中给子组件设置自定义属性 tit,将要传递的参数赋值给tit属性
<!--父组件 -->
<template>
<p></p>
<Testvue3 :tit="schoolName">
<span>123</span>
</Testvue3>
</template>
<script>
import Testvue3 from "@/components/Testvue3";
export default {
name: "App",
components: { Testvue3 },
setup() {
let schoolName = "千锋"; // 定义要传给子组件的数据
return {
schoolName, // 要使用的变量抛出去,这样就可以在页面模板中使用该变量
};
},
};
</script>
-
在子组件中接收传过来的属性通过props ,这个和vue2 一样没有变化。
<!-- 子组件 -->
<template>
<p>{{ tit }}</p>
<button>点击事件,子传父</button>
</template>
<script>
export default {
data() {
return {};
},
props: ["tit"],
setup(props) {
// 参数props即为父组件传过来的参数
console.log(props)
return {
//setup函数返回值为一个对象
};
},
};
</script>
2、子传父
-
给子组件绑定自定义事件,然后在setup中定义该事件对应的方法,因为setup中没有this ,this为undefined,所以vue的开发者为了解决该问题,在setup中提供了2个形参,prop和context
-
props 为父传子的参数
-
context 上下文对象,里面有emit 方法,可以实现子传父
-
-
子组件中多了 emits选项,该选项类似于props,接收父组件给子组件绑定的自定义方法,如果不加该选项,vue3 会提示警告。但不影响功能
<!-- 子组件 -->
<template>
<p>{{ tit }}</p>
<button @click="emit">点击事件,子传父</button>
</template>
<script>
import { reactive } from "vue";
export default {
data() {
return {};
},
emits: ["transfer"], // 在子组件中使用emits配置项,接收父组件给我绑定的自定义事件,用法类似于props, // 不加该配置项,控制台会提示警告
setup(props, context) {
console.log(11, props);
console.log(22, context);
// 定义方法
function emit() {
// 子传父 此处不用this,使用context上下文对象
context.emit("transfer", 666);
}
return {
//setup函数返回值为一个对象
emit,
};
},
};
</script>
-
在父组件接收自定义事件,该事件对应的执行函数的形参就是传过来的数据,这个就和vue2一样啦。
<!--父组件 --> <template> <p></p> <Testvue3 @transfer="showdata"> <span>123</span> </Testvue3> </template> <script> import Testvue3 from "@/components/Testvue3"; export default { name: "App", components: { Testvue3 }, setup() { function showdata(value) { console.log(value); } return { showdata, }; }, }; </script>
toRef 与 toRefs
定义:toRef 创建一个ref 响应数据
语法:let name = toRef(person,'name') 将响应对象person中的name属性单独拿出来变成响应属性。
应用:一般用于将响应对象中的某个属性单独提供给外部使用
-
如下是使用toRef 前的代码: 插值表达式模板中的 person 有点繁琐
-
<!-- 子组件 -->
<template> <div> <p> {{ person.name }} -- {{ person.age }} -- {{ person.job.type }} -- {{ person.job.salary }} </p> </div> </template> <script> import { reactive } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); return { person, }; }, }; </script>
-
如下是使用toRef 后 的代码,
-
<!-- 子组件 -->
<template> <div> <p> <!-- 在模板中直接使用name,age,type,salary --> {{ name }} -- {{ age }} -- {{ type }} -- {{ salary }} </p> <p> <button @click="name += '-'">修改name</button> <button @click="salary++">修改薪水</button> </p> </div> </template> <script> import { reactive, toRef } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); // 将person 中的name 属性转换成ref 响应式数据,这样就可以直接在模板中使用了,以此类推 let name = toRef(person, "name"); let age = toRef(person, "age"); let type = toRef(person.job, "type"); let salary = toRef(person.job, "salary"); return { name, age, type, salary, }; }, }; </script> <style scoped> /* @import url(); 引入css类 */ </style>
-
使用toRefs 可以将对象中的多个属性转换成响应数据,代码如下:
-
<!-- 子组件 -->
<template> <div> <p> {{ name }} -- {{ age }} -- {{ job.type }} -- {{ job.salary }} </p> <p> <button @click="name += '-'">修改name</button> <button @click="job.salary++">修改薪水</button> </p> </div> </template> <script> import { reactive, toRefs } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); //toRefs返回一个响应对象,该对象中每个属性都变成了响应属性了。这样就可以直接拿来在模板插值表达式中使用了 let person1 = toRefs(person); // console.log(person1); return { ...person1, // 使用后扩展运算符展开对象 }; }, }; </script> <style scoped> /* @import url(); 引入css类 */ </style>
关于数据响应式设置的问题:
1、如何设置一个响应式数据? ref reactive
2、如何将非响应式数据转为响应式数据? toRef toRefs
3、如何将数据设置为只读数据?不能够修改 readOnly
vue3中的计算属性
同vue2不同,使用计算属性需要引入computed 方法
<template>
<p>姓:<input type="text" v-model="data.firstname" /></p>
<p>名:<input type="text" v-model="data.lastname" /></p>
<p>姓名:<input type="text" v-model="data.fullname" /></p>
</template>
<script>
// 引入对应的计算属性方法
import { reactive, computed } from "vue";
export default {
name: "App",
setup() {
let data = reactive({
firstname: "",
lastname: "",
fullname: "",
});
// 计算属性--简写
// data.fullname = computed(() => {
// return data.firstname + data.lastname;
// });
// 计算属性--完整写法
data.fullname = computed({
get() {
return data.firstname + data.lastname;
},
set(value) {
console.log(value);
data.firstname = value.substr(0, 1);
data.lastname = value.substr(1);
},
});
return {
data,
};
},
};
</script>
vue3 中的 watch监听器
vue3 中的watch 也是 组合式api中的一个方法,所以使用时,需要引入
<template>
<p>{{ sum }} <button @click="sum++">sum++</button></p>
<p>{{ fullname }} <button @click="fullname += '-'">修改姓名</button></p>
<p>
{{ userinfo.name }}--{{ userinfo.age }}--{{ userinfo.job.type }}--{{
userinfo.job.salary
}}K
<button @click="userinfo.age++">修改年龄</button>
<button @click="userinfo.job.salary++">修改薪水</button>
</p>
</template>
<script>
// 引入对应的计算属性方法
import { ref, watch, reactive } from "vue";
export default {
name: "App",
setup() {
let sum = ref(0);
let fullname = ref("张三");
let userinfo = reactive({
name: "李四",
age: 20,
job: {
type: "web开发",
salary: 20,
},
});
//1、监听ref定义的响应式数据 immediate初始化就执行watch
watch(sum, (newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
},{immediate:true});
//2、 监听ref定义的多个响应式数据,immediate初始化就执行watch
watch([sum, fullname], (newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
}, { immediate: true });
//3、 监听reactive 定义的响应式数据
// 注意:此处oldvalue 无效(新值与旧值一样),默认是深度监听,immediate初始化就执行watch
watch(
userinfo,
(newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
},
{ immediate: true });
return {
sum,
fullname,
userinfo,
};
},
};
</script>
watch
和watchEffect
都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
watch
只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch
会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
watchEffect
,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。