Vue组件通讯方式记录

1、父组件向子组件传值

组件是 vue.js 最强大的功能之一,而组件实例的做用域是相互独立的,这就意味着不一样组件之间的数据没法相互引用。那么组件间如何通讯,也就成为了vue中重点知识了, 下面是我整理的组件之间传值问题.javascript

1.经过props进行通讯

props是用于父组件向子组件传递数据信息(props是单向绑定的,即只能父组件向子组件传递,不能反向)html

(1)静态传递

子组件经过props选项来声明一个自定义的属性,而后父组件就能够在嵌套标签的时候,经过这个属性往子组件传递数据了。vue

<!-- 父组件 -->

<template>
  <div>
    <h1>我是父组件!</h1>
    <child message="我是子组件一!"></child>  //经过自定义属性传递数据
  </div>
</template>

<script> import Child from '../components/child.vue' export default { components: {Child}, } </script>
复制代码
<!-- 子组件 -->

<template>
  <h3>{{message}}</h3>
</template>
<script> export default { props: ['message'] //声明一个自定义的属性 } </script>
复制代码

(2)动态传递java

咱们已经知道了能够像上面那样给 props 传入一个静态的值,可是咱们更多的状况须要动态的数据。这时候就能够用 v-bind 来实现。经过v-bind绑定props的自定义的属性,传递去过的就不是静态的字符串了,它能够是一个表达式、布尔值、对象等等任何类型的值。vuex

<!-- 父组件 -->

<template>
  <div>
    <h1>我是父组件!</h1>
    <child message="我是子组件一!"></child> 

    <!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
    <child v-bind:message="a+b"></child>

    <!-- 用一个变量进行动态赋值。-->
    <child v-bind:message="msg"></child>
  </div>
</template>

<script> import Child from '../components/child.vue' export default { components: {Child}, data() { return { a:'我是子组件二!', b:112233, msg: '我是子组件三!'+ Math.random() } } } </script>
复制代码
<!-- 子组件 -->
<template>
  <h3>{{message}}</h3>
</template>
<script> export default { props: ['message'] } </script>
复制代码

2.经过$ref 实现通讯

对于ref官方的解释是:ref 是被用来给元素或子组件注册引用信息的。引用信息将会注册在父组件的 $refs 对象上。
看不懂对吧?很正常,我也看不懂。那应该怎么理解?看看个人解释:
后端

  • 若是ref用在子组件上,指向的是组件实例,能够理解为对子组件的索引,经过$ref可能获取到在子组件里定义的属性和方法。
  • 若是ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,经过 $ref 可能获取到该DOM 的属性集合,轻松访问到DOM元素,做用与JQ选择器相似。

那如何经过$ref 实现通讯?下面我将上面prop实现的功能,用$ref实现一遍:数组

<!-- 父组件 -->

<template>
  <div>
    <h1>我是父组件!</h1>
    <child ref="msg"></child>
  </div>
</template>

<script> import Child from '../components/child.vue' export default { components: {Child}, mounted: function () { console.log( this.$refs.msg); this.$refs.msg.getMessage('我是子组件一!') } } </script>
复制代码
<!-- 子组件 -->

<template>
  <h3>{{message}}</h3>
</template>
<script> export default { data(){ return{ message:'' } }, methods:{ getMessage(m){ this.message=m; } } } </script>
复制代码

从上面的代码咱们能够发现,经过ref=‘msg’能够将子组件child的实例指给$ref,而且经过.msg.getMessage()调用到子组件的getMessage方法,将参数传递给子组件。下面是“ console.log( this.$refs.msg);”打印出来的内容,这可让你们更加了解,究竟经过ref咱们获取了什么:app

这里再补充一点就是,prop和$ref之间的区别:

  • prop 着重于数据的传递,它并不能调用子组件里的属性和方法。像建立文章组件时,自定义标题和内容这样的使用场景,最适合使用prop。
  • $ref 着重于索引,主要用来调用子组件里的属性和方法,其实并不擅长数据传递。并且ref用在dom元素的时候,能使到选择器的做用,这个功能比做为索引更常有用到。

3.经过$emit 实现通讯

上面两种示例主要都是父组件向子组件通讯,而经过$emit 实现子组件向父组件通讯。 对于$emit官网上也是解释得很朦胧,我按我本身的理解是这样的: vm.$emit( event, arg )
$emit 绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件经过@event监听并接收参数。dom

<!--父组件-->
<template>
  <div>
    <h1>{{title}}</h1>
    <child @getMessage="showMsg"></child>
  </div>
</template>

<script> import Child from '../components/child.vue' export default { components: {Child}, data(){ return{ title:'' } }, methods:{ showMsg(title){ this.title=title; } } } </script>

复制代码
<!--子组件-->
<template>
  <div>
    <h1>{{title}}</h1>
    <child @getMessage="showMsg"></child>
  </div>
</template>

<script> import Child from '../components/child.vue' export default { components: {Child}, data(){ return{ title:'' } }, methods:{ showMsg(title){ this.title=title; } } } </script>
复制代码

2、子组件向父组件传递数据和方法

vue是禁止子组件直接向父组件传值的,因此只能经过触发事件来达到目的.异步

1. 子组件向父组件传递数据

子组件定义一个自定义方法,方法中经过this.$emit('方法名',传递数据1,传递数据2)方式发送数据,父组件监听自定义事件,当事件触发时,执行函数,进行传值 子组件 childC.vue

<!--子组件-->
<template>
  <div id="childC">
    <h3>我是子组件</h3>
    {{data}}
    <button @click="clickEvent">点击传值</button>
  </div>
</template>
<script> export default { data () { return { data: '子组件传递数据' } }, methods: { clickEvent () { this.$emit('sendValueToParent', this.data) } }, } </script>
复制代码

父组件 app.vue

<!--父组件-->
<template>
  <div id="app">
    父组件数据:{{name}}
    <!-- 经过子组件定义的事件来接收-->
    <child-c @sendValueToParent="getValue"></child-c>
  </div>
</template>
<script> import childC from './childC' export default { name: 'app', data () { return { name: '父组件' } }, components: { childC }, methods: { getValue (data) { this.name = data } }, } </script>
复制代码

2. 子组件向父组件传递方法

  1. 子组件定义方法
alert2 (){
    alert('这是子组件方法')
}
复制代码
  1. 在父组件引用子组件标签中添加标识符,rel是语法,childM是标识
<!--引用子组件的标签-->
<child-c ref="childM"></child-c>
复制代码
  1. 父组件定义一个方法,调用方法就是标识为 childM 的子组件里的 alert2 方法
fn1(){
    <!--childM: 在引用子组件标签中自定义的标识-->
    <!--alert2(): 子组件中自定义方法的名称-->
    this.$refs.childM.alert2()
}
复制代码
  1. 在组建中调用父组件中定义的方法
<button @click="fn">调用</button>
复制代码

3、兄弟组件通讯

方式1 : 借助中央事件总线思想:

  1. 在外部新建一个js文件,取名Bug.js,可放在assets文件目录下.
<!--新建 Vue 实例并导出-->
import Vue from 'vue'
export default new Vue()
复制代码
  1. 在两个组件的公共父组件中引入须要通讯的组件
  2. 两个须要通讯的组件同时引入Bus.js文件
import Bus from './Bus'
复制代码
  1. 传递数据的组件须要定义一个发送数据的方法,此处 sendMsg 是定义在此的方法,页面点击时触发此函数,经过 $emit 发送一个 send 事件, send为自定义事件名称.
<template>
     <!--点击传递数据-->
    <button @click="fn">点击传值</button>
 </template>
<script> import Bus from './Bus' export default { data () { return { msg:'数据' } }, methods: { fn(){ <!--Bus.$emit(事件名,数据);--> Bus.$emit('send',this.msg) } } } </script>

复制代码
  1. 接受数据的组件在 data 中先声明一个变量,在钩子函数 created 中,经过Bus中央事件总线用 $on 监听组件1中发送的 send事件,用一个带参数的回调函数,接收传过来的值,把值赋给data中的变量.
<template>
     {{value}}
 </template>
<script> import Bus from './Bus' export default { data () { return { value:'1111' } }, created() { <!-- Bus.$on(事件名,data => {});--> Bus.$on('send',data => { this.value = data }) } } </script>
复制代码

方式2 : 方式1简化版

  1. 省略外部的js文件,将总线放在 main.js 入口文件里的 vue 实例中
new Vue({
    el: '#app',
    router,
    data:{
        Bus: new Vue()
    },
    template: '<App/>',
    components: { App }
})
复制代码
  1. 在使用的时候,不须要引入外部文件,只须要在Bus前加this.$root,便可调用.
<!--传递数据的组件-->
methods: {
    sendMsg() {
        this.$root.Bus.$emit('send',this.msg);
    }
}
复制代码
<!--接收数据的组件-->
created() {
    this.$root.Bus.$on('send',data=> {
        this.value = data
    })
}
复制代码

4、vuex

1. 简要理解 Vue 原理

Vuex 实现了一个单向数据流,在全局拥有一个 State 存放数据,当组件要更改 State 中的数据时, 必须经过 Mutation 进行, Mutation 同时提供了订阅者模式供外部插件获取 State 数据的更新.而当全部异步操做(常见于调用后端接口异步获取更新数据)或批量的同步操做须要走 Action ,但 Action 也是没法直接修改 State 的,仍是须要经过 Mutation 来修改 State 的数据.最后,根据 State 的变化,渲染到视图上.

2. 简要介绍各模块在流程中的功能:

  • Vue Components: Vue 的组件.负责接收用户操做等交互行为,执行 dispatch 方法触发对应的 action 进行回应.
  • dispatch: 操做行为触发方法,是惟一能执行的 action 的方法.
  • actions: 操做行为处理模块,由组件中的 $store.dispatch('action 名称', data1)来触发,而后由 commit() 来触发调用,间接更新 state.负责处理 Vue Components 接收到的全部交互行为.包含同步/异步操做,支持多个同名方法,按照注册的顺序依次触发.向后台 API 请求的操做就在这个模块中进行,包括触发其余 action 以及提交 mutation 的操做.该模块提供了Promise 的封装,以支持 action 的链式触发.
  • commit: 状态改变提交操做方法.对mutation 进行提交,是惟一能执行 mutation 的方法.
  • mutations 状态改变操做方法,由 actions 中的 commit('mutation 名称') 来触发. 是Vuex修改 state 的惟一推荐方法.该方法只能进行同步操做,且方法名只能全局惟一.操做之中会有一些 hook 暴露出来,以进行 state 的监控等.
  • state: 页面状态管理容器对象.集中存储 Vue components 中data 对象的零散数据,全局惟一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用 Vue 的细粒度数据响应机制来进行高效的状态更新。
  • getters: state 对象读取方法. Vuex流程图中没有单独列出该模块,应该被包含在了 render 中, Vue Components 经过该方法读取全局 state 对象.

3. Vuex 与 localStorage

vuex 是 vue 的状态管理器,存储的数据是响应式的。可是并不会保存起来,刷新以后就回到了初始状态,具体作法应该在 vuex 里数据改变的时候把数据拷贝一份保存到 localStorage 里面,刷新以后,若是 localStorage 里有保存的数据,取出来再替换 store 里的 state。

let defaultCity = "上海"
try {   // 用户关闭了本地存储功能,此时在外层加个try...catch
  if (!defaultCity){
    defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
  }
}catch(e){}
export default new Vuex.Store({
  state: {
    city: defaultCity
  },
  mutations: {
    changeCity(state, city) {
      state.city = city
      try {
      window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
      // 数据改变的时候把数据拷贝一份保存到localStorage里面
      } catch (e) {}
    }
  }
})
复制代码

这里须要注意的是:因为 vuex 里,咱们保存的状态,都是数组,而 localStorage 只支持字符串,因此须要用 JSON 转换:

// array -> string
JSON.stringify(state.subscribeList); 
// string -> array
JSON.parse(window.localStorage.getItem("subscribeList"));    
复制代码
相关文章
相关标签/搜索