vue中常见的传值方式
平时项目开发中,经常使用的VUE开发的时候,会把一些功能相似的模块封装成一个组件。向组件传入相关信息,然后就可以实现功能的输出,不必注重内在逻辑的实现,这可以理解为封装。组件的主要的通信方式就是’接口’,这个接口可以是一个参数或者是一个函数操作的开始。哈哈 … ,说了这么多这是我自己的见解。我们具体说说VUE的传值方式。
VUE中的传值方式有几种常见的方式,例如:父子组件通信、兄弟组件通信、vuex状态管理等等。简单的汇总一下遇到的各种VUE传值方式。
父子组件之间的传值
首先最常见的是父子组件之间的传值,包含子组件传父组件,父组件传子组件,直接上代码。
- 首先父传子,这个最常用看下面例子,看父组件文件:
// Parent.vue
<template>
<child :praentData="praentData"></child>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {
child: Child
},
data() {
return {
praentData: {
testKey: "Hello world"
}
}
}
}
</script>
再看看子组件文件中的代码,如下面所示:
// Child.vue
<template>
<div class="text"> {{ praentData.testKey ? praentData.testKey : " " }} </div>
</template>
<script>
export default {
props: {
praentData: {
type: Object,
default: {}
}
}
}
</script>
这样在子组件中拿到父组件中的值,进行逻辑操作,例如一个网站的加购弹窗等数据传入进来,在子组件中处理完加购逻辑,在多处可以引入该组件形成组件的复用。如果在父组件中会有一些数据可能是异步获取的,例如通过axios
请求拿到的数据,有时候会发现页面数据加载不会更新,这个时候可以用到watch
属性来监听传递过来的数据,看下面例子:
// Parent.vue
<template>
<child :praentData="praentData"></child>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {
child: Child
},
data() {
return {
praentData: {
testKey: "Hello world"
}
}
},
methods: {
initData() {
setTimeout(() => {
this.praentData.testKey = "Nice"
},2000)
}
}
}
</script>
子组件中使用witch
,或者使用计算属性(computed
)配合witch
使用更加合适。
// Child.vue
<template>
<div class="text"> {{ text }} </div>
</template>
<script>
export default {
props: {
praentData: {
type: Object,
default: {}
}
},
witch: {
"praentData.testKey": function (n, o) {
let flagText = n ? n : o;
flagText && this.text = flagText;
}
},
data() {
return {
text: ""
}
}
}
</script>
- 子组件给父组件传值,在我看来有两种简单方式,通过监听事件来实现,一种是通过
$emit
来监听父组件的方法,就是绑定自定义函数。也可以通过调用父子组件的方法传递参数来实现传值。比如有一个登录弹窗的组件,我们在多个地方调用这个组件。下面我们来看看代码:
// index.vue 父组件
<template>
<div @click="showLogin">
// ...
<login :praentData="loginStatus" @close="hideLogin"></login>
</div>
</template>
<script>
import login from "@/components/login";
export default {
components: {
login
},
data() {
return {
loginStatus: false
}
},
methods: {
showLogin() {
this.loginStatus = true;
},
hideLogin(val = undefined) {
this.loginStatus = val || false;
}
}
}
</script>
在子组件中使用,如下图所示:
// login.vue 子组件
<template>
<div class="login" v-show="praentData" @click="close"> {{ 'Hello world' }} </div>
</template>
<script>
export default {
props: {
praentData: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
close() {
this.$emit("hideLogin", false); // $emit 监听绑定的父组件方法
// this.$parent.hideLogin(); // 或者获取到父组件实例之后直接调用父组件的方法,如果组件之间嵌套比较深,获取不到正确的父组件,此方法行不通,可以尝试下面的依赖注入的方式
// this.praentData = false; // ??为何不这样
}
}
}
</script>
我们为什么没有在子组件中直接修改父组件传过来的值,因为vue
中是数据流是单向流通的,在子组件中直接修改父组件中传递过来的值,为了方便管理,数据都是从父组件传入子组件,子组件修改父组件的值,在data()
中定义数据是响应式的,父组件的值改动了子组件里的值也会相对应的更新。
- 上面说了如果组件层级嵌套比较深,不能直接获取到正确的父组件实例,这种如果使用UI框架开发的话,场景非常常见,因为UI框架本身封装的是一层组件,然后我们在UI组件里面引入我们的组件,这时候就可以使用上依赖注入了。
代码如下所示:// index.vue 父组件 <template> <div @click="showLogin"> // ... <login :praentData="loginStatus" @close="hideLogin"></login> </div> </template> <script> import login from "@/components/login"; export default { components: { login }, data() { return { loginStatus: false } }, methods: { showLogin() { this.loginStatus = true; }, hideLogin(val = undefined) { this.loginStatus = val || false; } }, provide() { return { hideLogin: this.hideLogin } }, } </script>
在子组件中使用了Vant-UI
的遮罩层UI组件,后面所有的组件都能访问到这写属性和方法,如下面所示:
// login.vue 子组件
<template>
<van-overlay :show="praentData" @click="close"> <!--如果这个组件挂载到body下面-->
<div class="login"> {{ 'Hello world' }} </div>
</van-overlay >
</template>
<script>
export default {
props: {
praentData: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
inject: ['hideLogin'],
methods: {
close() {
//this.$emit("hideLogin", false); // 这样不行,除非这个方法写在UI框架组件中
// this.$parent.hideLogin(); // 这样也不行,拿不到正确的父组件实例
this.hideLogin();
}
}
}
</script>
当然上面的例子不一定是具体的真实情况,我是举个例子依赖注入使用的场景例子,通过在父组件依赖注入之后的方法和数据,在后代的所有组件中都能访问这个方法或数据。
最后,由于篇幅时间问题,组件传值还有大家熟知的$bus
、vuex
、v-solt
传值等等,这些都可以归纳为为传值的方式,等有时间再做详细讲解。