Vue组件间 8 种通信方式

Vue组件间 8 种通信方式

优先使用 Vuex

其次 props & $emit

再次 $parent, $children, Vue原型上挂载方法 $dispatch, $broadcast

常用的还有 VueRouter 的 $router, $route 传值

  1. 父子组件通信
  props & $emit()

  $parent & $children
    $parent 是个对象,Object
    $children 是个数组,Array

  ref

  1. 跨层级组件通信
  Vuex
  
  provide & inject

  $attrs & $listeners

  $dispatch & $broadcast

  $router

  localStorage

  Vue.prototype.$bus = new Vue() // 不推荐使用

快速原型开发

  • 可以快速识别 .vue 文件封装组件插件等功能
  sudo npm install @vue/cli -g
  sudo npm install -g @vue/cli-service-global
  vue serve App.vue

1 props 传递数据

  • 单向数据流:数据只能通过 props 由父组件流向子组件
  • 子组件不能修改 props 传来的数据
  • 防止从子组件意外改变父级组件的状态,导致你的应用的数据流向难以理解
    • 每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值
    • $emit() 派发事件来修改父级数据
  • Vue 组件通信
components
   ├── Grandson1.vue // 孙子1
   ├── Grandson2.vue // 孙子2
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   └── Son2.vue     // 儿子2
  1. 在父组件中使用儿子组件
<template>
  <div>
    父组件:{{value}}
    <Son1 :value="value"></Son1>
  </div>
</template>

<script>
import Son1 from "./Son1"

export default {
  components: {
    Son1
  },
  data() {
    return { value: 100 }
  }
}
</script>

  1. 子组件接受父组件的属性
<template>
  <div>子组件1: {{value}}</div>
</template>

<script>
export default {
  props: {
    value: {
     type: Number
    }
  }
}
</script>

2 $emit() 派发事件

  1. 子组件触发父组件方法,通过回调的方式将修改的内容传递给父组件
<template>
 <div>
  父组件:{{value}}
  <Son1 :value="value" @input="change"></Son1>
 </div>
</template>

<script>
import Son1 from "./Son1"

export default {
  methods: {
    change(val) {
      this.value = val;
    }
  },
  components: {
    Son1
  },
  data() {
    return { value: 100 }
  }
}
</script>

  1. 子组件触发绑定自己身上的方法
<template>
 <div>
  子组件1: {{value}}
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>

<script>
export default {
  props: {
    value: {
      type: Number
    }
  }
}
</script>

.sync

这里的主要目的就是同步父子组件的数据,->语法糖的写法

  • 子组件 方法必须是 update:value
<Son1 :value.sync="value"></Son1>
<!-- 触发的事件名 update:(绑定.sync属性的名字) -->
<button @click="$emit('update:value',200)">更改</button>

v-model

  • 值必须是 value
  • 数据同步,优先使用 v-model,其次用 .sync, 再次用事件
<Son1 v-model="value"></Son1>
<template>
 <div>
  子组件1: {{value}} // 触发的事件只能是input
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>

<script>
export default {
  props: {
    value: { // 接收到的属性名只能叫value
      type: Number
    }
  }
}
</script>

3 $parent & $children

如果层级很深那么就会出现 p a r e n t . parent. parent.parent…

  • 我们可以封装一个 $dispatch 方法向上进行派发
  • 继续将属性传递
<template>
 <div>
  孙子:{{value}}
  <!-- 调用父组件的input事件 -->
  <button @click="$parent.$emit('input',200)">更改</button>
  <Grandson1 :value="value"></Grandson1>
 </div>
</template>

<script>
export default {
  props: {
    value: {
      type: Number
    }
  }
}
</script>

$dispatch

  • 把这个方法挂载 Vue的原型上
// 向上通知父组件
Vue.prototype.$dispatch = function $dispatch(eventName, data) {
  let parent = this.$parent
  while (parent) {
    parent.$emit(eventName, data)
    parent = parent.$parent
  }
}

  • 组件调用
  this.$parent.$emit('change-parent', 666)

  // $dispatch 派发事件
  this.$dispatch('change-parent', 666)

$broadcast

  • 既然能向上派发那同样可以向下进行派发
// 向下传递 子组件传递
Vue.prototype.$broadcast = function (eventName, data) {
  const broadcast = function () {
    this.$children.forEach((child) => {
      child.$emit(eventName, data);
      if (child.$children) {
        $broadcast.call(child, eventName, data)
      }
    })
  }
  broadcast.call(this, eventName, data)
}

  • 组件调用
mounted () {
  // 触发组件上的 @on-say 事件
  // this.$broadcast('on-say', this.arr)
}

<el-button type="primary" @on-say="fnChild">on-say</el-button>

4 $attrs & $listeners

$attrs 向下传入属性

  • v-bind="$attrs"
<Son2 name="小珠峰" age="10"></Son2>

<!-- 可以在son2组件中使用$attrs属性,可以将属性继续向下传递 -->
<div>
  儿子2: {{$attrs.name}}
  <Grandson2 v-bind="$attrs"></Grandson2>
</div>

<template>
 <div>孙子:{{$attrs}}</div>
</template>

$listeners 向下传入方法

  • v-on="$listeners"
<Son2 name="小珠峰" age="10" @click="()=>{this.value = 500}"></Son2>

<!-- 可以在son2组件中使用listeners属性,可以将方法继续向下传递 -->
<Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2>

<button @click="$listeners.click()">更改</button>

5 Provide & Inject

  • provide 原理: 在当前的实例上 vm._prvoide
  • inject:vm.$parent._prvoide

provide 在父级中注入数据

provide() {
  return { parent: this }
}

Inject

  • 在任意子组件中可以获取父级数据
inject: ["parent"] // 会将数据挂载在当前实例上

6 ref使用

  • 获取组件实例,放在组件上,就是获取当前组件
  • 获取 DOM,放在标签上就是获取 DOM
<Grandson2 v-bind="$attrs" v-on="$listeners" ref="grand2"></Grandson2>

mounted() { // 获取组件定义的属性
  console.log(this.$refs.grand2.name);
}

7 EventBus

  • 用于跨组件通知(不复杂的项目可以使用这种方式)
    • 两个组件不是父子关系
  • 不推荐使用,用 Vuex 代替
// Vue的实例上有 $on & $emit 等方法,相当于把Vue的实例暴露在全局上
// 所有组件都可以用这些方法
// 缺点:事件重名会覆盖,不好定位错误
// Vue.prototype.$bus = new Vue()
Vue.prototype.$bus = new Vue()

// $bus.$emit() 触发事件
this.$bus.$emit('on-change', val)

// $bus.$on() 监听触发的事件
this.$bus.$on('on-change', (val) => {
  this.value = val
})

  1. Son2组件和Grandson1相互通信
mounted() {
  this.$bus.$on("my", data => {
    console.log(data);
  })
}

mounted() {
  this.$nextTick(() => {
    this.$bus.$emit("my", "我是Grandson1");
  })
}

8 Vuex通信

  • 状态管理

Vuex 数据管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值