/** * 触发实例上的指定事件,vm._event[event] => cbs => loop cbs => cb(args) * @param {*} event 事件名 * @returns */ Vue.prototype.$emit = function (event: string): Component { constvm: Component = this if (process.env.NODE_ENV !== 'production') { // 将事件名转换为小些 const lowerCaseEvent = event.toLowerCase() // 意思是说,HTML 属性不区分大小写,所以你不能使用 v-on 监听小驼峰形式的事件名(eventName),而应该使用连字符形式的事件名(event-name) 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}".` ) } } // 从 vm._event 对象上拿到当前事件的回调函数数组,并一次调用数组中的回调函数,并且传递提供的参数 let cbs = vm._events[event] if (cbs) { cbs = cbs.length > 1 ? toArray(cbs) : cbs const args = toArray(arguments, 1) const info = `event handler for "${event}"` for (let i = 0, l = cbs.length; i < l; i++) { invokeWithErrorHandling(cbs[i], vm, args, vm, info) } } return vm }
/** * 负责更新页面,页面首次渲染和后续更新的入口位置,也是 patch 的入口位置 */ Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { constvm: Component = this const prevEl = vm.$el const prevVnode = vm._vnode const restoreActiveInstance = setActiveInstance(vm) vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (!prevVnode) { // 首次渲染,即初始化页面时走这里 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false/* removeOnly */) } else { // 响应式数据更新时,即更新页面时走这里 vm.$el = vm.__patch__(prevVnode, vnode) } restoreActiveInstance() // update __vue__ reference if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. }
vm.$forceUpdate
1 2 3 4 5 6 7 8 9 10
/** * 直接调用 watcher.update 方法,迫使组件重新渲染。 * 它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件 */ Vue.prototype.$forceUpdate = function () { constvm: Component = this if (vm._watcher) { vm._watcher.update() } }