Vue组件通信方法汇总

本文介绍了Vue中父子组件通信的各种方式,包括v-model用于表单组件的双向绑定,.sync修饰符实现数据同步,props和$emit进行单向数据流动,以及ref/$refs、$parent/$children访问组件实例。此外,还讨论了非父子组件间通信的$root和EventBus实现。最后提到了Vuex作为状态管理工具在大型项目中的重要性。
摘要由CSDN通过智能技术生成

父子组件通信

1、v-model 指令

概念

v-model是用来在表单控件或者组件上创建双向绑定的,他的本质是 v-bindv-on 的语法糖,在一个组件上使用 v-model,默认会为组件绑定名为 valueprop 和名为 input 的事件。

语法糖

<input v-model="message" />

解析

<input v-bind:value="message" v-on:input="message= $event.target.value" />

简写

<input :value="message" @input="message= $event.target.value" />

当我们组件中的某一个 prop 需要实现上面所说的”双向绑定“时,v-model 就能大显身手了。有了它,就不需要自己手动在组件上绑定监听当前实例上的自定义事件,会使代码更简洁。

示例

下面以一个 input 组件实现的核心代码,简单介绍下 v-model 的在组件中实现动态传值:

父组件代码如下:

<template>
  <div>
    父组件:<span>{{message}}</span>
    <Child v-model="message"></Child>
  </div>
</template>
<script>
import Child from '../Child'
export default {
  components:{Child},
  data() {
    return {
      message: ''
    }
  },
}
</script>

子组件代码如下:

<template>
  <div>
    子组件:
    <input type="text" :value="currentValue"  @input="handleInput">
  </div>
</template>
<script>
export default {
  data() {
    return {
      currentValue: this.value === undefined || this.value === null || ''
    }
  },
  props: {
    value: [String, Number],
  },
  methods: {
    handleInput(event) {
      const value = event.target.value;
      this.$emit('input', value);
    },
  },
}
</script>

我们可以通过上面代码,子组件修改父组件v-model绑定的值!

实现截图如下:
在这里插入图片描述

扩展

以上这种方式实现的父子组件的v-model通信,限制了popos接收的属性名必须为value和emit触发的必须为input,这样容易有冲突,特别是在表单里面。Vue2.2.0+ 新增自定义组件的model选项,可以自定义属性(prop)和事件(event)名称,这样更加灵活也可以避免默认的 value 属性值有其它的用处

子组件代码修改如下:

<template>
  <div>
    子组件:
    <input type="text" :value="currentValue"  @input="handleInput">
  </div>
</template>
<script>
export default {
  data() {
    return {
      currentValue: this.val === undefined || this.val === null || ''
    }
  },
  // model选项用来避免冲突,prop属性用来指定props属性中的哪个值用来接收父组件v-model传递的值,
  // 例如:这里用props中的flag1来接收父组件传递的v-model值;event属性可以理解为父组件@input的别名,从而避免冲突,即emit时要提交的事件名。
  model: {
    prop: 'val',
    event: 'AnyName'
  },
  props: {
  	//定义和model的prop相同的props来接收
    val: [String, Number],
  },
  methods: {
    handleInput(event) {
      const value = event.target.value;
      this.$emit('AnyName', value);
    },
  },
}
</script>

v-model 的缺点和解决办法

  • text、textarea 使用 value 属性 与 input 事件
  • select 使用 value 与 change 事件
  • radio、checkbox 使用 checked 与 change 事件

在创建类似复选框或者单选框或者下拉框的常见组件时,v-model就不好用了。

以checkbox为例的解决办法:

<input type="checkbox" v-model="whyooms" />

可以这样解决

<input type="checkbox" :checked="status" @change="status = $event.target.checked" />

父组件:

<template>
  <div>
    父组件:<span>{{whyrooms}}</span>
    <Child v-model="whyrooms"></Child>
  </div>
</template>
<script>
import Child from '../Child'
export default {
  components:{Child},
  data() {
    return {
      whyrooms: false
    }
  },
}
</script>

子组件:

<template>
  <div>
    子组件:
    <!--这里就不用 input 了,而是 任意名称-->
    <input type="checkbox"
      @change="handleChange"
      :checked="checked"
    />
  </div>
</template>
<script>
export default {
  data() {
    return {
    }
  },
  model: {
    prop: 'checked',
    event: 'AnyName'
  },
  props: {
    checked: Boolean,
  },
  methods: {
    handleChange(event) {
      const checked = event.target.checked;
      this.$emit('AnyName', checked)
    },
  },
}
</script>

2、 .sync 修饰符

概念

.sync 修饰符在 vue 1.x 的版本中就已经提供,1.x 版本中,当子组件改变了一个带有 .sync 的 prop 的值时,会将这个值同步到父组件中的值。这样使用起来十分方便,但问题也十分明显,这样破坏了单向数据流,当应用复杂时,debug 的成本会非常高。

Vue2.3.0+ 新增,默认以 update:prop 模式触发事件,注意.sync 绑定的 prop 不能是表达式(v-bind:title.sync=“message + ‘!’”)这种绑定,只能是属性名

新的 .sync 修饰符所实现的已经不再是真正的双向绑定,它的本质和 v-model 类似,只是一种缩写。

<text-document v-bind:title.sync="doc.title"></text-document>
<!-- 是以下的简写: -->
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

示例

父组件代码:

<template>
    <div>
      <h2>父组件的值num-->{{num}}---num1-->{{num1}}</h2>
      <Child :a.sync="num " :b.sync='num1'></Child> 
    </div>
</template>
<script>
import Child from "../Child";
export default {
  data() {
    return {
      num: 10,
      num1:20
    };
  },
  components: {
    Child,
  },
};
</script>

子组件代码:

<template>
  <div>
    <h3>子组件接收的值a:{{a}}</h3>
    <h3>子组件接收的值b:{{b}}</h3>
    <button @click='change'>点击修改</button>
  </div>
</template>
<script>
export default {
  props:{
    a:{
      type:Number,
      required:true,
    },
    b:{
      type:Number,
      required:true,
    }
  },
  methods: {
    change(){
      // $emit触发update事件修改接收的值 父组件中跟着变化
      this.$emit('update:a',this.a+1)
      this.$emit('update:b',this.b+1)
    }
  }
}
</script>

效果图:
在这里插入图片描述
使用.sync 向子组件传递 多个props

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

<text-document v-bind.sync="doc"></text-document>

这样会把 doc对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

总结

父子组件中使用.sync通信,子组件用props接收传递的值(绑定的属性名自己决定) 在子组件中通过$emit方法触发’update:属性名’事件 实现父组件子组件值同时变化

$emit('update:属性名',要修改的值)

v-model 和 .sync 区别

  • 相同点

都是为了实现数据的“双向绑定”,本质上,也都不是真正的双向绑定,而是语法糖。

  • 不同点

1、v-model只能用一次;.sync可以有多个。
2、格式不同。 v-model=“num”, :num.sync=“num”

个人理解
语义区别:prop.sync表示这个子组件会修改父组件的值,v-model表示这是个表单类型的组件。

v-model一般是表单组件,绑定的是value属性,这个值的双向绑定也不是父组件和子组件的关系,而是view和model的对应关系,因为表单组件的值的变化来自于用户输入
而.sync是指父子组件之间的通信

3、props/$emit

概念

父组件通过 props 向子组件传递数据,子组件通过 $emit 和父组件通信

(1)父组件向子组件传值(props的用法)

props的特点:

  • props只能是父组件向子组件进行传值,props使得父子组件之间形成一个单向的下行绑定。子组件的数据会随着父组件的更新而响应式更新。
  • props可以显示定义一个或一个以上的数据,对于接收的数据,可以是各种数据类型,同样也可以是传递一个函数。
  • props属性名规则:若在props中使用驼峰形式,模板中标签需要使用短横线的形式来书写。
示例

父组件代码:

<template>
  <div>
    <Child :msg="msgData" :fn="myFunction"></Child> 
  </div>
</template>
<script>
import Child from "../Child";
export default {
  name: "parent",
  data() {
    return {
      msgData: "父组件数据"
    };
  },
  components: {
    Child,
  },
  methods:{
    myFunction() {
      console.log("vue");
    }
  }
};
</script>

子组件代码:

<template>
  <div>
    <h3>{{msg}}</h3>
    <button @click='fn'>点击修改</button>
  </div>
</template>
<script>
export default {
  name: "child",
  props:["msg", "fn"],
}
</script>
注意

第一:不应该在一个子组件内部改变 prop,这样会破坏单向的数据绑定,导致数据流难以理解。如果有这样的需要,可以通过 data 属性接收或使用 computed 属性进行转换。
第二:如果 props 传递的是引用类型(对象或者数组),在子组件中改变这个对象或数组,父组件的状态会也会做相应的更新,利用这一点就能够实现父子组件数据的“双向绑定”,虽然这样实现能够节省代码,但会牺牲数据流向的简洁性,令人难以理解,最好不要这样去做。想要实现父子组件的数据“双向绑定”,可以使用 v-model 或 > .sync。

更多有关props相关内容

(2)子组件向父组件传递数据($emit的用法)

$emit的特点:

  • $emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数
示例

父组件代码:

<template>
  <div>
    <Child :fruits="fruitList" @onEmitIndex="onEmitIndex"></Child>
    <p>{{currentIndex}}</p>
  </div>
</template>
<script>
import Child from "../Child";
export default {
  name: "parent",
  data() {
    return {
      currentIndex: 0,
      fruitList: ['草莓', '蓝莓', '火龙果']
    };
  },
  components: {
    Child,
  },
  methods:{
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
};
</script>

子组件代码:

<template>
  <div>
    <div v-for="(item, index) in fruits" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>
<script>
export default {
  name: "child",
  props:["fruits"],
  methods: {
    emitIndex(index) {
      this.$emit('onEmitIndex', index) // 触发父组件的方法,并传递参数index
    }
  }
}
</script>

4、ref / $refs

概念

ref 给元素或子组件注册引用信息,通过这个引用信息可以直接访问这个子组件的实例。
当父组件中需要主动获取子组件中的数据或者方法时,可以使用 $ref 来获取。

换一种说法:

1、如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。

2、如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可能获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。

示例

父组件代码:

<template>
  <div>
    <Child ref="child"></Child>
  </div>
</template>
<script>
import Child from "../Child";
export default {
  name: "parent",
  components: {
    Child,
  },
  mounted(){
    console.log(this.$refs.child.name);  // JavaScript
    this.$refs.child.sayHello();  // hello
  }
};
</script>

子组件代码:

export default {
  name: "child",
  data(){
    return {
      name: 'JavaScript'
    }
  },
  methods: {
    sayHello () {
      console.log('hello')
    }
  }
}
</script>

注意

1、$refs 是作为渲染结果被创建的,所以在初始渲染的时候它还不存在,此时无法无法访问。

2、$refs 不是响应式的,只能拿到获取它的那一刻子组件实例的状态,所以要避免在模板和计算属性中使用它。

5、$parent / $children

  • 使用$parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)。如果当前实例没有父实例,此实例将会是其自己。
  • 使用$children 可以让组件访问子组件的实例,但是, $children 并不能保证顺序,并且访问的数据也不是响应式的

示例

父组件代码:

<template>
  <div>
    <div>{{msg}}</div>
    <Child></Child>
    <button @click="change">点击改变子组件值</button>
  </div>
</template>
<script>
import Child from "../Child";
export default {
  name: "parent",
  components: {
    Child,
  },
  data() {
    return {
      msg: 'Welcome'
    }
  },
  methods: {
    change() {
      // 获取到子组件
      this.$children[0].message = 'JavaScript'
    }
  }
};
</script>

子组件代码:

<template>
  <div>
    <span>{{message}}</span>
    <p>获取父组件的值为:  {{parentVal}}</p>
  </div>
</template>
<script>
export default {
  name: "child",
  data(){
    return {
      message: 'Vue'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>

注意

1、通过 $parent 访问到的是上一级父组件的实例,可以使用 $root 来访问根组件的实例

2、在组件中使用$children拿到的是所有的子组件的实例,它是一个数组,并且是无序的

3、在根组件 #app 上拿 $parent 得到的是 new Vue()的实例,在这实例上再拿 $parent 得到的是undefined,而在最底层的子组件拿 $children 是个空数组

4、$children 的值是数组,是直接儿子的集合,关于具体是第几个儿子,那么儿子里面有个 _uid 属性,可以知道他是第几个元素,是元素的唯一标识符,根据这个属性,我们可以进行其他的操作,而 $parent是个对象

非父子组件通信

6、$root

注意: 是根组件,不是父组件。$root只对根组件有用。

示例
<div id="app">
  <child></child>
</div>

Vue.component('child', {
  mounted() {
    this.$root.fun('子组件的参数')
  },
  template:`<div></div>`
})

new Vue({
  el: '#app',
  data: {
    msg: '我是app内的msg'
  },
  methods: {
    fun (str) {
      console.log(this.msg + str) // 我是app内的msg 子组件的参数
    }
  }
})

7、eventBus

对于比较小型的项目,没有必要引入 vuex 的情况下,可以使用 eventBus。相比我们上面说的所有通信方式,eventBus 可以实现任意两个组件间的通信。事件总线 ,即 EventBus来通信。

(1)EventBus的使用

初始化(首先需要创建事件总线并将其导出,以便其它模块可以使用或者监听它。)

  1. 新创建一个 .js 文件,比如 event-bus.js
// utils/event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
  1. 可以直接在项目中的 main.js 初始化 EventBus(具体在下面有做说明)
// main.js
Vue.prototype.$EventBus = new Vue()

注意,这种方式(2)初始化的EventBus是一个全局的事件总线。

(2)发送事件

假设你有两个Vue页面需要通信: A 和 B ,A页面 在按钮上面绑定了点击事件,发送一则消息,通知 B页面。

PageA.vue

<template>
    <button @click="sendMsg()">-</button>
</template>

<script> 
import { EventBus } from "../../utils/event-bus";
export default {
  methods: {
    sendMsg() {
      EventBus.$emit("message", '来自A页面的消息'); 
      // EventBus.$emit('message',data)
      // 这个message是一个自定义的事件名称,data就是你要传递的数据。
    }
  }
}; 
</script>

(3)接收事件

接下来,我们需要在 B页面 中接收这则消息。

PageB.vue

<template>
  <p>{{msg}}</p>
</template>

<script> 
import { EventBus } from "../../utils/event-bus";
export default {
  data(){
    return {
      msg: ''
    }
  },
  mounted() {
    EventBus.$on("message", (msg) => {
      // A发送来的消息
      this.msg = msg;
    });
  }
};
</script>

注意:发送和监听的事件名称必须一致,msg就是获取的数据。第一个参数是事件名,第二个参数是方法

同理我们也可以在 B页面 向 A页面 发送消息。这里主要用到的两个方法:

// 发送消息
EventBus.$emit(channel: string, callback(payload1,))

// 监听接收消息
EventBus.$on(channel: string, callback(payload1,))

(4)接收事件移除事件监听者

如果想移除事件的监听,可以像下面这样操作:

import { EventBus } from "../../utils/event-bus";
beforeDestroy(){
    EventBus.$off('message',{})
}
  • $off() 会取消所有的事件订阅;
  • $off(‘事件名’) 会取消指定事件名的;
  • $off(‘事件名’, 回调) 会取消指定事件名的,指定回调

在vue生命周期beforeDestroy或者destroyed中用vue实例的$off方法清除eventBus

全局eventBus

它的工作原理是发布/订阅方法,通常称为 Pub/Sub 。

创建全局EventBus
// main.js
import Vue from 'vue'
// 创建事件总线   就相当于创建了一个新的vue实例
const bus = new Vue()
// 把bus挂载到了Vue的原型上, 保证所有的组件都能通过 this.$bus访问到事件总线
Vue.prototype.$bus = bus
发布事件 - 传递值
// this.$bus.$emit('事件名', 额外参数)
this.$bus.$emit('sendMsg', 'hello')
订阅事件 - 接收值
// 1. 在created中订阅
// 2. 回调函数需要写成箭头函数
// this.$bus.$on('事件名', 事件回调函数)
this.$bus.$on('sendMsg', msg => {
  console.log(msg)
})

同时也可以使用this. b u s . bus. bus.off(‘sendMsg’)来移除事件监听。

参考:Vue事件总线(EventBus)、 o n 、 on、 onemit、$off

利弊分析

使用EventBus的好处在于:

  1. 可全局使用
  2. 订阅和发布都很灵活,代码量少
  3. 跨组件通信,无需使用缓存

相对于状态管理,缺点也很明显

  1. 订阅和发布必须成对出现,不然就没有意义
  2. 由于在页面使用里的灵活性,一旦事件多了后,难以对事件进行维护
  3. 在订阅事件的组件里,必须手动销毁监听,否则会引发多次执行
  4. 对于一些包含业务逻辑的通信,复用性差,需要在多个地方重复写逻辑
总结

中大型项目都不推荐用EventBus,建议用vuex做状态管理,方便日后维护。
小型项目,涉及到多处跨组件通信的情况,可以考虑使用。

8、attrs和listeners

在这里插入图片描述

为什么要用$attrs 和 $listeners

先让我们来想一种情况,就是组件A跟组件C怎么通信,我们可以有多少中解决方案?

  1. 看到这种情况,大多数人应该会想到用vuex来进行数据通信吧,但是如果项目中多个组件中的共享状态很少,且项目比较小,全局数据通信也很少,那我们用vuex来实现这个功能,就感觉有点杀鸡用牛刀了
  2. 我们可以使用组件B来做通信的中转站,当组件A需要把数据传到组件C时,组件A通过props将数据传给组件B,然后组件B再用props传给组件C,这是一种解决方案,但是如果嵌套的组件过多,就会导致代码冗余且繁琐,维护就比较困难,而且如果组件C也要将数据传给组件A,也要一层一层往上传递,就更麻烦了
  3. 自定义一个Vue数据总线,这种适合组件跨级传递数据,但是缺点是碰到多人合作时,会导致代码的维护性较低,代码可读性也较低
  4. 还有一种解决方案,就是用provide inject,但是这种方式,官方不推荐,因为这个方法真的是太不好管控了,比如说我在根组件provide了this,孙孙重孙组件去使用了this里面的一个变量,这时候很难去跟踪到这个变量的出处了,而且你也并不知道,项目中哪个组件有用到这个变量,有没有在其他组件中进行改变,所以这个api在项目中很少人使用,但是很多人拿来写组件用

$attrs的用法

理解

正常情况下:父组件通过v-bind绑定一个数据传递给子组件,子组件通过props接收到就可以在子组件的html中使用了。但是,如果父组件v-bind传递给子组件,子组件没有用props接收呢?

注意:这个时候,父组件传递过来的数据就会被挂载(赋值)到这个子组件自带的对象$attrs上面,

所以: $attrs就是一个容器对象,这个容器对象会存放父组件传过来的且子组件未使用props声明接收的数据

示例

爷组件代码
在爷组件中,我们给父组件传递4个数据,msg1、msg2、msg3、msg4,其数据类型分别是字符串、字符串、数组、对象

<template>
  <div id="app">
    我是爷组件
    <fu
      :msg1="msg1"
      :msg2="msg2"
      :msg3="msg3"
      :msg4="msg4"
    ></fu>
  </div>
</template>

<script>
import fu from "./views/fu.vue";
export default {
  components: {
    fu,
  },
  data() {
    return {
      msg1: "孙悟空",
      msg2: "猪八戒",
      msg3: ["白骨精", "玉兔精", "狐狸精"],
      msg4: {
        name: "炎帝萧炎",
        book: "斗破苍穹",
      },
    };
  },
};
</script>
<style scoped>
#app {
  width: 950px;
  height: 600px;
  box-sizing: border-box;
  border: 3px dashed #e9e9e9;
  background-color: #cde;
  margin: 50px;
}
</style>

父组件代码

在父组件中我们只在props中接收msg1,另外三个我们不在props中接收。于是另外三个未在props中接收的,会自动被存放在 a t t r s 这个容器对象中去。同时,我们通过 attrs 这个容器对象中去。同时,我们通过 attrs这个容器对象中去。同时,我们通过attrs对象也可以拿到对应的爷组件中传递过来的,未在props中接收的数据值,也可以在html中使用。

<template>
  <div class="fatherClass">
    我是父组件
    <h2>{{ msg1 }}</h2>
    <h2>{{ $attrs.msg2}}</h2>
    <h2>{{ $attrs.msg3}}</h2>
    <h2>{{ $attrs.msg4}}</h2>
  </div>
</template>

<script>
export default {
  name: "DemoFather",
  props: {
    msg1: {
      type: String,
      default: "",
    },
  },
  mounted() {
    console.log('fu组件实例',this);
  },
};
</script>
<style lang="less" scoped>
.fatherClass {
  width: 850px;
  height: 400px;
  background-color: #baf;
  margin-left: 50px;
  margin-top: 50px;
}
</style>

祖孙之间的数据传递,需要通过中间的父组件$attrs做一个桥梁。

孙组件代码

<template>
  <div class="sunClass">
    我是孙子组件
    <h2>接收爷组件数据:-->{{ msg2 }}</h2>
    <h2>接收爷组件数据:-->{{ msg3 }}</h2>
    <h2>接收爷组件数据:-->{{ msg4 }}</h2>
  </div>
</template>

<script>
export default {
  // $attrs一般搭配interitAttrs 一块使用
  inheritAttrs: false, 
  // 默认会继承在html标签上传递过来的数据,类似href属性的继承
  /*
    孙子组件通过props,就能接收到父组件传递过来的$attrs了,就能拿到里面的数据了,也就是:
    爷传父、父传子。即:祖孙之间的数据传递。
  */ 
  props: {
    msg2: {
      type: String,
      default: "",
    },
    msg3: {
      type: Array,
      default: () => {
        return [];
      },
    },
    msg4: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  name: "DemoSun",
};
</script>

<style lang="less" scoped>
.sunClass {
  width: 750px;
  height: 180px;
  background-color: #bfa;
  margin-top: 80px;
  margin-left: 50px;
}
</style>

$listeners的用法

理解

使用$listeners可以实现孙组件的数据传递到爷组件中去,逻辑的话,也是用在中间的桥梁父组件上面去,我的理解就是$listeners可以将子组件emit的方法通知到爷组件。代码如下:

示例

第一步,在中间的父组件中加上$listenners

<sun v-bind="$attrs" v-on="$listeners"></sun>

第二步,爷组件中定义事件方法

<template>
  <div id="app">
    我是爷组件
    <h3>{{ fromSunData }}</h3>
    <fu :msg1="msg1" :msg2="msg2" :msg3="msg3" :msg4="msg4" 
        @fromSun="fromSun">
    </fu>
  </div>
</template>

<script>
import fu from "./views/fu.vue";
export default {
  components: {
    fu,
  },
  data() {
    return {
      msg1: "孙悟空",
      msg2: "猪八戒",
      msg3: ["白骨精", "玉兔精", "狐狸精"],
      msg4: {
        name: "炎帝萧炎",
        book: "斗破苍穹",
      },
      fromSunData: "",
    };
  },
  methods: {
    fromSun(payload) {
      console.log("孙传祖", payload);
      this.fromSunData = payload;
    },
  },
};
</script>

第三步,孙组件去触发爷组件的事件方法即可

<template>
  <div class="sunClass">
    我是孙子组件
    <h2>接收爷组件:-->{{ msg2 }}</h2>
    <h2>接收爷组件:-->{{ msg3 }}</h2>
    <h2>接收爷组件:-->{{ msg4 }}</h2>
    <el-button size="small" type="primary" plain @click="sendToZu">孙传祖</el-button>
  </div>
</template>

<script>
export default {
  // $attrs一般搭配interitAttrs 一块使用
  inheritAttrs: false, // 默认会继承在html标签上传递过来的数据,类似href属性的继承
  props: {
    msg2: {
      type: String,
      default: "",
    },
    msg3: {
      type: Array,
      default: () => {
        return [];
      },
    },
    msg4: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  name: "DemoSun",
  data() {
    return {
      data: "来自孙组件的数据",
    };
  },
  methods: {
    sendToZu() {
      // 孙组件能够触发爷组件的fromSun方法的原因还是因为父组件中有一个$listeners作为中间人,去转发这个事件的触发
      this.$emit("fromSun", this.data);
    },
  },
};
</script>

参考:详细讲解vue中祖孙组件间的通信之使用$attrs$listeners的方式

9、provide 和 inject

概念

provide 和 inject 需要在一起使用(成对使用),它可以使一个祖先组件向其所有子孙后代注入一个依赖,可以指定想要提供给后代组件的数据/方法,不论组件层次有多深,都能够使用。

简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量

示例

<!--祖先组件-->
<script>
export default {
    provide () {
	    return {
	    	author: 'yushihu',
	    }
    },
    data() {},
}
</script>
<!--子孙组件-->
<script>
export default {
    inject: ['author'],
    created() {
        console.log('author', this.author) // => yushihu
    },
}
</script>

注意

provide 和 inject 绑定不是响应的,它被设计是为组件库和高阶组件服务的,平常业务中的代码不建议使用。 因为数据追踪比较困难,不知道那一层级声明了 provide 又或是哪些层级使用了 inject 。造成比较大的维护成本。

10、dispatch 和 broadcast

参考

Vue $dispatch 和 $broadcast 详解

11、Vuex

概念

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex各个模块:

  • state:用于数据的存储,是store中的唯一数据源
  • getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
  • mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
  • actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
  • modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

vuex官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值