Vue组件通信(父传子、子传父、兄弟间、祖先与子孙间)

components
   ├── Grandson1.vue // 孙子1
   ├── Grandson2.vue // 孙子2
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   └── Son2.vue     // 儿子2

一、props父传子

Parent.vue

<template>
 <div>
  父组件:{
     {
     mny}}
  <Son1 :mny="mny"></Son1>
 </div>
</template>
<script>
import Son1 from "./Son1";
export default {
     
 components: {
     
  Son1
 },
 data() {
     
  return {
      mny: 100 };
 }
};
</script>

Son1.vue

<template>
 <div>子组件1: {
     {
     mny}}</div>
</template>
<script>
export default {
     
 props: {
     
  mny: {
     
   type: Number,
   default: 1
  }
 }
};
</script>

当传递的属性过多时,可用 $attrs(在下面进行了说明)

二、$emit 子组件触发父组件事件,传值

Parent.vue

<template>
 <div>
  父组件:{
     {
     mny}}
  <Son1 :mny="mny" @input="change"></Son1>
 </div>
</template>
<script>
import Son1 from "./Son1";
export default {
     
 methods: {
     
  change(mny) {
     
   this.mny = mny;
  }
 },
 components: {
     
  Son1
 },
 data() {
     
  return {
      mny: 100 };
 }
};
</script>

Son1.vue

<template>
 <div>
  子组件1: {
     {
     mny}}
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
     
 props: {
     
  mny: {
     
   type: Number,
   default: 1
  }
 }
};
</script>

语法糖的写法:

1、.sync

用于场景:父组件传递的属性子组件想修改

<Son1 :mny.sync="mny"></Son1>
<!-- 触发的事件名 update:(绑定.sync属性的名字) -->
<button @click="$emit('update:mny',200)">更改</button>

2、v-model

等同于:value+@input事件的结合

<Son1 v-model="mny"></Son1>
<template>
 <div>
  子组件1: {
     {
     value}} // 触发的事件只能是input
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
     
 props: {
     
  value: {
      // 接收到的属性名只能叫value
   type: Number
  }
 }
};
</script>

v-model 与 .sync 的区别
两者的目的都是实现组件与外部数据的双向绑定。v-model 是 .sync 的一种体现(prop是valuevm.$emit('update:input'))。
v-model只能在表单元素像单选框/输入框等类型的控件中实现双向绑定,但是如果用在一个组件上,就无法实现双向绑定,因为从本质上说,他就是绑定value值,监听input事件,总的来说,v-model 倾向于 ‘value’。.sync 倾向于 ‘change’,是父组件获取子组件状态的一种快捷方式,是一种update操作,事件名称也相对固定 update:xx

三、兄弟组件间的传值

1、路由URL参数

将要传递的数据放到URL后面,跳转到另外的组件时直接获取url字符串获取想要的参数。

// router index.js 动态路由
{
     
   path:'/params/:Id',
   component:Params,
   name:Params
}
// 跳转路由
<router-link :to="/params/10">跳转路由</router-link>

在跳转后的组件中用$route.params.id去获取到这个id参数为10,但这种只适合传递比较小的数据,数字之类的。

2、Bus通信

在组件之外定义一个bus.js 作为组件间通信的桥梁,适用于比较小型不需要vuex 又需要兄弟组件通信的
1、bus.js中添加

import Vue from 'vue'
export default new Vue

2、组件中调用bus.js通过自定义事件传递数据

import Bus from './bus.js'
export default {
     
	methods:{
     
		bus () {
     
			Bus.$emit('msg', '传给兄弟组件的')
		}
	}
}

3、兄弟组件中监听事件接受数据

import Bus from './bus.js'
export default {
     
	mounted () {
     
		Bus.$on('msg', (e) => {
     
			console.log(e)
		})
	}
}

3、vuex集中状态管理

vuex是vue的集中状态管理工具,对于大型应用统一集中管理数据

规范:

  • vuex分模块:项目不同模块间维护各自的vuex数据;
  • 限制使用:只允许action 操作数据,getters 获取数据,使用mapGetters、mapActions辅助函数调用数据;

四、祖先组件与子组件间传值

1、利用parent / children

继续将属性传递
Parent.vue中

<Son1 :mny="mny" @input="mny => this.mny = mny"></Son1>

Son1.vue中

<Grandson1 :value="value"></Grandson1>

Grandson1.vue

<template>
 <div>
  孙子:{
     {
     value}}
  <!-- 调用父组件的input事件 -->
  <button @click="$parent.$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
     
 props: {
     
  value: {
     
   type: Number
  }
 }
};
</script>

如果有很多父级,即层级很深,parent.parent… ,那么可以封装一个$dispatch 方法向上进行派发

$dispatch

Vue.prototype.$dispatch = function (eventName, value) {
     
	let parent = this.$parent;
	while (parent) {
     
		parent.$emit(eventName, value)
		parent = parent.$parent
	}
}

Grandson1.vue

<button @click="$dispatch('input', 200)">更改儿子1 value数据</button> // 此刻的input其实为parent.vue中的

既然能够向上派发也能向下派发

$broadcast

// 向下派发
Vue.prototype.$broadcast = function broadcast(componentName, eventName, data) {
     
	this.$children.forEach((child) => {
     
		const name = child.$options.name
		console.log(name)
		// 组件名与传入componentName一致
		if (name === componentName) {
     
			// 子组件触发eventName事件
			child[eventName](data)
		} else {
     
			broadcast.call(child, eventName, data) // eslint-disable-line
		}
	})
}

Grandson1.vue

孙子的年龄:{
     {
     age}}
export default {
     
	data() {
     
		return {
     
			age: 10
		}
	},
	methods: {
     
		broadcastTest (val) {
     
			this.$nextTick(() => {
     
				alert(val)
				this.age = val
			})
		}
	}
}

Son1.vue

<button @click="$broadcast('Grandson1','broadcastTest', 19)">更改孙子年龄</button>

2、利用attrs、listeners

$attrs

批量向下传入属性

<Son2 name='Tom' age='19'></Son2>

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

<!--- Grandson2.vue -->
<template>
	<div>
		孙子:{
     {
     $attrs}}
	</div>
</template>

Vue组件通信(父传子、子传父、兄弟间、祖先与子孙间)_第1张图片

$listeners

批量向下传方法

<Son2 name='AA' age='19' @click='() => {this.mny = 500}'></Son2>
<!-- 可以在son2组件中使用listeners属性,可以将方法继续向下传递 -->
<Grandson2 v-bind='$attrs' v-on='$linsteners'></Grandson2>

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

3、Provide、Inject

只需要向后台注入组件本身,后代组件中可以无视层级任意访问组件中的状态。

Provide

在父级中注入数据
Son2.vue

provide () {
     
	return {
     parentMsg: '这是儿子2'}
}

之后在想调用的子组件中使用用 inject 引入。

Inject

在任意子组件中可以注入父级数据
Grandson2.vue

<p>动态设置的son2的值然后传入到孙子的值: {
     {
     parentMsg}}</p>

export default {
     
	inject: ['parentMsg'] // 会将数据挂载到当前实例上
}

实际上,可以把依赖注入看做一部分"大范围有效的prop",除了:
1、祖先组件不需要知道哪些后代组件使用它提供的属性
2、后代组件不需要知道被注入的属性来自哪里

提示:provide 和 inject 绑定并不是可响应的。然而如果传入的是一个可监听的对象,那么其对象的属性还是可响应的

你可能感兴趣的:(vue,vue,sync)