vue 在2.0已经去除了dispatch 和brocast,但是又想用它的特性怎么办?
1 初级版,只能传一个参数
问题:为什么不用eventBus?如果想要用类似的功能独立于业务项目,不可能在一个项目用一次,就要改一下代码,用eventBus.
实现原理:假设s.vue
要向app.vue
发消息,通过options.name
的方式找到目标组件target,然后target.$emit(target, eventName, params)
自己触发事件.
核心实现(如下:),可以通过mixins的方式混入。
dispatch('$option.name','事件名', 参数)
// emmiter.js
function broadcast (componentName, eventName, data) {
this.$children.forEach(child => {
if (child.$options.name === componentName) {
child.$emit.call(child, eventName, data)
} else {
broadcast.call(child, componentName, eventName, data)
}
})
}
export default {
methods: {
dispatch (componentName, eventName, data) {
let parent = this.$parent || this.$root
let name = parent.$options.name
while (parent && (!name || parent.$options.name !== componentName)) {
parent = parent.$parent
if (parent) {
name = parent.$options.name
}
}
console.log(parent)
parent.$emit.apply(parent, [eventName].concat(data))
},
broadcast (componentName, eventName, data) {
broadcast.call(this ,componentName, eventName, data)
}
}
}
具体例子:
// app.vue
<template>
<div id="app">
<input type="text" v-model="rMsg"><button @click="huixin">回信</button>
<div>hello</div>
<grand></grand>
</div>
</template>
<script>
import grand from './components/g'
import emitter from './components/emmit'
export default {
mixins: [emitter],
name: 'app',
data () {
return {
show: false,
rMsg: 'sb我收到信息了,考上大学你也找不到工作,还得你爹给你买房!'
}
},
methods: {
fn (e){
console.log('消息收到了', e)
},
huixin () {
this.broadcast('son', 'huixin', this.rMsg)
}
},
mounted () {
this.$on('joy', this.fn)
},
components: {
grand
}
}
</script>
// g.vue
<template>
<div>
我是grand,中文就是爷爷的意识,现在组件建好了,要干大事咯
<father></father>
</div>
</template>
<script>
import father from './f'
export default {
name: 'grand',
components: {
father
}
}
</script>
// f.vue
<template>
<div>
我是father,并且我有一个son
<son></son>
</div>
</template>
<script>
import son from './s'
export default {
name: 'father',
components: { son }
}
</script>
// s.vue
<template>
<div>
我是son
<el-form label-width="100px">
<el-form-item label="喜事">
<el-input v-model="joyText" style="width: 240px;"></el-input>
</el-form-item>
</el-form>
<el-button @click="transferJoy">向app报喜</el-button>
</div>
</template>
<script>
import emitter from './emmit'
export default {
mixins: [emitter],
name: 'son',
data () {
return {
joyText: '考上清华大学长河分校'
}
},
created () {
this.$on('huixin', (data) => {
console.log('回信', data)
})
},
methods: {
transferJoy () {
this.dispatch('app', 'joy', this.joyText)
}
}
}
</script>
最终效果:
运行效果
2 源码实现:
// 所有的父组件都自己触发事件,自己监听
Vue.prototype.$dispatch = function (event) {
var shouldPropagate = this.$emit.apply(this, arguments)
if (!shouldPropagate) return
var parent = this.$parent
var args = toArray(arguments)
// use object event to indicate non-source emit
// on parents
args[0] = { name: event, source: this }
while (parent) {
shouldPropagate = parent.$emit.apply(parent, args)
parent = shouldPropagate
? parent.$parent
: null
}
return this
}
// 所有的子组件自己触发事件
Vue.prototype.$broadcast = function (event) {
var isSource = typeof event === 'string'
event = isSource
? event
: event.name
// if no child has registered for this event,
// then there's no need to broadcast.
if (!this._eventsCount[event]) return
var children = this.$children
var args = toArray(arguments)
if (isSource) {
// use object event to indicate non-source emit
// on children
args[0] = { name: event, source: this }
}
for (var i = 0, l = children.length; i < l; i++) {
var child = children[i]
var shouldPropagate = child.$emit.apply(child, args)
if (shouldPropagate) {
child.$broadcast.apply(child, args)
}
}
return this
}
网友评论