vue数据通信

数据通信在我们开发过程中遇到的频率是相当的多,特别是现在主流的单页面、多组件的开发方式。项目开发周期长,功能复杂,页面多。这种情况下我们需要借助模块化、组件化的方式进行开发,一是能够复用代码,可维护性高,二是能够协同开发,互不干扰,提升开发效率。这样的开发模式必然会存在大量的数据通信,比如父子组件之间的通信,又或者是毫不关系的两个组件之前需要进行数据的通信,还有全局数据的传递及使用等等。我把vue中数据通信的几种方式总结入下。

图片

父组件向子组件传递数据

父组件向子组件传递数据的方法是父组件通过属性的方式向子组件传递,子组件通过prop接收。下面我们来看一下代码。

// 父组件
<template>
  <div class="container">
    <child :title="title"></child>
  </div>
</template>

<script>
import Child from "./component/child.vue";
export default {
  name: "demo",
  data: function() {
    return {
      title: "我是父组件给的"
    };
  },
  components: {
    Child
  },
};
</script>


// 子组件

<template>
  <div class="text">{{title}}</div>
</template>

<script>
export default {
  name: 'demo',
  data: function() {},
  props: {
    title: {
      type: String
    }
  },
};
</script>

子组件向父组件传递数据

子组件向父组件传递数据是通过事件的形式,子组件通过 $emit 事件向父组件发送消息,将自己的数据传递给父组件。

// 父组件
<template>
  <div class="container">
    <div class="title">{{title}}</div>
    <child @changeTitle="parentTitle"></child>
  </div>
</template>

<script>
import Child from "./component/child.vue";

export default {
  name: "demo",
  data: function() {
    return {
      title: null
    };
  },
  components: {
    Child
  },
  methods: {
    parentTitle(e) {
      this.title = e;
    }
  }
};
</script>


// 子组件
<template>
  <div class="center">
    <button @click="childTitle">我给父组件赋值</button>
  </div>
</template>

<script>
export default {
  name: 'demo',
  data() {
    return {
      key: 1
    };
  },
  methods: {
    childTitle() {
      this.$emit('changeTitle', `我给父组件的第${this.key}次`);
      this.key++;
    }
  }
};
</script>

事件监听的方式传递数据

这个方法是通过创建了一个空的 vue 实例,当做 $emit 事件的处理中心(事件总线),通过他来触发以及监听事件,方便的实现了任意组件间的通信,包含父子,兄弟,隔代组件。

// 父组件
<template>
  <div class="container">
    <child1 :Event="Event"></child1>
    <child2 :Event="Event"></child2>
    <child3 :Event="Event"></child3>
  </div>
</template>

<script>
import Vue from "vue";

import Child1 from "./component/child1.vue";
import Child2 from "./component/child2.vue";
import Child3 from "./component/child3.vue";

const Event = new Vue();

export default {
  name: "demo",
  data: function() {
    return {
      Event: Event
    };
  },
  components: {
    Child1,
    Child2,
    Child3
  },
};
</script>

// 子组件1
<template>
  <div class="center">
    1.我的名字是:{{name}}
    <button @click="send">我给3组件赋值</button>
  </div>
</template>

<script>
export default{
  name: "demo1",
  data() {
    return {
      name: "gewen"
    };
  },
  props: {
    Event
  },
  methods: {
    send() {
      this.Event.$emit("message-a", this.name);
    }
  }
};
</script>

// 子组件2
<template>
  <div class="center">
    2.我的年龄是:{{age}}岁
    <button @click="send">我给3组件赋值</button>
  </div>
</template>

<script>
/* eslint-disable */
export default {
  name: "demo2",
  data() {
    return {
      age: "3"
    };
  },
  props: {
    Event
  },
  methods: {
    send() {
      this.Event.$emit("message-b", this.age);
    }
  }
};
</script>

// 子组件3
<template>
  <div class="center">我的名字是{{name}},今年{{age}}岁</div>
</template>

<script>
export default{
  name: 'demo3',
  data() {
    return {
      name: '',
      age: ''
    };
  },
  props: {
    Event
  },
  mounted() {
    this.Event.$on('message-a', name => {
      this.name = name;
    });
    this.Event.$on('message-b', age => {
      this.age = age;
    });
  },
};
</script>

vuex

Vuex 实现了一个单项数据流,通过创建一个全局的 State 数据,组件想要修改 State 数据只能通过 Mutation 来进行,例如页面上的操作想要修改 State 数据时,需要通过 Dispatch (触发 Action ),而 Action 也不能直接操作数据,还需要通过 Mutation 来修改 State 中数据,最后根据 State 中数据的变化,来渲染页面。

Provider / Inject

Vue 2.2 版本以后新增了这两个 API , 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。 简单来说,就是父组件通过 Provider 传入变量,任意子孙组件通过 Inject 来拿到变量

// 父组件
<template>
  <div class="container">
    <button @click="this.changeName">我要改名字了</button>
    <p>我的名字:{{name}}</p>
    <child1></child1>
  </div>
</template>

<script>
import Child1 from './component/child1.vue';
export default {
  name: 'demo',
  data: function() {
    return {
      name: 'gewen'
    };
  },
  // provide() {
  //   return {
  //     name: this.name //这种绑定方式是不可响应的
  //   };
  // },
  provide() {
    return {
      obj: this
    };
  },
  components: {
    Child1
  },
  methods: {
    changeName() {
      this.name = 'gewen前端';
    }
  }
};
</script>


// 子组件
<template>
  <div>
    <div class="center">
      <!-- <p>子组件名字:{{name}}</p> -->
      <p>子组件名字:{{this.obj.name}}</p>
    </div>
    <child2></child2>
  </div>
</template>

<script>
import child2 from './child2.vue';

export default {
  name: 'demo1',
  data() {
    return {};
  },
  props: {},
  // inject: ["name"],
  inject: {
    obj: {
      default: () => {
        return {};
      }
    }
  },
  components: {
    child2
  },
};
</script>

需要注意的是: Provide 和 Inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

所以,如果采用的是我代码中注释的方式,父级的 name 如果改变了,子组件this.name 是不会改变的,仍然是 gewen ,而当采用代码中传入一个监听对象,修改对象中属性值,是可以监听到修改的。

Provider / Inject 在项目中需要有较多公共传参时使用还是颇为方便的。

parentchildren $refs

parent /children: 指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用 this.parent 访问父实例,子实例被推入父实例的children 数组中。

refs: 一个对象,持有注册过 ref 特性[3] 的所有 DOM 元素和组件实例。ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件。

// 父组件
<template>
  <div class="container">
    <p>我的title:{{title}}</p>
    <p>我的name:{{name}}</p>
    <child1 ref="comp1"></child1>
    <child2 ref="comp2"></child2>
  </div>
</template>

<script>
import Child1 from './component/child1.vue';
import Child2 from './component/child2.vue';
export default {
  name: 'demo',
  data: function() {
    return {
      title: null,
      name: null,
      content: '就是我'
    };
  },
  components: {
    Child1,
    Child2
  },
  mounted() {
    const comp1 = this.$refs.comp1;
    this.title = comp1.title;
    comp1.sayHello();
    this.name = this.$children[1].title;
  },
};
</script>


// 子组件1-ref方式
<template>
  <div>
    <div class="center">我的父组件是谁:{{content}}</div>
  </div>
</template>

<script>
export default {
  name: 'demo1',
  data() {
    return {
      title: '我是子组件',
      content: null
    };
  },
  mounted() {
    this.content = this.$parent.content;
  },
  methods: {
    sayHello() {
      window.alert('Hello');
    }
  }
};
</script>


// 子组件2-children方式
<template>
  <div>
    <div class="center"></div>
  </div>
</template>

<script>
export default{
  name: 'demo1',
  data() {
    return {
      title: '我是子组件2'
    };
  },
};
</script>

通过例子可以看到这两种方式都可以父子间通信,而缺点也很统一,就是都不能跨级以及兄弟间通信。

总结

组件间不同的使用场景可以分为 3 类,对应的通信方式如下:

• 父子通信:Props / emit,emit / on,Vuex,attrs / listeners,provide/inject,parent / children&refs

• 兄弟通信:emit /on,Vuex

• 隔代(跨级)通信:emit /on,Vuex,provide / inject,attrs /listeners

大家可以根据自己的使用场景选择不同的通信方式,当然还是都自己写写代码,加深印象

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容