We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
// packages/runtime-core/src/renderer.ts // createApp -> createAppAPI -> mount -> render -> patch -> processElement -> mountElement -> hostPatchProp(即 patchProp)
// packages/runtime-core/src/renderer.ts const patchProps = ( el: RendererElement, vnode: VNode, oldProps: Data, newProps: Data, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, namespace: ElementNamespace, ) => { // 如果 oldProps !== newProps if (oldProps !== newProps) { if (oldProps !== EMPTY_OBJ) { for (const key in oldProps) { // 非 vue 保留 prop 且 不在 newProps 的 prop if (!isReservedProp(key) && !(key in newProps)) { // 实际执行 renderer options 上的 patchProp 方法 // packages/runtime-dom/src/index.ts // import { patchProp } from './patchProp' // const { patchProp: hostPatchProp } = options hostPatchProp( el, key, oldProps[key], null, namespace, vnode.children as VNode[], parentComponent, parentSuspense, unmountChildren, ) } } } for (const key in newProps) { // 判断是否非 vue 保留 prop(空字符串也在保留字符串内) if (isReservedProp(key)) continue const next = newProps[key] const prev = oldProps[key] // prop 对应新值不等于旧值,且 prop 不是 value if (next !== prev && key !== 'value') { hostPatchProp( el, key, prev, next, namespace, vnode.children as VNode[], parentComponent, parentSuspense, unmountChildren, ) } } // 单独处理 prop 是 value 的情况 if ('value' in newProps) { hostPatchProp(el, 'value', oldProps.value, newProps.value, namespace) } } } // 具体的 patchProp 方法 const patchProp: DOMRendererOptions['patchProp'] = ( el, key, prevValue, nextValue, namespace, prevChildren, parentComponent, parentSuspense, unmountChildren ) => { const isSVG = namespace === "svg"; if (key === "class") { // 处理 class patchClass(el, nextValue, isSVG); } else if (key === "style") { // 处理 style patchStyle(el, prevValue, nextValue); } else if (isOn(key)) { // 处理事件,忽略 v-model 的情况 // 事件的 patch 看这里 if (!isModelListener(key)) { patchEvent(el, key, prevValue, nextValue, parentComponent); } } else if ( key[0] === "." ? ((key = key.slice(1)), true) : key[0] === "^" ? ((key = key.slice(1)), false) : shouldSetAsProp(el, key, nextValue, isSVG) ) { patchDOMProp( el, key, nextValue, prevChildren, parentComponent, parentSuspense, unmountChildren ); // #6007 also set form state as attributes so they work with // <input type="reset"> or libs / extensions that expect attributes if (key === "value" || key === "checked" || key === "selected") { patchAttr(el, key, nextValue, isSVG, parentComponent, key !== "value"); } } else { // special case for <input v-model type="checkbox"> with // :true-value & :false-value // store value as dom properties since non-string values will be // stringified. // 对于 <input v-model type="checkbox"> 且带有 :true-value :false-value 的特殊处理 if (key === "true-value") { el._trueValue = nextValue; } else if (key === "false-value") { el._falseValue = nextValue; } patchAttr(el, key, nextValue, isSVG, parentComponent); } }; // 具体的 patchEvent const veiKey = Symbol('_vei') function patchEvent( el: Element & { [veiKey]?: Record<string, Invoker | undefined> }, rawName: string, prevValue: EventValue | null, nextValue: EventValue | unknown, instance: ComponentInternalInstance | null = null, ) { // vei = vue event invokers const invokers = el[veiKey] || (el[veiKey] = {}) const existingInvoker = invokers[rawName] if (nextValue && existingInvoker) { // 如果存在 新的事件处理函数 且 已经存在 invoker 方法,则把新的处理函数复制到 invoker 方法的 value existingInvoker.value = (nextValue as EventValue) } else { // 解析事件名称 和 事件 options // onClick:Capture = () => console.log(1) // name => click // options = { // capture: true // } const [name, options] = parseName(rawName) if (nextValue) { // 新增事件监听 /***** invoker 是一个伪造的事件处理函数,用来处理提升给事件打补丁时的性能,因为如果不这样处理,那么在打补丁的时候,需要先移除监听,再重新监听。而 invoker 处理之后,通过把事件的处理方法直接替换的方法,减少了一次 移除监听 // 伪代码 const createInvoker = (nextValue) => { const invoker = (e) => { // e.timestmap if (!e._vts) { // 事件发生时间 e._vts = Date.now() } else if (e._vts <= invoker.attached) { // 如果事件发生事件 遭遇 事件处理函数绑定的时间,则不执行事件处理函数 return } // 执行事件绑定的函数 if (Array.isArray(invoker.value)) { invoker.value.map(fn => fn(e)) } else { invoker.value(e) } } // nextValue 真正的事件处理函数 invoker.value = nextValue; // 事件处理函数的 invoker.attached = Date.now(); return invoker } *****/ const invoker = (invokers[rawName] = createInvoker((nextValue as EventValue), instance,)) addEventListener(el, name, invoker, options) } else if (existingInvoker) { // 移除事件监听 removeEventListener(el, name, existingInvoker, options) invokers[rawName] = undefined } } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
The text was updated successfully, but these errors were encountered: