vue组件通信

参照博客:https://www.jianshu.com/p/7df2576a8a2b

方法一、prop和$emit

1.prop--父组件向子组件传值

a.prop大小写: postTitle 等价于 post-title;

b.prop类型:

  以数组形式:

1 props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

  以对象形式:(通常你希望每个 prop 都有指定的值类型)

1 props: {
2   title: String,
3   likes: Number,
4   isPublished: Boolean,
5   commentIds: Array,
6   author: Object,
7   callback: Function,
8   contactsPromise: Promise // or any other constructor
9 }

c.传递静态或者动态prop

1 <!-- 静态赋值 -->
2 <blog-post title="My journey with Vue"></blog-post>
3 <!-- 动态赋予一个变量的值 -->
4 <blog-post v-bind:title="post.title"></blog-post>
5 <!-- 动态赋予一个复杂表达式的值 -->
6 <blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>

d.传递的数据可以是字符串、数组、数字、对象、布尔值

 1 //父组件
 2 <template>
 3   <div id="app">
 4     <users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名
 5   </div>
 6 </template>
 7 <script>
 8 import Users from "./components/Users"
 9 export default {
10   name: 'App',
11   data(){
12     return{
13       users:["Henry","Bucky","Emily"]
14     }
15   },
16   components:{
17     "users":Users
18   }
19 }
 1 //子组件
 2 <template>
 3   <div class="hello">
 4     <ul>
 5       <li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面
 6     </ul>
 7   </div>
 8 </template>
 9 <script>
10 export default {
11   name: 'HelloWorld',
12   props:{
13     users:{           //这个就是父组件中子标签自定义名字
14       type:Array,
15       required:true
16     }
17   }
18 }
19 </script>

2.$emit--子组件向父组件传值(通过事件形式)

 1 // 子组件
 2 <template>
 3   <header>
 4     <h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
 5   </header>
 6 </template>
 7 <script>
 8 export default {
 9   name: 'app-header',
10   data() {
11     return {
12       title:"Vue.js Demo"
13     }
14   },
15   methods:{
16     changeTitle() {
17       this.$emit("titleChanged","子向父组件传值");//自定义事件  传递值“子向父组件传值”
18     }
19   }
20 }
21 </script>
 1 // 父组件
 2 <template>
 3   <div id="app">
 4     <app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致
 5    // updateTitle($event)接受传递过来的文字
 6     <h2>{{title}}</h2>
 7   </div>
 8 </template>
 9 <script>
10 import Header from "./components/Header"
11 export default {
12   name: 'App',
13   data(){
14     return{
15       title:"传递的是一个值"
16     }
17   },
18   methods:{
19     updateTitle(e){   //声明这个函数
20       this.title = e;
21     }
22   },
23   components:{
24    "app-header":Header,
25   }
26 }
27 </script>

总结:子组件通过 events 给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。

方法二、$parent和 $children与 ref

ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例。

$parent / $children:访问父 / 子实例。

需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。

我们先来看个用 ref来访问组件的例子:

 1 // 子组件
 2 export default {
 3   data () {
 4     return {
 5       title: '这是子组件的数据'
 6     }
 7   },
 8   methods: {
 9     sayHello () {
10       console.log('hello');
11 } 12 } 13 }
 1 // 父组件
 2 <template>
 3   <children ref="comA"></children> //首先你的给子组件做标记
 4 </template>
 5 <script>
 6   export default {
 7     mounted () {
 8       const comA = this.$refs.comA;
 9       console.log(comA.title);  // 这是子组件的数据
10       comA.sayHello();  // hello
11     }
12   }
13 </script>

 用$parent / $children直接访问组件实例

1 在父组件中
2 this.$children
3 在子组件中
4 this.$parent

方法三、vuex

参照博客:https://segmentfault.com/a/1190000015782272

1.安装vuex

1 pm install vuex --save

2.在src文件目录下新建一个名为store的文件夹,为方便引入并在store文件夹里新建一个index.js,里面的内容如下:

1 import Vue from 'vue';
2 import Vuex from 'vuex';
3 Vue.use(Vuex);
4 const store = new Vuex.Store();
5 export default store;

3.接下来,在 main.js里面引入store,然后再全局注入一下,这样一来就可以在任何一个组件里面使用this.$store了:

1 import store from './store'//引入store
2 new Vue({
3   el: '#app',
4   router,
5   store,//使用store
6   template: '<App/>',
7   components: { App }
8 })

4.配置state、getter、mutation、action

 1 import Vue from 'vue';
 2 import Vuex from 'vuex';
 3 Vue.use(Vuex);
 4  const state={   //要设置的全局访问的state对象
 5      showFooter: true,
 6      changableNum:0
 7      //要设置的初始属性值
 8    };
 9 const getters = {   //实时监听state值的变化(最新状态)
10     isShow(state) {  //承载变化的showFooter的值
11        return state.showFooter
12     },
13     getChangedNum(){  //承载变化的changebleNum的值
14        return state.changableNum
15     }
16 };
17 const mutations = {
18     show(state) {   //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
19         state.showFooter = true;
20     },
21     hide(state) {  //同上
22         state.showFooter = false;
23     },
24     newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum
25        state.changableNum+=sum;
26     }
27 };
28  const actions = {
29     hideFooter(context) {  //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性
30         context.commit('hide');
31     },
32     showFooter(context) {  //同上注释
33         context.commit('show');
34     },
35     getNewNum(context,num){   //同上注释,num为要变化的形参
36         context.commit('newNum',num)
37      }
38 };
39   const store = new Vuex.Store({
40        state,
41        getters,
42        mutations,
43        actions
44 });
45 export default store;

而在外部组件里进行全局执行actions里面方法的时候,你只需要用执行:

this.$store.dispatch('hideFooter')

或this.$store.dispatch('showFooter')

以及this.$store.dispatch('getNewNum',6) //6要变化的实参

想要获取state值:

this.$store.state

5.modules 模块化 以及 组件中引入 mapGetters、mapActions 和 mapStates的使用

因为在大多数的项目中,我们对于全局状态的管理并不仅仅一种情况的需求,有时有多方面的需求,比如写一个商城项目,你所用到的全局state可能是关于购物车这一块儿的也有可能是关于商品价格这一块儿的;像这样的情况我们就要考虑使用vuex中的 modules 模块化了,具体怎么使用modules呢?咱们继续一步一步的走:

首先,在store文件夹下面新建一个modules文件夹,然后在modules文件里面建立需要管理状态的js文件(collection.js 、footerStatus.js),既然要把不同部分的状态分开管理,那就要把它们给分成独立的状态文件了。

而对应的store文件夹下面的index.js 里面的内容就直接改写成:

 1 import Vue from 'vue';
 2 import Vuex from 'vuex';
 3 import footerStatus from './modules/footerStatus'
 4 import collection from './modules/collection'
 5 Vue.use(Vuex);
 6 export default new Vuex.Store({
 7     modules:{
 8          footerStatus,
 9          collection
10     }
11 });
 1 //collection.js
 2 const state={
 3     collects:[],  //初始化一个colects数组
 4 };
 5 const getters={
 6   renderCollects(state){ //承载变化的collects
 7     return state.collects;
 8   }
 9 };
10 const mutations={
11      pushCollects(state,items){ //如何变化collects,插入items
12         state.collects.push(items)
13      }
14  };
15 const actions={
16     invokePushItems(context,item){ //触发mutations里面的pushCollects ,传入数据形参item 对应到items
17         context.commit('pushCollects',item);
18     }
19 };
20 export default {
21      namespaced:true,//用于在全局引用此文件里的方法时标识这一个的文件名
22      state,
23      getters,
24      mutations,
25      actions
26 }
 1 //footerStatus.js
 2  const state={   //要设置的全局访问的state对象
 3      showFooter: true,
 4      changableNum:0
 5      //要设置的初始属性值
 6    };
 7 const getters = {   //实时监听state值的变化(最新状态)
 8     isShow(state) {  //承载变化的showFooter的值
 9        return state.showFooter
10     },
11     getChangedNum(){  //承载变化的changebleNum的值
12        return state.changableNum
13     }
14 };
15 const mutations = {
16     show(state) {   //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
17         state.showFooter = true;
18     },
19     hide(state) {  //同上
20         state.showFooter = false;
21     },
22     newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum
23        state.changableNum+=sum;
24     }
25 };
26  const actions = {
27     hideFooter(context) {  //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性
28         context.commit('hide');
29     },
30     showFooter(context) {  //同上注释
31         context.commit('show');
32     },
33     getNewNum(context,num){   //同上注释,num为要变化的形参
34         context.commit('newNum',num)
35      }
36 };
37 export default {
38     namespaced: true, //用于在全局引用此文里的方法时标识这一个的文件名
39     state,
40     getters,
41     mutations,
42     actions
43 }

mapState,mapGetters,mapActions的使用:首先 在需要用的 组件里面先导入 import {mapState,mapGetters,mapActions} from 'vuex';

 1 <template>
 2   <div class="children1">
 3     <button class="joinStatus" @click="invokePushItems(item)">加入收藏列 然后跳转到children2页面查看</button>
 4     <li v-for="(val,index) in arrList" :key="index">
 5       <h5>{{val.productName}}</h5>
 6       <p>{{val.price}}</p>
 7     </li>
 8   </div>
 9 </template>
10 
11 <script>
12 import {mapState,mapGetters ,mapActions} from "vuex";
13 export default {
14   name: "children1",
15   data() {
16     return {
17       item: {
18         id: "01",
19         productName: "苹果",
20         price: "1.6元/斤"
21       }
22     };
23   },
24   methods: {
25     ...mapActions("collection", [
26       //collection是指modules文件夹下的collection.js
27       "invokePushItems" //collection.js文件中的actions里的方法,在上面的@click中执行并传入实参
28     ])
29   },
30   computed: {
31     // ...mapState({  //用mapState来获取collection.js里面的state的属性值
32     //    arrList:state=>state.collection.collects
33     // }),
34     ...mapGetters("collection", {
35       //用mapGetters来获取collection.js里面的getters
36       arrList: "renderCollects"
37     })
38   }
39 };
40 </script>

 方法四、eventBus 兄弟组件通信

1.使用 eventBus 首先我们创建一个 bus.js 文件,里面的内容如下

import Vue from 'vue';  
export default new Vue(); 

2.在需要使用 eventBus 的组件中引入上面创建的 bus.js 文件。

import Bus from 'common/js/bus.js';

3.发布Bus消息的组件

Bus.$emit('getTarget', event.target);

4.接收Bus消息的组件

Bus.$on('getTarget', target => {  
    console.log(target);  
});

 5.解决多次触发在发布组件添加解绑事件

beforeDestroy () {
    bus.$off('getTarget')
},

 

posted @ 2019-10-18 10:16  PiPai  阅读(170)  评论(0编辑  收藏  举报