You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// vm.$on
export function eventsMixin (Vue: Class<Component>) {
const hookRE = /^hook:/
//参数类型为字符串或者字符串组成的数组
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
// 传入类型为数组
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$on(event[i], fn)
//递归并传入相应的回调
}
} else {
//
(vm._events[event] || (vm._events[event] = [])).push(fn)
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
}
return vm
}
// vm.$emit
Vue.prototype.$emit = function (event: string): Component {
const vm: Component = this
if (process.env.NODE_ENV !== 'production') {
const lowerCaseEvent = event.toLowerCase()
if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
tip(
`Event "${lowerCaseEvent}" is emitted in component ` +
`${formatComponentName(vm)} but the handler is registered for "${event}". ` +
`Note that HTML attributes are case-insensitive and you cannot use ` +
`v-on to listen to camelCase events when using in-DOM templates. ` +
`You should probably use "${hyphenate(event)}" instead of "${event}".`
)
}
}
let cbs = vm._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
try {
cbs[i].apply(vm, args)// 执行之前传入的回调
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
}
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that has this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
const augment = hasProto
? protoAugment
: copyAugment
augment(value, arrayMethods, arrayKeys)
this.observeArray(value)
} else {
this.walk(value)
}
}
/**
* Walk through each property and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
// 属性为对象的时候,observe 对象的属性
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
/**
* Observe a list of Array items.
*/
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
结合
Vue
源码谈谈发布-订阅模式最近的工作学习中接触到了发布-订阅模式。该思想编程中的应用也是很广泛的, 例如在
Vue
中也大量使用了该设计模式,所以会结合Vue的源码和大家谈谈自己粗浅的理解.发布订阅模式主要包含哪些内容呢?
这么看下来,其实就像
JavaScript
中的事件模型,我们在DOM节点上绑定事件函数,触发的时候执行就是应用了发布-订阅模式.我们先按照上面的内容自己实现一个
Observer
对象如下:为什么会使用发布订阅模式呢? 它的优点在于:
发布-订阅模式在
Vue
中的应用Vue
的实例方法中的应用:(当前版本:2.5.16)Vue
中还实现了vm.$once
(监听一次);以及vm.$off
(取消订阅) ,大家可以在同一文件中看一下是如何实现的.Vue
数据更新机制中的应用工作中小应用举例
redux
进行状态管理.但是在不同的组件(不限于父子组件)之间,存在相关联的异步操作.所以在wepy对象上挂载了一个本文最开始实现的Observer对象.作为部分组件之间通信的总线机制:要注意的点
当然,发布-订阅模式也是有缺点的.
当然设计模式的存在是帮助我们解决特定场景的问题的,学会在正确的场景中使用才是最重要的.
广而告之
本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~
The text was updated successfully, but these errors were encountered: