vue 修改div宽度_Vue 组件通信方式及其应用场景总结(1.5W字)

前言

相信实际项目中用过vue的同学,一定对vue中父子组件之间的通信并不陌生,vue中采用良好的数据通讯方式,避免组件通信带来的困扰。今天笔者和大家一起分享vue父子组件之间的通信方式,优缺点,及其实际工作中的应用场景

首先我们带着这些问题去思考

1 vue中到底有多少种父子组件通信方式?

2 vue中那种父子组件最佳通信方式是什么?

3 vue中每个通信方式应用场景是什么?

一 prop

1 基本用法

prop通信方式大家最常见的,也是最常用的父子组件通信类型,我们可以直接在标签里面给子组件绑定属性和方法,对于属性我们可以直接通过子组件声明的prop拿到,对于父元素的方法,我们可以通过 this.$emit触发

我们先简单写一个props父子组件通信的场景

父组件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >对子组件说button>
<div>子组件对我说:{{ sonMes }}div>
<son :fatherMes="sendSonMes" @sonSay="sonSay" />
div>
template>
<script>import son from './son'export default {name:'father',components:{
son /* 子组件 */
},data(){return {mes:'',sendSonMes:'', /* 来自子组件的信息 */sonMes:'' /* 发送给子组件的信息 */
}
},methods:{/* 传递给子组件 */send(){this.sendSonMes = this.mes
},/* 接受子组件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我们这里只需要将给子组件的数据fatherMes和提供给子组件的方法 sonSay 通过标签方式传递给子组件。

子组件

<template>
<div class="son" >
<div> 父组件对我说:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button>
div>
template>
<script>export default {name:'son',props:{fatherMes:{type:String,default:''
}
},data(){return {mes:''
}
},methods:{send(){this.$emit('sonSay',this.mes)
}
},
}script>>

子组件通过props来定义接受父组件传递过来的信息,我们就可以直接通过this获取到,对于父组件传递的事件,我们可以通过this.$emit来触发事件。

区别react的props

这里和reactprops有点区别,react组件更新来源于props更新和自身state改变,当props改变,会默认更新组件。而在Vue中,如果我们对父组件传过来的新的props没有做依赖收集(template模版收集,computed计算属性收集),组件是不会触动更新的。

效果

a7111b507a56f9adf3d034998accd4e0.gif

数据格式化

如果我们想对props数据进行数据格式化,那么用computed接受props并格式化想要的数据类型。

<div class="son" >
<div> 父组件对我说:{{ computedFatherMes }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button>
div>
export default {
name:'son',
props:{
fatherMes:{
type:String,
default:''
}
},
computed:{
computedFatherMes(){
return this.fatherMes + '??'
}
},

}

824fa92e0a88a2fb6c2046caf90877e6.png

数据监听

当我们根据props改变不想更新视图,或者不想立即更新视图,那么可以用watch来监听来自父组件的props的变化。

watch:{
fatherMes(newVaule){
console.log( newVaule)
}
},

2优点

props传递数据优点是显而易见的,灵活简单,可以对props数据进行计算属性,数据监听等处理。父子组件通信灵活方便。这里可能单单仅限父子一层。

3缺点

1 props篡改

我们在子组件中使用父组件props的时候,如果涉及一些变量赋值,修改等操作,props被莫名其妙的修改了,连同父组件的数据也被篡改了,有的同学可能会很疑惑,父元素的props不是不能修改么,这里怎么改变了呢,vueprops到底能不能改变?,至于这个问题,不能直接给出答案,如果props是基础数据类型,当我们改变的时候,就会曝出错误。我们一起看一个例子。

a9d72c8681fd33ce000d66c345b1c8af.png

父组件

<template>
<div>
<div>父组件div>
<son :fData="sonProps" />
div>
template>
<script>import son from './sTampering'export default {name:'father',components:{
son
},data(){return {sonProps:''
}
},
}script>

子组件

<template>
<button >改变父组件propsbutton>
template>

<script>export default {name:'son',props:{fData:{required:true
}
},methods:{changFatherProps(){this.fData = 'hello ,father'
}
}
}script>

当我们直接点击button 会抛出以下警。

4a603cb3749e5a3e3e776fc227b06399.png

但是当我们传过来的是一个引用数据类型,并且修改数据下某一个属性的时候。

父组件

data(){
return {
sonProps:{
a:1,
b:2
}
}
},

子组件

changFatherProps(){
this.fData.a = 'hello,world'
}

当点击按钮发现并没有报错。

于是我们打印父组件的sonprops数据:

36a234f81ab18e0454e6a16bbe4bada1.png

我们发现父组件的data数据已经被子组件篡改。于是我们总结出一个结论,子组件虽然不能直接对父组件prop进行重新赋值,但是当父组件是引用类型的时候,子组件可以修改父组件的props下面的属性。这就是一个很尴尬的事情,如果我们设计的初衷就是父组件数据也同时被修改,这个结果是可以接受的,但是当我们不希望父组件那份数据源有任何变化的时候,这就是一个严重的逻辑bug。所以这就是props通讯的风险项之一。

2 跨层级通信,兄弟组件通讯困难

对于父组件-子组件-子组件的子组件这种跨层级的通信,显然需要我们一层一层的prop绑定属性和方法,如果遇到更复杂的情况,实现起来比较困难。

df050862de54d7bba12a596ef9797609.png

对于兄弟组件之间的通讯,props需要通过父组件作为桥梁,实现子组件-> 父组件 -> 子组件通信模式,如果想要通过父组件做媒介,那么必定会造成父组件重新渲染,为了实现兄弟组件通信付出的代价比较大。d222f49ac31991a879ff0b52f7cbcfa0.png

4 应用场景

props的应用场景很简单,就是正常不是嵌套很深的父子组件通信,和关系不是很复杂的兄弟组件组件通信。

二 this.$xxx

通过this下面的数据直接获取vue实例这种方法比较暴力,因为我们所谓的组件,最终都会是一个对象,存放组件的各种信息,组件和组件通过this.$childrenthis.$parent指针关联起来。因为在项目中只有一个root根组件,理论上,我们可以找到通过this.$children this.$parent来访问页面上的任何一个组件 ,但是实际上如何精确匹配到目标组件,确是一个无比棘手的问题。

1 基本用法

父组件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >对子组件说button>
<son2 v-if="false" />
<div>子组件对我说:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'import son2 from './son2'export default {name:'father',components:{
son ,/* 子组件 */
son2
},data(){return {mes:'',sendSonMes:'', /* 来自子组件的信息 */sonMes:'' /* 发送给子组件的信息 */
}
},methods:{/* 传递给子组件 */send(){/* 因为son组件是第一个有效组件所以直接去下标为0的组件 */const currentChildren = this.$children[0]
currentChildren.accept(this.mes)
},/* 接收子组件的信息 */accept(value){this.sonMes = value
}
},
}script>

子组件

<template>
<div class="son" >
<div> 父组件对我说:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button>
div>
template>
<script>export default {name:'son',data(){return {mes:'',fatherMes:''
}
},methods:{/* 接受父组件内容 */accept(value){this.fatherMes = value
},/* 向父组件发送信息 */send(){this.$parent.accept(this.mes)
},
},
}script>

效果

d7bb16a11b44a8406ceef5743411d474.gif

我们可以清楚看到,和props通信相比,this.$parentthis.$children显得更加简洁,无需再给子组件绑定事件和属性,只需要在父组件和子组件声明发送和接受数据的方法。就可以实现组件间的通信,看起来很是便捷,但是实际操作中会有很大的弊端,而且vue本身也不提倡这种通信方式。而且这种通信方式也有很多风险性,我们稍后会给予解释。

2 优点

简单,方便 this.$children,this.$parent this.$refs 这种通信方式,更加的简单直接获取vue实例,对vue实例下的数据和方法直接获取或者引用。

3 缺点

1 $this.children不可控性大,有一定风险

如上的例子,我们稍微对父组件加以改动,就会直接报错。

之前的

 <son2 v-if="false" />

改成

<son2 v-if="true" />

ec6510b7ab72b8809928c2d3d1d67293.png

就会报如上错误,错误的原因很简单,我们用 $children 的下标获取,但是兄弟组件son2 v-if = true 之后,我们通过通过this.$children[0] 获取的就是son2组件,son2没有绑定方法,所以得出结论,对于v-if动态控制组件显示隐藏的不建议用this.$children用法,取而代之的我们可以用ref获取对应子组件的实例。

如上改成

<son ref="son" />

然后获取:

const currentChildren = this.$refs.son

根本解决了问题。

2 不利于组件化

直接获取组件实例这种方式,在一定程度上妨碍了组件化开发,组件化开发的过程中,那些方法提供给外部,那些方法是内部使用,在没有提前商量的情况下,父子组件状态不透明的情况下,一切都是未知的,所以不同开发人员在获取组件下的方法时候,存在风险,提供的组件方法,属性是否有一些内部耦合。组件开发思路初衷,也不是由组件外部来对内部作出一定改变,而往往是内部的改变,通知外部绑定的方法事件。反过来如果是子组件内部,主动向父组件传递一些信息,也不能确定父组件是否存在。

3 兄弟组件深层次嵌套组件通讯困难

和props方式一下,如果是兄弟直接组件的通信,需要通过父组件作为中间通讯的桥梁,而深层次的组件通讯,虽然不需要像props通讯那样逐层绑定,但是有一点,需要逐渐向上层或下层获取目标实例,如何能精准获取这是一个非常头疼的问题,而且每当深入一层,风险性和不确定性会逐级扩大。

4 应用场景

直接通过实例获取的通信方式适合已知的,固定化的页面结构,这种通讯方式,要求父子组件高度透明化,知己知彼,很明确父子组件有那些方法属性,都是用来干什么。所以说这种方式更适合页面组件,而不适合一些第三方组件库,或者是公共组件。

三 provide inject

如果说vue中 provide 和 inject,我会首先联想到reactcontext上下文,两个作用在一定程度上可以说非常相似,在父组件上通过provide将方法,属性,或者是自身实例暴露出去,子孙组件,插槽组件,甚至是子孙组件的插槽组件,通过inject把父辈provide引进来。提供给自己使用,很经典的应用 provide和 inject的案例就是 element-ui中 el-form和 el-form-item

我们先不妨带着问题想象一个场景

<el-form  label-width="80px" :model="formData">
<el-form-item label="姓名">
<el-input v-model="formData.name">el-input>
el-form-item>
<el-form-item label="年龄">
<el-input v-model="formData.age">el-input>
el-form-item>
el-form>

我们可以看到 el-form 和 el-form-item不需要建立任何通信操作,那么el-formel-form-item 是如何联系起来,并且共享状态的呢?我们带着疑问继续往下看。

1 基本用法

普通方式

我们用父组件 -> 子组件 -> 孙组件 的案例

父组件

<template>
<div class="father" >
<div>子组件对我说:{{ sonMes }}div>
<div>孙组件对我说:{{ grandSonMes }}div>
<son />
div>
template>
<script>import son from './son'export default {name:'father',components:{
son /* 子组件 */
},provide(){return {/* 将自己暴露给子孙组件 ,这里声明的名称要于子组件引进的名称保持一致 */father:this
}
},data(){return {grandSonMes:'', /* 来自子组件的信息 */sonMes:'' /* 发送给子组件的信息 */
}
},methods:{/* 接受孙组件信息 */grandSonSay(value){this.grandSonMes = value
},/* 接受子组件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

这里我们通过provide把本身暴露出去。⚠️⚠️⚠️这里声明的名称要与子组件引进的名称保持一致

子组件

<template>
<div class="son" >
<input v-model="mes" /> <button @click="send" >对父组件说button>
<grandSon />
div>
template>

<script>import grandSon from './grandSon'export default {/* 子组件 */name:'son',components:{
grandSon /* 孙组件 */
},data(){return {mes:''
}
},/* 引入父组件 */inject:['father'],methods:{send(){this.father.sonSay(this.mes)
}
},
}script>

子组件通过inject把父组件实例引进来,然后可以直接通过this.father可以直接获取到父组件,并调用下面的sonSay方法。

孙组件

<template>
<div class="grandSon" >
<input v-model="mes" /> <button @click="send" >对爷爷组件说button>
div>
template>

<script>export default {/* 孙组件 */name:'grandSon',/* 引入爷爷组件 */inject:['father'],data(){return {mes:''
}
},methods:{send(){this.father.grandSonSay( this.mes )
}
}
}script>

孙组件没有如何操作,引入的方法和子组件一致。

效果

6b8493cdc9a3f194304605178b040483.gif

2 插槽方式

provide , inject 同样可以应用在插槽上,我们给父子组件稍微变动一下。

父组件

<template>
<div class="father" >
<div>子组件对我说:{{ sonMes }}div>
<div>孙组件对我说:{{ grandSonMes }}div>
<son >
<grandSon/>
son>
div>
template>
<script>import son from './slotSon'import grandSon from './grandSon' export default {name:'father',components:{
son, /* 子组件 */
grandSon /* 孙组件 */
},provide(){return {/* 将自己暴露给子孙组件 */father:this
}
},data(){return {grandSonMes:'', /* 来自子组件的信息 */sonMes:'' /* 发送给子组件的信息 */
}
},methods:{/* 接受孙组件信息 */grandSonSay(value){this.grandSonMes = value
},/* 接受子组件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

子组件

<template>
<div class="son" >
<input v-model="mes" /> <button @click="send" >对父组件说button>
<slot />
div>
template>

达到了同样的通信效果。实际这种插槽模式,所在都在父组件注册的组件,最后孙组件也会绑定到子组件的children下面。和上述的情况差不多。

provied其他用法

provide不仅能把整个父组件全部暴露出去,也能根据需要只暴露一部分(一些父组件的属性或者是父组件的方法),上述的例子中,在子孙组件中,只用到了父组件的方法,所以我们可以只提供两个通信方法。但是这里注意的是,如果我们向外提供了方法,如果方法里面有操作this行为,需要绑定this

父组件

   provide(){
return {
/* 将通信方法暴露给子孙组件(注意绑定this) */
grandSonSay:this.grandSonSay.bind(this),
sonSay:this.sonSay.bind(this)
}
},
methods:{
/* 接受孙组件信息 */
grandSonSay(value){
this.grandSonMes = value
},
/* 接受子组件信息 */
sonSay(value){
this.sonMes = value
},
},

子组件

/* 引入父组件方法 */
inject:['sonSay'],
methods:{
send(){
this.sonSay(this.mes)
}
},

2 优点

ab01b085c3d593078658ee510cbaa122.png

1 组件通信不受到子组件层级的影响

provide inject用法 和 react.context非常相似, provide相当于Context.Provider ,inject 相当于 Context.Consumer,让父组件通信不受到组件深层次子孙组件的影响。

2 适用于插槽,嵌套插槽

provide inject 让插槽嵌套的父子组件通信变得简单,这就是刚开始我们说的,为什么 el-form 和 el-form-item能够协调管理表单的状态一样。在element源码中 el-form 就是将this本身provide出去的。

3 缺点

1 不适合兄弟通讯

provide-inject 协调作用就是获取父级组件们提供的状态,方法,属性等,流向一直都是由父到子,provide提供内容不可能被兄弟组件获取到的,所以兄弟组件的通信不肯能靠这种方式来完成。

2 父级组件无法主动通信

provide-inject更像父亲挣钱给儿子花一样,儿子可以从父亲这里拿到提供的条件,但是父亲却无法向儿子索取任何东西。正如这个比方,父组件对子组件的状态一无所知。也不能主动向子组件发起通信。

4 应用场景

provide-inject这种通信方式,更适合深层次的复杂的父子代通信,子孙组件可以共享父组件的状态,还有一点就是适合el-form el-form-item这种插槽类型的情景。

四 vuex

vuex算是vue中处理复杂的组件通信的最佳方案,毕竟是vuevuex一个娘胎里出来的。而且vuex底层也是用vue实现的。相信不少同学对vuex并不陌生。接下来我们开始介绍vuex。

ee033f12866135fa6ce11aedd27af0a2.png

1 基础用法

vuex文件

import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex)

export default new Vuex.Store({
state:{
fatherMes:'',
sonMes:'',
fatherMesAsync:''
},
mutations:{
sayFaher(state,value){
state.fatherMes = value
},
saySon(state,value){
state.sonMes = value
},
sayAsyncFather(state,value){
state.fatherMesAsync = value
}
},
actions:{
asyncSayFather({ commit },payload){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(payload)
},2000)
}).then(res=>{
commit('sayAsyncFather',res)
})
}
}
})

store文件中,我们声明三个mutations 分别是向父组件通信saySon,父组件向子组件通信,同步方法sayFaher和异步方法sayAsyncFather ,actions中模拟了一个三秒后执行的异步任务asyncSayFather

main.js

import store from './components/vuex/store'

new Vue({
render: h => h(App),
store
}).$mount('#app')

main.js注入store

父组件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >同步:对子组件说button><br/>
<input v-model="asyncMes" /> <button @click="asyncSend" >异步:对子组件说button><br/>
<div>子组件对我说:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'export default {/* 父组件 */name:'father',components:{
son ,/* 子组件 */
},data(){return {mes:'',asyncMes:''
}
},computed:{sonMes(){return this.$store.state.sonMes
}
},mounted(){console.log(this.$store)
},methods:{/* 触发mutations,传递数据给子组件 */send(){this.$store.commit('sayFaher',this.mes)
},/* 触发actions,传递数据给子组件 */asyncSend(){this.$store.dispatch('asyncSayFather',this.asyncMes)
}
},
}script>

父组件分别触发同步异步方法,把信息发送给子组件。用computed来接受vuex中的state

子组件

<template>
<div class="son" >
<div> 父组件对我说:{{ fatherMes }} div>
<div> 父组件对我说(异步):{{ fatherMesAsync }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button>
div>
template>
<script>export default {name:'son',data(){return {mes:'',
}
},computed:{/* 接受父组件同步消息 */fatherMes(){return this.$store.state.fatherMes
},/* 接受父组件异步消息 */fatherMesAsync(){return this.$store.state.fatherMesAsync
}
},methods:{/* 向父组件发送信息 */send(){this.$store.commit('saySon',this.mes)
},
},
}script>

子组件的方法和父组件保持一致。

效果

f89b4665f4cde5b562339a5b1a38d8bb.gif

2 优点

1 根本解决复杂组件的通信问题

vuex在一定程度上根本解决了vue复杂的组件通信情况,我们不再关心两个毫无干系的两个组件的通信问题。

2 支持异步组件通信

vuexactions允许我们做一些异步操作,然后通过commit可以把数据传入对应的mutation,至于actions为什么可以执行异步,是因为里面底层通过Promise.resolve能够获取异步任务完成的状态。

3 缺点

1 流程相比稍微复杂

vuex通信方式相比其他方式,比较复杂,而且如果不同的模块,需要建立独立的modules

4 应用场景

实际开发场景中,不会存在demo项目这样简单的通信,vuex的出现,就是解决这些比较复杂的组件通信场景。对于中大型项目,vuex是很不错的状态管理,数据通信方案。

五 事件总线一 EventBus

EventBus事件总线, EventBus 所有事件统一调度,有一个统一管理事件中心,一个组件绑定事件,另一个组件触发事件,所有的组件通信不再收到父子组件的限制,那个页面需要数据,就绑定事件,然后由数据提供者触发对应的事件来提供数据,这种通讯场景不仅仅应用在vue,而且也应用在react

EventBus 核心思想是事件的绑定和触发,这一点和vue中 this.$emit 和 this.$on一样,这个也是整个EventBus核心思想。接下来我们来重点解析这个流程。

1 基本用法

EventBus

export default class EventBus {
es = {}
/* 绑定事件 */
on(eventName, cb) {
if (!this.es[eventName]) {
this.es[eventName] = []
}
this.es[eventName].push({
cb
})
}
/* 触发事件 */
emit(eventName, ...params) {
const listeners = this.es[eventName] || []
let l = listeners.length

for (let i = 0; i < l; i++) {
const { cb } = listeners[i]
cb.apply(this, params)
}
}
}

export default new EventBus()

这个就是一个简单的事件总线,有on,emit两个方法。

父组件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >对子组件说button>
<div>子组件对我说:{{ sonMes }}div>
<son />
<brotherSon />
div>
template>
<script>import son from './son'import brotherSon from './brother'import EventBus from './eventBus'export default {name:'father',components:{
son ,/* 子组件 */
brotherSon, /* 子组件 */
},data(){return {mes:'',sonMes:''/* 发送给子组件的信息 */
}
},mounted(){/* 绑定事件 */
EventBus.on('sonSay',this.sonSay)
},methods:{/* 传递给子组件 */send(){
EventBus.emit('fatherSay',this.mes)
},/* 接受子组件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我们在初始化的时候通过EventBuson方法绑定sonSay方法供给给子组件使用。向子组件传递信息的时候,通过emit触发子组件的绑定方法,实现了父子通信。接下来我们看一下子组件。

子组件

<template>
<div class="son" >
<div> 父组件对我说:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button>
<div>
<input v-model="brotherMes" /> <button @click="sendBrother" >对兄弟组件说button>
div>
div>
template>
<script>import EventBus from './eventBus' export default {name:'son',data(){return {mes:'',brotherMes:'',fatherMes:''
}
},mounted(){/* 绑定事件 */
EventBus.on('fatherSay',this.fatherSay)
},methods:{/* 向父组件传递信息 */send(){
EventBus.emit('sonSay',this.mes)
},/* 向兄弟组件传递信息 */sendBrother(){
EventBus.emit('brotherSay',this.brotherMes)
},/* 父组件对我说 */fatherSay(value){this.fatherMes = value
}
},
}script>

和父组件的逻辑差不多,把需要接受数据的方法,通过EventBus绑定,通过触发eventBus方法,来向外部传递信息。我们还模拟了兄弟之间通信的场景。我们建立一个兄弟组件。

<template>
<div class="son" > 兄弟组件对我说: {{ brotherMes }} div>
template>

<script>import EventBus from './eventBus'export default {/* */name:'brother',data(){return {brotherMes:''
}
},mounted(){/* 绑定事件给兄弟组件 */
EventBus.on('brotherSay',this.brotherSay)
},methods:{brotherSay(value){this.brotherMes = value
}
}
}script>

我们可以看到,兄弟组件处理逻辑和父子之间没什么区别。

效果

3dacc154c6d6e7688c131b3f04ba5716.gif

2 优点

1 简单灵活,父子兄弟通信不受限制。

eventBus的通信方式,相比之前的几种比较简单,而且不受到组件层级的影响,可以实现任意两个组件的通信。需要数据就通过on绑定,传递数据就emit触发。

2 通信方式不受框架影响

eventBus的通信方式,不只是vue可以用,react,小程序都可以使用这种通信方式,而且笔者感觉这种通信方式更适合小程序通信,至于为什么稍后会一一道来。

4 缺点

1 维护困难,容易引起连锁问题

如果我们采用事件总线这种通信模式,因为所有事件是高度集中,统一管理的,中间如果有一个环节出现错误,就会造成牵一发动全身的灾难.而且后期维护也是十分困难的。

2 需要谨小慎微的命令规范

现实的应用场景,要比demo场景复杂的多,实际场景会有无数对父子组件,无数对兄弟组件,我们不肯能每个事件都叫相同名字,所以eventBus绑定事件的命名要有严格的规范,不能起重复名字,也不能用错名字。

3 不利于组件化开发

eventBus通信方式是无法进行有效的组件化开发的,假设一个场景,一个页面上有多个公共组件,我们只要向其中的一个传递数据,但是每个公共组件都绑定了数据接受的方法。我们怎么样做到把数据传递给需要的组件呢?

4 应用场景

1b02f5cb5f2fbfb629a61dcaccbac85a.png

实现总线这种方式更适合,微信小程序,和基于vue构建的小程序,至于为什么呢,因为我们都知道小程序采用双线程模型(渲染层+逻辑层)(如下图所示),渲染层作用就是小程序wxml渲染到我们的视线中,而逻辑层就是我们写的代码逻辑,在性能上,我们要知道在渲染层浪费的性能要远大于逻辑层的代码执行性能开销,如果我们在小程序里采用通过props等传递方式,属性是绑定在小程序标签里面的,所以势必要重新渲染视图层。如果页面结构复杂,可能会造成卡顿等情况,所以我们通过eventBus可以绕过渲染层,直接有逻辑层讲数据进行推送,节约了性能的开销。

六 事件总线二 new Vue

new Vue 这种通信方式和eventBus大致差不多,有一点不同的是,以vue实例作为eventBus中心,除了我们可以用$on,$emit之外,我们还可以用vue下的data,watch等方法,而且我们建立多个多个vue,作为不同模块的数据通信桥梁,相比上边那个EventBus方法,new Vue这种方法更高效,更适合vue项目场景。我们接着往下看。

1 基本使用

VueBus

import Vue from 'vue'

export default new Vue()

父组件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >对子组件说button>
<div>子组件对我说:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'import VueBus from './vueBus'export default {/* 父组件 */ name:'father',components:{
son ,/* 子组件 */
},data(){return {mes:'',sonMes:'' /* 发送给子组件的信息 */
}
},created(){/* 绑定属性 */
VueBus._data.mes = 'hello,world'
},mounted(){/* 绑定事件 */
VueBus.$on('sonSay',this.sonSay)
},methods:{/* 传递给子组件 */send(){
VueBus.$emit('fatherSay',this.mes)
},/* 接受子组件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我们通过 $on绑定了接受数据的方法,初始化的时候向 vue_data下面绑定了数据。

子组件

<template>
<div class="son" >
<div> 父组件对我说:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >对父组件说button><br/>
<button @click="getFatherMes" >获取数据button>
div>
template>

<script>import VueBus from './vueBus' export default {name:'son',data(){return {mes:'',brotherMes:'',fatherMes:''
}
},mounted(){/* 绑定事件 */
VueBus.$on('fatherSay',this.fatherSay)
},methods:{/* 向父组件传递信息 */send(){
VueBus.$emit('sonSay',this.mes)
},/* 父组件对我说 */fatherSay(value){this.fatherMes = value
},/* 获取父组件存入vue中的数据 */getFatherMes(){console.log( VueBus._data.mes )
}
},
}script>

eventBus事件总线一样,我们还可以直接通过_data数据直接获取到父组件传递的内容。

效果

a87ad4a887b1ec1ff931254d6eab8ffd.gif

2 优点

1 简单灵活,任意组件之间通信。

和上边eventBus通信方式一样,这种通信方式很灵活,可以轻松在任意组件间实现通信。

2 除了通信还可以使用watch , computed等方法

如果我们通过vue作为通信媒介,那么只用其中的$emit$on真的是有点大材小用了,既然实例了一个vue,我们可以轻松的使用vue的 $watch computed等功能。

3 缺点

基本上EventBus的缺点,都在vue这种通信方式中都有存在。

4 应用场景

在项目中不考虑用vuex的中小型项目中,可以考虑采用vue事件总线这种通信方式,在使用的这种方式的时候,我们一定要注意命名空间,不要重复绑定事件名称。分清楚业务模块,避免后续维护困难。

写在后面

我们在写vue项目中,具体要用什么通信方式,还要看具体的业务场景,项目大小等因素综合评估。文章中给大家介绍了vue通信方式的优缺点,可以给大家实际工作提供一个参考。

交流讨论

欢迎关注公众号「前端试炼」,公众号平时会分享一些实用或者有意思的东西,发现代码之美。专注深度和最佳实践,希望打造一个高质量的公众号。

c72ee9887dea989c17b5170eb03d976f.png

公众号后台回复「小炼」加我微信,带你飞。

如果觉得这篇文章还不错,来个【分享、点赞、在看】三连吧,让更多的人也看到~

430b31a30b31802e0a916a5741dd69ff.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

源码安装nginx以及平滑升级

源码安装nginx以及平滑升级作者&#xff1a;尹正杰版权声明&#xff1a;原创作品&#xff0c;谢绝转载&#xff01;否则将追究法律责任。欢迎加入&#xff1a;高级运维工程师之路 598432640这个博客不方便上传软件包&#xff0c;我给大家把软件包放到百度云链接&#xff1a;htt…

乐高泰坦机器人视频解说_“安防”机器人将亮相服贸会

可巡视园区、自动避障、自动充电&#xff0c;实现24小时巡逻&#xff0c;与后台链接实时视频监控&#xff0c;异常检测……17日下午&#xff0c;北青-北京头条记者在特斯联科技集团有限公司的展厅中看到&#xff0c;一款“身怀绝技”的“安防”机器人备受关注。这款机器人也将在…

ios上传文件云服务器上,ios文件上传服务器

ios文件上传服务器 内容精选换一换在当前的迁移流程中&#xff0c;可能会存在迁移后ECS控制台镜像名称与实际操作系统不一致的现象。在当前机制下&#xff0c;该现象属于正常现象。该处显示的是下发ECS时使用的镜像名称&#xff0c;而不是操作系统名称。如果设置目的端时使用的…

这是一个UIImage集合类,可以很方便的对图片的染料(着色),增加亮度(闪电)和降低亮度(黑)和其他扩展的功能模块。...

2019独角兽企业重金招聘Python工程师标准>>> 这是一个UIImage集合类&#xff0c;可以很方便的对图片的染料&#xff08;着色&#xff09;&#xff0c;增加亮度&#xff08;闪电&#xff09;和降低亮度&#xff08;黑&#xff09;和其他扩展的功能模块。 在swift下实…

微商相册一直显示服务器偷懒,【小程序】微商个人相册多端小程序源码以及安装...

程序介绍学习node.js顺便接的400元单子&#xff0c;前后端都是自己写&#xff0c;相比自己以前写的&#xff0c;这次相对来说比较规范&#xff0c;用于个人相册展示&#xff0c;适合微商&#xff0c;有客服联系&#xff0c;无需后台管理系统&#xff0c;小程序上直接进行管理&a…

ipfs分布式存储网络服务器系统,IPFS分布式存储是什么意思 分布式云存储服务器详解...

一直以来&#xff0c;数据的安全性&#xff0c;存储的隐私性都是用户很重视的方面。基于此&#xff0c;再加上现在媒体对于分布式存储的疯狂报道&#xff0c;分布式存储一词再度涌入了大家的视野之中&#xff0c;接下来IPFS新说就为大家详解一下有关IPFS分布式存储的知识。VIPF…

时间轮

老早之前就听说时间轮算法特别高效&#xff0c;Linux内核都用的它&#xff0c;这两天抽空实现了遍……嗯&#xff0c;被差一bug搞死(~&#xffe3;▽&#xffe3;~) 啊哈 网上扣来的图&#xff0c;原理好懂&#xff1a;轮子里的每格代表一小段时间&#xff08;精度&#xff09;…

qt tab弹出特效_Nuke Studio 12(影视特效合成软件)中文版分享

Nuke 12是一款功能强大&#xff0c;世界知名的影视后期特效合成软件。NUKE是一个获得学院奖(Academy Award)的数码合成软件。已经经过10年的历练&#xff0c;为艺术家们提供了创造具有高质素的相片效果的图像的方法。NUKE无需专门的硬件平台&#xff0c;但却能为艺术家提供组合…

【转】unity地形插件T4M使用帮助

unity的地形系统在手机游戏中因为效率问题基本无法使用&#xff0c;只能通过T4M这个地形插件来进行优化制作。下面大概讲解一下使用流程及方法。 先中U3D里面用自带的地形系统刷出想要的地形和贴图。贴图可以大概刷一下。后面要重新刷。 用导出脚本ExportTerrain.js导出地形为O…

Linux的简介与虚拟机的管理

Linux的简介&#xff1a; 严格的来讲&#xff0c;Linux不算是一个操作系统&#xff0c;只是一个Linux系统中的内核&#xff0c;Linux的全称是GUN/Linux&#xff0c;这才算是一个真正意义上的Linux系统。 Linux是一个多用户多任务的操作系统&#xff0c;拥有良好的用户界面&…

R语言:ggplot2精细化绘图——以实用商业化图表绘图为例(转)

本文旨在介绍R语言中ggplot2包的一些精细化操作&#xff0c;主要适用于对R画图有一定了解&#xff0c;需要更精细化作图的人&#xff0c;尤其是那些刚从excel转ggplot2的各位&#xff0c;有比较频繁的作图需求的人。不讨论那些样式非常酷炫的图表&#xff0c;以实用的商业化图表…

Linux中常用的命令

1.文件建立 touch file&#xff08;文件的名字&#xff09; 注意&#xff1a; touch不但可以建立文件也可以修改文件的时间戳 时间戳分为&#xff1a; atime&#xff1a;文件内容被访问的时间标识 mtime&#xff1a;文件内容被修改的时间标识 ctime&#xff1a;文件属性或文件内…

Linux系统中输出输入的管理

1.什么是输入和输出 输入和输出是计算机系统中的主机与外部进行通信的系统。它由外围设备和输入输出控制系统两部分组成&#xff0c;我们在shell中键入指令&#xff0c;然后送入CPU中运算产生结果&#xff0c;再将结果送到字符设备中显示。简单点来说输入输出就是通过我们的键盘…

Linux系统中用户的管理

#####用户管理###### 1在Linux中&#xff0c;有三种用户&#xff1a; 1 root : 也成为超级用户&#xff0c;对系统有控制权限&#xff0c;超级用户可以不受限制的运行任何命令&#xff0c;root 用户可以看作是系统的管理员。 2 系统用户&#xff1a; 系统用户通常为系统功能所必…

Linux中对进程的管理

1.what is 进程 程序&#xff08;program&#xff09;放置在储存媒体中&#xff08;如硬盘、光盘、软盘、磁盘等&#xff09;&#xff0c;为实体的型态存在。 进程&#xff1a;程序被触发后&#xff0c;执行者的权限与属性、程序的程序码与所需数据等都会被载入内存中&#xff…

Linux远程连接与sshd服务安全设定

1.远程连接&#xff1a; 首先设置ip&#xff1a; 设置好之后&#xff0c;先ping一下IP 看能不能通 ssh root172.25.13.103 ##表示的是&#xff1a;连接ip为172.25.13.103的root用户 2.系统控制命令 系统控制命令的查看相关参数如下表 systemctl服务控制命令systemctl stat…

一个简单的封ip规则

2019独角兽企业重金招聘Python工程师标准>>> 一个简单通过nginx日志封ip规则&#xff08;仅仅自己方便使用&#xff09; #!/bin/bash #Version:1.0 #Date:2016-08-09 #作用:防刷IP地址,解封蜘蛛,解封5天前封的IP地址function deny () { Date$(date "%F-%H-%M&q…

系统日志管理

1 查看系统中的日志 rsyslog 此服务是用来采集系统日志的&#xff0c;他不产生日志&#xff0c;只是起到采集作用 2 rsyslog 的管理 /var/log/messages服务信息日志/var/log/secuer系统登陆日志/var/log/cron定时任务日志/var/log/maillog邮件日志/var/log/boot.log系统启动日…

iOS10 UI教程视图的边界与视图的框架

2019独角兽企业重金招聘Python工程师标准>>> iOS10 UI教程视图的边界与视图的框架 iOS10 UI视图的边界 在视图的几何形状中我们提到了视图属性中的一部分属性可以将定义的视图绘制在屏幕上。其中典型的3个属性为边界属性、框架属性以及中心位置属性。 bounds表示的就…

Linux中远程文件的传输

1. scp命令 scp file userip:/dir 把自己主机的文件远程复制到其他主机 scp userip:/file dir 把其他主机的文件远程复制到当前主机 注意&#xff1a;要关闭接受端的防火墙 把主机的file远程复制到IP为172.25.254.117的root用户的Desktop 把IP为172.25.254.117的root用户Deskt…