wip: include children type in shapeFlag

This commit is contained in:
Evan You 2019-06-02 19:40:50 +08:00
parent 2f1f6b4355
commit 6d90ba28d3
3 changed files with 72 additions and 39 deletions

View File

@ -14,7 +14,7 @@ import {
createComponentInstance, createComponentInstance,
setupStatefulComponent setupStatefulComponent
} from './component' } from './component'
import { isString, isArray, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared' import { isString, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
import { import {
TEXT, TEXT,
CLASS, CLASS,
@ -28,7 +28,13 @@ import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
import { effect, stop, ReactiveEffectOptions } from '@vue/observer' import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
import { resolveProps } from './componentProps' import { resolveProps } from './componentProps'
import { resolveSlots } from './componentSlots' import { resolveSlots } from './componentSlots'
import { ELEMENT, STATEFUL_COMPONENT, FUNCTIONAL_COMPONENT } from './shapeFlags' import {
ELEMENT,
STATEFUL_COMPONENT,
FUNCTIONAL_COMPONENT,
TEXT_CHILDREN,
ARRAY_CHILDREN
} from './shapeFlags'
const prodEffectOptions = { const prodEffectOptions = {
scheduler: queueJob scheduler: queueJob
@ -193,15 +199,16 @@ export function createRenderer(options: RendererOptions) {
function mountElement(vnode: VNode, container: HostNode, anchor?: HostNode) { function mountElement(vnode: VNode, container: HostNode, anchor?: HostNode) {
const el = (vnode.el = hostCreateElement(vnode.type as string)) const el = (vnode.el = hostCreateElement(vnode.type as string))
if (vnode.props != null) { const { props, shapeFlag } = vnode
for (const key in vnode.props) { if (props != null) {
hostPatchProp(el, key, vnode.props[key], null, false) for (const key in props) {
hostPatchProp(el, key, props[key], null, false)
} }
} }
if (isString(vnode.children)) { if (shapeFlag & TEXT_CHILDREN) {
hostSetElementText(el, vnode.children) hostSetElementText(el, vnode.children as string)
} else if (isArray(vnode.children)) { } else if (shapeFlag & ARRAY_CHILDREN) {
mountChildren(vnode.children, el) mountChildren(vnode.children as VNodeChildren, el)
} }
hostInsert(el, container, anchor) hostInsert(el, container, anchor)
} }
@ -374,16 +381,16 @@ export function createRenderer(options: RendererOptions) {
optimized?: boolean optimized?: boolean
) { ) {
const targetSelector = n2.props && n2.props.target const targetSelector = n2.props && n2.props.target
const { patchFlag, shapeFlag, children } = n2
if (n1 == null) { if (n1 == null) {
const children = n2.children
const target = (n2.target = isString(targetSelector) const target = (n2.target = isString(targetSelector)
? hostQuerySelector(targetSelector) ? hostQuerySelector(targetSelector)
: null) : null)
if (target != null) { if (target != null) {
if (isString(children)) { if (shapeFlag & TEXT_CHILDREN) {
hostSetElementText(target, children) hostSetElementText(target, children as string)
} else if (isArray(children)) { } else if (shapeFlag & ARRAY_CHILDREN) {
mountChildren(children, target) mountChildren(children as VNodeChildren, target)
} }
} else { } else {
// TODO warn missing or invalid target // TODO warn missing or invalid target
@ -391,8 +398,8 @@ export function createRenderer(options: RendererOptions) {
} else { } else {
// update content // update content
const target = (n2.target = n1.target) const target = (n2.target = n1.target)
if (n2.patchFlag === TEXT) { if (patchFlag === TEXT) {
hostSetElementText(target, n2.children as string) hostSetElementText(target, children as string)
} else if (!optimized) { } else if (!optimized) {
patchChildren(n1, n2, target) patchChildren(n1, n2, target)
} }
@ -403,13 +410,12 @@ export function createRenderer(options: RendererOptions) {
: null) : null)
if (nextTarget != null) { if (nextTarget != null) {
// move content // move content
const children = n2.children if (shapeFlag & TEXT_CHILDREN) {
if (isString(children)) {
hostSetElementText(target, '') hostSetElementText(target, '')
hostSetElementText(nextTarget, children) hostSetElementText(nextTarget, children as string)
} else if (isArray(children)) { } else if (shapeFlag & ARRAY_CHILDREN) {
for (let i = 0; i < children.length; i++) { for (let i = 0; i < (children as VNode[]).length; i++) {
move(children[i] as VNode, nextTarget, null) move((children as VNode[])[i], nextTarget, null)
} }
} }
} else { } else {
@ -516,10 +522,11 @@ export function createRenderer(options: RendererOptions) {
optimized?: boolean optimized?: boolean
) { ) {
const c1 = n1 && n1.children const c1 = n1 && n1.children
const prevShapeFlag = n1 ? n1.shapeFlag : 0
const c2 = n2.children const c2 = n2.children
// fast path // fast path
const { patchFlag } = n2 const { patchFlag, shapeFlag } = n2
if (patchFlag) { if (patchFlag) {
if (patchFlag & KEYED) { if (patchFlag & KEYED) {
// this could be either fully-keyed or mixed (some keyed some not) // this could be either fully-keyed or mixed (some keyed some not)
@ -545,22 +552,28 @@ export function createRenderer(options: RendererOptions) {
} }
} }
if (isString(c2)) { if (shapeFlag & TEXT_CHILDREN) {
// text children fast path // text children fast path
if (isArray(c1)) { if (prevShapeFlag & ARRAY_CHILDREN) {
unmountChildren(c1 as VNode[]) unmountChildren(c1 as VNode[])
} }
hostSetElementText(container, c2) hostSetElementText(container, c2 as string)
} else { } else {
if (isString(c1)) { if (prevShapeFlag & TEXT_CHILDREN) {
hostSetElementText(container, '') hostSetElementText(container, '')
if (isArray(c2)) { if (shapeFlag & ARRAY_CHILDREN) {
mountChildren(c2, container, anchor) mountChildren(c2 as VNodeChildren, container, anchor)
} }
} else if (isArray(c1)) { } else if (prevShapeFlag & ARRAY_CHILDREN) {
if (isArray(c2)) { if (shapeFlag & ARRAY_CHILDREN) {
// two arrays, cannot assume anything, do full diff // two arrays, cannot assume anything, do full diff
patchKeyedChildren(c1 as VNode[], c2, container, anchor, optimized) patchKeyedChildren(
c1 as VNode[],
c2 as VNodeChildren,
container,
anchor,
optimized
)
} else { } else {
// c2 is null in this case // c2 is null in this case
unmountChildren(c1 as VNode[], true) unmountChildren(c1 as VNode[], true)
@ -791,7 +804,7 @@ export function createRenderer(options: RendererOptions) {
const shouldRemoveChildren = vnode.type === Fragment && doRemove const shouldRemoveChildren = vnode.type === Fragment && doRemove
if (vnode.dynamicChildren != null) { if (vnode.dynamicChildren != null) {
unmountChildren(vnode.dynamicChildren, shouldRemoveChildren) unmountChildren(vnode.dynamicChildren, shouldRemoveChildren)
} else if (isArray(vnode.children)) { } else if (vnode.shapeFlag & ARRAY_CHILDREN) {
unmountChildren(vnode.children as VNode[], shouldRemoveChildren) unmountChildren(vnode.children as VNode[], shouldRemoveChildren)
} }
if (doRemove) { if (doRemove) {

View File

@ -1,3 +1,6 @@
export const ELEMENT = 1 export const ELEMENT = 1
export const FUNCTIONAL_COMPONENT = 1 << 1 export const FUNCTIONAL_COMPONENT = 1 << 1
export const STATEFUL_COMPONENT = 1 << 2 export const STATEFUL_COMPONENT = 1 << 2
export const TEXT_CHILDREN = 1 << 3
export const ARRAY_CHILDREN = 1 << 4
export const SLOTS_CHILDREN = 1 << 5

View File

@ -3,7 +3,14 @@ import { ComponentInstance } from './component'
import { HostNode } from './createRenderer' import { HostNode } from './createRenderer'
import { RawSlots } from './componentSlots' import { RawSlots } from './componentSlots'
import { CLASS } from './patchFlags' import { CLASS } from './patchFlags'
import { ELEMENT, FUNCTIONAL_COMPONENT, STATEFUL_COMPONENT } from './shapeFlags' import {
ELEMENT,
FUNCTIONAL_COMPONENT,
STATEFUL_COMPONENT,
TEXT_CHILDREN,
ARRAY_CHILDREN,
SLOTS_CHILDREN
} from './shapeFlags'
export const Fragment = Symbol('Fragment') export const Fragment = Symbol('Fragment')
export const Text = Symbol('Text') export const Text = Symbol('Text')
@ -95,8 +102,10 @@ export function createVNode(
): VNode { ): VNode {
// Allow passing 0 for props, this can save bytes on generated code. // Allow passing 0 for props, this can save bytes on generated code.
props = props || null props = props || null
// normalize children
children = normalizeChildren(children) as NormalizedChildren
const shapeFlag = isString(type) const typeFlag = isString(type)
? ELEMENT ? ELEMENT
: isFunction(type) : isFunction(type)
? FUNCTIONAL_COMPONENT ? FUNCTIONAL_COMPONENT
@ -104,16 +113,24 @@ export function createVNode(
? STATEFUL_COMPONENT ? STATEFUL_COMPONENT
: 0 : 0
const childFlag = isString(children)
? TEXT_CHILDREN
: isArray(children)
? ARRAY_CHILDREN
: isObject(children)
? SLOTS_CHILDREN
: 0
const vnode: VNode = { const vnode: VNode = {
type, type,
props, props,
key: props && props.key, key: props && props.key,
children: normalizeChildren(children), children,
component: null, component: null,
el: null, el: null,
anchor: null, anchor: null,
target: null, target: null,
shapeFlag, shapeFlag: typeFlag | childFlag,
patchFlag, patchFlag,
dynamicProps, dynamicProps,
dynamicChildren: null dynamicChildren: null
@ -138,8 +155,8 @@ export function createVNode(
if ( if (
shouldTrack && shouldTrack &&
(patchFlag || (patchFlag ||
shapeFlag & STATEFUL_COMPONENT || typeFlag & STATEFUL_COMPONENT ||
shapeFlag & FUNCTIONAL_COMPONENT) typeFlag & FUNCTIONAL_COMPONENT)
) { ) {
trackDynamicNode(vnode) trackDynamicNode(vnode)
} }