前言
最近复习了vue相关知识点,今天分享下组件通信。
组件在嵌套的过程中,经常会遇到互相传递数据的情况。
我们可以把组件之间的数据传递分为三种情况:
- 父级向子级传递数据
- 子级向父级传递数据
- 非父子级传递数据
1.父传子(props属性)
props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
props基于对象的写法有4个属性(具体可以参考下Vue官方文档,附上一张属性解释图):
type类型 required必填项 default默认值 validator自定义验证函数
子组件设置props属性,接收从父组件传递过来的参数。
需求:父组件是App.vue,子组件是Child.vue。想将父组件里面的一些数据传递到子组件中。
- 在父组件中引入、注册、使用子组件,使用时绑定要传递的属性;
- 在子组件中使用props接收父组件传递过来的数据;
- 子组件的模板中使用props定义的属性。
父组件App.vue的代码如下:
<template>
<div id="app">
<h2>Hi,我是父组件</h2>
<div class="content">
<!-- 使用子组件 -->
<!-- 1.不传值 -->
<Child></Child>
<!-- 2.父组件传递字符串到子组件不需要使用v-bind来绑定(直接传递写死的值不需要动态绑定) -->
<Child cmsg="这是子组件喔~"></Child>
<!-- 3.传递动态数据需要利用v-bind动态绑定 -->
<Child :ctitle="title" cmsg="这是子组件喔~" :cnum="num" :clist="list">
</Child>
</div>
</div>
</div>
</template>
<script>
// 引入子组件
import Child from "./components/Child.vue";
export default {
name: "App",
// 注册组件
components: {
Child,
},
data() {
return {
title: "父组件传递的标题",
list: [],
num: 88,
};
},
methods: {},
};
</script>
子组件Child.vue用props进行接收从父组件传递过来的值,代码如下:
<template>
<div>
<h5>hello,我是子组件</h5>
<div>
标题:<b>{{ ctitle }}</b>
</div>
<div>
介绍:<b>{{ cmsg }}</b>
</div>
<div>
数字:<b>{{ cnum }}</b>
</div>
<div>
列表内容:<b>{{ clist }}</b>
</div>
</div>
</template>
<script>
export default {
name: "Child",
data() {
return {};
},
// 子组件设置props属性,接收从父组件传递过来的参数
// props选项可以写成数组形式,也可以写成对象形式。
// props选项写成对象,有很多好处,比如:类型限制、默认值、必传值等。
props: {
ctitle: {
type: String,
//默认值只有在不传值的时候起作用
default: "默认标题",
},
cmsg: {
type: String,
default: "默认介绍",
},
cnum: {
type: Number,
default: 0,
},
clist: {
type: Array,
//注意:数组和对象的default默认值必须是一个函数,并且都需要有return
default() {
return [1, 2, 3, 4];
},
},
},
methods: {},
};
</script>
<style>
b {
color: #6db6fa;
}
</style>
注意:数组和对象的default默认值必须是一个函数,并且都需要有return。
场景1:父组件不传递值,子组件就会显示props中定义的默认的内容。
效果如下:
场景2:父组件传递字符串到子组件不需要使用v-bind来绑定(直接传递写死的值不需要动态绑定):
效果如下:
场景3:父组件需要利用v-bind动态绑定子组件的参数:
效果如下:
2.子传父($emit)
在子组件中,通过$emit发射自定义事件。
在父组件中,通过v-on来监听子组件的自定义事件。当监听到这个事件,在父组件的methods中进行处理就可以了。
例如:现在想写一个功能,点击子级的button按钮时,将子级的数据传递给父级,然后让父级的数据变成子级的数据。
子组件Child.vue代码如下:
<template>
<div>
<h2>hello,我是子组件</h2>
<button @click="sendData">传递数据</button>
</div>
</template>
<script>
export default {
name: "Child",
data() {
return {
// 将childData传递给父组件
childData: " I am Child-data",
};
},
methods: {
sendData() {
// 通过$emit()来触发/发射一个自定义事件item-click
this.$emit("item-click", this.childData);
},
},
};
</script>
父组件App.vue的代码如下:
<template>
<div id="app">
<h2>Hi,我是父组件</h2>
<h3>{{ childData }}</h3>
<!-- 子父组件中,通过v-on来监听子组件发射的自定义事件;
当监听到这个事件,在父组件的methods中进行处理就可以了 。
-->
<hr />
<child @item-click="changeData"></child>
</div>
</template>
<script>
// 引入子组件
import Child from "./components/Child.vue";
export default {
name: "App",
// 注册组件
components: {
Child,
},
data() {
return {
childData: "I am Father-data",
};
},
methods: {
// 定义changeData方法
changeData(childData) {
this.childData = childData;
},
},
};
</script>
过程分析:
- 子组件如果想给父组件传递数据,需要发射emit一个事件,并且这个事件是需要自定义的。
- 之后,需要在父组件中使用子组件标签时,在这里监听这个自定义事件。
- 当监听到这个事件,去父组件的methods中处理这个事件就可以了。
运行项目,进入页面查看,可以看到子组件里面的数据成功传递给了父组件。
3.非父子级传递数据(vuex的store)
在项目中的Compnents文件夹中新建两个文件User.vue和About.vue,它们不是父子组件的关系;将它们在App.vue中引入、注册并使用。
需求:在About组件中点击“修改数据”按钮,User组件的数据也会改变。
- 在项目中安装vuex:npm i vuex@3(这里是Vue2项目,需要安装指定的vuex的3版本);
- 然后,在项目新建一个文件夹store,在里面创建一个index.js文件,并在index.js文件中引入插件vuex,安装插件,创建vuex里面的store对象,导出store共享;在state中定义两个状态:counter与message。
- 接着,回到main.js中挂载;一旦在main.js中挂载store之后,那么,所有的vue组件都有一个$store对象了。
import Vue from "vue";
import App from "./App.vue";
// 引入store
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: (h) => h(App),
}).$mount("#app");
这么做,项目里面的组件就都能拿到counter和message了,直接通过 $store.state.counter和 $store.state.message来取出来直接展示index.js中的state值,如下图所示:
至此,About与User实现了数据的共享了。
- 接下来,就是实现数据传递了。那么,如何实现呢?在index.js中的mutations中定义方法EditStateMessage;
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// 创建store对象。
const store = new Vuex.Store({
// state就是保存状态
state: {
counter: 912,
message: "hello,vuex",
},
// 只要是改store里面的state,一定是通过mutation的。
// mutations中默认参数为:state。
mutations: {
EditStateMessage(state, str) {
state.message = str;
},
},
});
// 导出store对象
export default store;
在About.vue中写一个button来修改数据,并绑定点击事件changeData ,在methods中定义changeData,调用store中的EditStateMessage,后面写想要设置的值即可,这里点击即可改变数据为”hi,我是修改好的数据”。
<template>
<div>
<h2>我是About组件</h2>
<h3>{{ $store.state.counter }}</h3>
<button @click="changeData" style="background: red">
修改数据
</button>
<h3>{{ $store.state.message }}</h3>
</div>
</template>
<script>
export default {
name: "About",
data() {
return {};
},
methods: {
changeData() {
this.$store.commit("EditStateMessage", "hi,我是修改好的数据");
},
},
};
</script>
这样,就实现了非父子级关系的数据传递。
运行项目,点击“修改数据”前的页面效果如下图所示:
点击About组件的“修改数据”按钮,可以发现不仅About组建的数据会被修改,User组件也会改变数据。
4.父组件主动获取子组件的数据/方法
可以利用ref。
调用子组件的时候定义了ref=”child”(ref的命名是随意的),那么父组件想主动获取子组件的数据/方法,就利用this.$refs.child.xxx即可。
效果如下:
总结:如果给子组件上绑定一个ref=”child”,那么在父组件中就可以通过this.$refs.child.xxx获取子组件的数据和方法了。
获取子组件的数据:如果子组件的data上有个cmessage属性,那么在父组件中,可以通过this.$refs.child.cmessage来拿到子组件中的cmessage数据;
获取子组件的方法:如果子组件的methods上有个getChild()方法,那么在父组件中,可以通过this.$refs.child.getChild()来拿到子组件中的方法。
总结
以上就是今天要分享的Vue2组件通信的相关内容,欢迎大家给出意见哦~