wip: refs
This commit is contained in:
parent
0ad31f29c4
commit
2848f65a7f
@ -7,7 +7,8 @@ import {
|
|||||||
isString,
|
isString,
|
||||||
isFunction,
|
isFunction,
|
||||||
isArray,
|
isArray,
|
||||||
isObject
|
isObject,
|
||||||
|
isReservedProp
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { Data, ComponentInstance } from './component'
|
import { Data, ComponentInstance } from './component'
|
||||||
@ -101,10 +102,8 @@ export function resolveProps(
|
|||||||
|
|
||||||
if (rawProps != null) {
|
if (rawProps != null) {
|
||||||
for (const key in rawProps) {
|
for (const key in rawProps) {
|
||||||
// key, ref, slots are reserved
|
// key, ref are reserved
|
||||||
if (key === 'key' || key === 'ref' || key === 'slots') {
|
if (isReservedProp(key)) continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
// any non-declared data are put into a separate `attrs` object
|
// any non-declared data are put into a separate `attrs` object
|
||||||
// for spreading
|
// for spreading
|
||||||
if (hasDeclaredProps && !options.hasOwnProperty(key)) {
|
if (hasDeclaredProps && !options.hasOwnProperty(key)) {
|
||||||
|
@ -19,6 +19,12 @@ export const RenderProxyHandlers = {
|
|||||||
return target.slots
|
return target.slots
|
||||||
case '$refs':
|
case '$refs':
|
||||||
return target.refs
|
return target.refs
|
||||||
|
case '$parent':
|
||||||
|
return target.parent
|
||||||
|
case '$root':
|
||||||
|
return target.root
|
||||||
|
case '$el':
|
||||||
|
return target.vnode && target.vnode.el
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,13 @@ import {
|
|||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setupStatefulComponent
|
setupStatefulComponent
|
||||||
} from './component'
|
} from './component'
|
||||||
import { isString, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
|
import {
|
||||||
|
isString,
|
||||||
|
EMPTY_OBJ,
|
||||||
|
EMPTY_ARR,
|
||||||
|
isReservedProp,
|
||||||
|
isFunction
|
||||||
|
} from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
TEXT,
|
TEXT,
|
||||||
CLASS,
|
CLASS,
|
||||||
@ -225,12 +231,14 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) {
|
) {
|
||||||
// mount
|
|
||||||
if (n1 == null) {
|
if (n1 == null) {
|
||||||
mountElement(n2, container, anchor, parentComponent, isSVG)
|
mountElement(n2, container, anchor, parentComponent, isSVG)
|
||||||
} else {
|
} else {
|
||||||
patchElement(n1, n2, parentComponent, isSVG, optimized)
|
patchElement(n1, n2, parentComponent, isSVG, optimized)
|
||||||
}
|
}
|
||||||
|
if (n2.ref !== null && parentComponent !== null) {
|
||||||
|
setRef(n2.ref, parentComponent, n2.el)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mountElement(
|
function mountElement(
|
||||||
@ -246,6 +254,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
const { props, shapeFlag } = vnode
|
const { props, shapeFlag } = vnode
|
||||||
if (props != null) {
|
if (props != null) {
|
||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
|
if (isReservedProp(key)) continue
|
||||||
hostPatchProp(el, key, props[key], null, isSVG)
|
hostPatchProp(el, key, props[key], null, isSVG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,7 +394,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
) {
|
) {
|
||||||
if (oldProps !== newProps) {
|
if (oldProps !== newProps) {
|
||||||
for (const key in newProps) {
|
for (const key in newProps) {
|
||||||
if (key === 'key' || key === 'ref') continue
|
if (isReservedProp(key)) continue
|
||||||
const next = newProps[key]
|
const next = newProps[key]
|
||||||
const prev = oldProps[key]
|
const prev = oldProps[key]
|
||||||
if (next !== prev) {
|
if (next !== prev) {
|
||||||
@ -402,7 +411,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
}
|
}
|
||||||
if (oldProps !== EMPTY_OBJ) {
|
if (oldProps !== EMPTY_OBJ) {
|
||||||
for (const key in oldProps) {
|
for (const key in oldProps) {
|
||||||
if (key === 'key' || key === 'ref') continue
|
if (isReservedProp(key)) continue
|
||||||
if (!(key in newProps)) {
|
if (!(key in newProps)) {
|
||||||
hostPatchProp(
|
hostPatchProp(
|
||||||
el,
|
el,
|
||||||
@ -539,6 +548,13 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
n2.el = n1.el
|
n2.el = n1.el
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (n2.ref !== null && parentComponent !== null) {
|
||||||
|
setRef(
|
||||||
|
n2.ref,
|
||||||
|
parentComponent,
|
||||||
|
(n2.component as ComponentInstance).renderProxy
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mountComponent(
|
function mountComponent(
|
||||||
@ -553,9 +569,9 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
Component,
|
Component,
|
||||||
parentComponent
|
parentComponent
|
||||||
))
|
))
|
||||||
instance.update = effect(function updateComponent() {
|
instance.update = effect(function componentEffect() {
|
||||||
if (instance.vnode === null) {
|
if (instance.vnode === null) {
|
||||||
// initial mount
|
// mountComponent
|
||||||
instance.vnode = initialVNode
|
instance.vnode = initialVNode
|
||||||
resolveProps(instance, initialVNode.props, Component.props)
|
resolveProps(instance, initialVNode.props, Component.props)
|
||||||
resolveSlots(instance, initialVNode.children)
|
resolveSlots(instance, initialVNode.children)
|
||||||
@ -575,7 +591,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
queuePostFlushCb(instance.m)
|
queuePostFlushCb(instance.m)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// component update
|
// updateComponent
|
||||||
// This is triggered by mutation of component's own state (next: null)
|
// This is triggered by mutation of component's own state (next: null)
|
||||||
// OR parent calling processComponent (next: VNode)
|
// OR parent calling processComponent (next: VNode)
|
||||||
const { next } = instance
|
const { next } = instance
|
||||||
@ -593,11 +609,17 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
if (instance.bu !== null) {
|
if (instance.bu !== null) {
|
||||||
invokeHooks(instance.bu)
|
invokeHooks(instance.bu)
|
||||||
}
|
}
|
||||||
|
// reset refs
|
||||||
|
// only needed if previous patch had refs
|
||||||
|
if (instance.refs !== EMPTY_OBJ) {
|
||||||
|
instance.refs = {}
|
||||||
|
}
|
||||||
patch(
|
patch(
|
||||||
prevTree,
|
prevTree,
|
||||||
nextTree,
|
nextTree,
|
||||||
// may have moved
|
// parent may have changed if it's in a portal
|
||||||
hostParentNode(prevTree.el),
|
hostParentNode(prevTree.el),
|
||||||
|
// anchor may have changed if it's in a fragment
|
||||||
getNextHostNode(prevTree),
|
getNextHostNode(prevTree),
|
||||||
instance,
|
instance,
|
||||||
isSVG
|
isSVG
|
||||||
@ -944,7 +966,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function move(vnode: VNode, container: HostNode, anchor: HostNode) {
|
function move(vnode: VNode, container: HostNode, anchor: HostNode) {
|
||||||
if (vnode.component != null) {
|
if (vnode.component !== null) {
|
||||||
move(vnode.component.subTree, container, anchor)
|
move(vnode.component.subTree, container, anchor)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1015,6 +1037,22 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
: getNextHostNode(vnode.component.subTree)
|
: getNextHostNode(vnode.component.subTree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setRef(
|
||||||
|
ref: string | Function,
|
||||||
|
parent: ComponentInstance,
|
||||||
|
value: HostNode | ComponentInstance
|
||||||
|
) {
|
||||||
|
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
|
||||||
|
if (isString(ref)) {
|
||||||
|
refs[ref] = value
|
||||||
|
} else {
|
||||||
|
if (__DEV__ && !isFunction(ref)) {
|
||||||
|
// TODO warn invalid ref type
|
||||||
|
}
|
||||||
|
ref(value, refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return function render(vnode: VNode | null, dom: HostNode): VNode | null {
|
return function render(vnode: VNode | null, dom: HostNode): VNode | null {
|
||||||
if (vnode == null) {
|
if (vnode == null) {
|
||||||
if (dom._vnode) {
|
if (dom._vnode) {
|
||||||
|
@ -49,3 +49,7 @@ export const UNKEYED = 1 << 6
|
|||||||
// iterated value, or dynamic slot names).
|
// iterated value, or dynamic slot names).
|
||||||
// Components with this flag are always force updated.
|
// Components with this flag are always force updated.
|
||||||
export const DYNAMIC_SLOTS = 1 << 7
|
export const DYNAMIC_SLOTS = 1 << 7
|
||||||
|
|
||||||
|
// Indicates an element with ref. This includes static string refs because the
|
||||||
|
// refs object is refreshed on each update and all refs need to set again.
|
||||||
|
export const REF = 1 << 8
|
||||||
|
@ -35,6 +35,7 @@ export interface VNode {
|
|||||||
type: VNodeTypes
|
type: VNodeTypes
|
||||||
props: { [key: string]: any } | null
|
props: { [key: string]: any } | null
|
||||||
key: string | number | null
|
key: string | number | null
|
||||||
|
ref: string | Function | null
|
||||||
children: NormalizedChildren
|
children: NormalizedChildren
|
||||||
component: ComponentInstance | null
|
component: ComponentInstance | null
|
||||||
|
|
||||||
@ -65,6 +66,9 @@ const blockStack: (VNode[] | null)[] = []
|
|||||||
// function render() {
|
// function render() {
|
||||||
// return (openBlock(),createBlock('div', null, [...]))
|
// return (openBlock(),createBlock('div', null, [...]))
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// disableTracking is true when creating a fragment block, since a fragment
|
||||||
|
// always diffs its children.
|
||||||
export function openBlock(disableTrackng?: boolean) {
|
export function openBlock(disableTrackng?: boolean) {
|
||||||
blockStack.push(disableTrackng ? null : [])
|
blockStack.push(disableTrackng ? null : [])
|
||||||
}
|
}
|
||||||
@ -116,6 +120,7 @@ export function createVNode(
|
|||||||
type,
|
type,
|
||||||
props,
|
props,
|
||||||
key: props && props.key,
|
key: props && props.key,
|
||||||
|
ref: props && props.ref,
|
||||||
children: null,
|
children: null,
|
||||||
component: null,
|
component: null,
|
||||||
el: null,
|
el: null,
|
||||||
|
@ -14,6 +14,9 @@ export const isString = (val: any): val is string => typeof val === 'string'
|
|||||||
export const isObject = (val: any): val is Record<any, any> =>
|
export const isObject = (val: any): val is Record<any, any> =>
|
||||||
val !== null && typeof val === 'object'
|
val !== null && typeof val === 'object'
|
||||||
|
|
||||||
|
export const isReservedProp = (key: string): boolean =>
|
||||||
|
key === 'key' || key === 'ref'
|
||||||
|
|
||||||
const camelizeRE = /-(\w)/g
|
const camelizeRE = /-(\w)/g
|
||||||
export const camelize = (str: string): string => {
|
export const camelize = (str: string): string => {
|
||||||
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
|
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user