Browse Source

refactor: split vdom helpers into separate files

dev
Evan You 8 years ago
parent
commit
e774ce2353
  1. 2
      src/core/components/keep-alive.js
  2. 2
      src/core/instance/events.js
  3. 2
      src/core/instance/render.js
  4. 2
      src/core/vdom/create-component.js
  5. 2
      src/core/vdom/create-element.js
  6. 148
      src/core/vdom/helpers.js
  7. 9
      src/core/vdom/helpers/index.js
  8. 18
      src/core/vdom/helpers/merge-hook.js
  9. 62
      src/core/vdom/helpers/normalize-children.js
  10. 68
      src/core/vdom/helpers/update-listeners.js
  11. 2
      src/core/vdom/modules/directives.js
  12. 2
      src/platforms/web/runtime/components/transition.js
  13. 2
      src/platforms/web/runtime/modules/events.js
  14. 2
      src/platforms/web/runtime/modules/transition.js

2
src/core/components/keep-alive.js

@ -1,5 +1,5 @@
import { callHook } from 'core/instance/lifecycle' import { callHook } from 'core/instance/lifecycle'
import { getFirstComponentChild } from 'core/vdom/helpers' import { getFirstComponentChild } from 'core/vdom/helpers/index'
export default { export default {
name: 'keep-alive', name: 'keep-alive',

2
src/core/instance/events.js

@ -1,7 +1,7 @@
/* @flow */ /* @flow */
import { bind, toArray } from '../util/index' import { bind, toArray } from '../util/index'
import { updateListeners } from '../vdom/helpers' import { updateListeners } from '../vdom/helpers/index'
export function initEvents (vm: Component) { export function initEvents (vm: Component) {
vm._events = Object.create(null) vm._events = Object.create(null)

2
src/core/instance/render.js

@ -2,7 +2,7 @@
import config from '../config' import config from '../config'
import VNode, { emptyVNode, cloneVNode, cloneVNodes } from '../vdom/vnode' import VNode, { emptyVNode, cloneVNode, cloneVNodes } from '../vdom/vnode'
import { normalizeChildren } from '../vdom/helpers' import { normalizeChildren } from '../vdom/helpers/index'
import { import {
warn, formatComponentName, bind, isObject, toObject, warn, formatComponentName, bind, isObject, toObject,
nextTick, resolveAsset, _toString, toNumber, looseEqual, looseIndexOf nextTick, resolveAsset, _toString, toNumber, looseEqual, looseIndexOf

2
src/core/vdom/create-component.js

@ -2,7 +2,7 @@
import Vue from '../instance/index' import Vue from '../instance/index'
import VNode from './vnode' import VNode from './vnode'
import { normalizeChildren } from './helpers' import { normalizeChildren } from './helpers/index'
import { activeInstance, callHook } from '../instance/lifecycle' import { activeInstance, callHook } from '../instance/lifecycle'
import { resolveSlots } from '../instance/render' import { resolveSlots } from '../instance/render'
import { createElement } from './create-element' import { createElement } from './create-element'

2
src/core/vdom/create-element.js

@ -3,7 +3,7 @@
import VNode, { emptyVNode } from './vnode' import VNode, { emptyVNode } from './vnode'
import config from '../config' import config from '../config'
import { createComponent } from './create-component' import { createComponent } from './create-component'
import { normalizeChildren } from './helpers' import { normalizeChildren } from './helpers/index'
import { warn, resolveAsset } from '../util/index' import { warn, resolveAsset } from '../util/index'
// wrapper function for providing a more flexible interface // wrapper function for providing a more flexible interface

148
src/core/vdom/helpers.js

@ -1,148 +0,0 @@
/* @flow */
import { isPrimitive, warn } from '../util/index'
import VNode from './vnode'
export function normalizeChildren (
children: any,
ns: string | void,
nestedIndex: number | void
): Array<VNode> | void {
if (isPrimitive(children)) {
return [createTextVNode(children)]
}
if (Array.isArray(children)) {
const res = []
for (let i = 0, l = children.length; i < l; i++) {
const c = children[i]
const last = res[res.length - 1]
// nested
if (Array.isArray(c)) {
res.push.apply(res, normalizeChildren(c, ns, i))
} else if (isPrimitive(c)) {
if (last && last.text) {
last.text += String(c)
} else if (c !== '') {
// convert primitive to vnode
res.push(createTextVNode(c))
}
} else if (c instanceof VNode) {
if (c.text && last && last.text) {
last.text += c.text
} else {
// inherit parent namespace
if (ns) {
applyNS(c, ns)
}
// default key for nested array children (likely generated by v-for)
if (c.tag && c.key == null && nestedIndex != null) {
c.key = `__vlist_${nestedIndex}_${i}__`
}
res.push(c)
}
}
}
return res
}
}
function createTextVNode (val) {
return new VNode(undefined, undefined, undefined, String(val))
}
function applyNS (vnode, ns) {
if (vnode.tag && !vnode.ns) {
vnode.ns = ns
if (vnode.children) {
for (let i = 0, l = vnode.children.length; i < l; i++) {
applyNS(vnode.children[i], ns)
}
}
}
}
export function getFirstComponentChild (children: ?Array<any>) {
return children && children.filter(c => c && c.componentOptions)[0]
}
export function mergeVNodeHook (def: Object, hookKey: string, hook: Function, key: string) {
key = key + hookKey
const injectedHash = def.__injected || (def.__injected = {})
if (!injectedHash[key]) {
injectedHash[key] = true
const oldHook = def[hookKey]
if (oldHook) {
def[hookKey] = function () {
oldHook.apply(this, arguments)
hook.apply(this, arguments)
}
} else {
def[hookKey] = hook
}
}
}
export function updateListeners (
on: Object,
oldOn: Object,
add: Function,
remove: Function,
vm: Component
) {
let name, cur, old, fn, event, capture
for (name in on) {
cur = on[name]
old = oldOn[name]
if (!cur) {
process.env.NODE_ENV !== 'production' && warn(
`Invalid handler for event "${name}": got ` + String(cur),
vm
)
} else if (!old) {
capture = name.charAt(0) === '!'
event = capture ? name.slice(1) : name
if (Array.isArray(cur)) {
add(event, (cur.invoker = arrInvoker(cur)), capture)
} else {
if (!cur.invoker) {
fn = cur
cur = on[name] = {}
cur.fn = fn
cur.invoker = fnInvoker(cur)
}
add(event, cur.invoker, capture)
}
} else if (cur !== old) {
if (Array.isArray(old)) {
old.length = cur.length
for (let i = 0; i < old.length; i++) old[i] = cur[i]
on[name] = old
} else {
old.fn = cur
on[name] = old
}
}
}
for (name in oldOn) {
if (!on[name]) {
event = name.charAt(0) === '!' ? name.slice(1) : name
remove(event, oldOn[name].invoker)
}
}
}
function arrInvoker (arr: Array<Function>): Function {
return function (ev) {
const single = arguments.length === 1
for (let i = 0; i < arr.length; i++) {
single ? arr[i](ev) : arr[i].apply(null, arguments)
}
}
}
function fnInvoker (o: { fn: Function }): Function {
return function (ev) {
const single = arguments.length === 1
single ? o.fn(ev) : o.fn.apply(null, arguments)
}
}

9
src/core/vdom/helpers/index.js

@ -0,0 +1,9 @@
/* @flow */
export * from './merge-hook'
export * from './update-listeners'
export * from './normalize-children'
export function getFirstComponentChild (children: ?Array<any>): ?VNodeWithData {
return children && children.filter(c => c && c.componentOptions)[0]
}

18
src/core/vdom/helpers/merge-hook.js

@ -0,0 +1,18 @@
/* @flow */
export function mergeVNodeHook (def: Object, hookKey: string, hook: Function, key: string) {
key = key + hookKey
const injectedHash = def.__injected || (def.__injected = {})
if (!injectedHash[key]) {
injectedHash[key] = true
const oldHook = def[hookKey]
if (oldHook) {
def[hookKey] = function () {
oldHook.apply(this, arguments)
hook.apply(this, arguments)
}
} else {
def[hookKey] = hook
}
}
}

62
src/core/vdom/helpers/normalize-children.js

@ -0,0 +1,62 @@
/* @flow */
import { isPrimitive } from 'core/util/index'
import VNode from 'core/vdom/vnode'
export function normalizeChildren (
children: any,
ns: string | void,
nestedIndex: number | void
): Array<VNode> | void {
if (isPrimitive(children)) {
return [createTextVNode(children)]
}
if (Array.isArray(children)) {
const res = []
for (let i = 0, l = children.length; i < l; i++) {
const c = children[i]
const last = res[res.length - 1]
// nested
if (Array.isArray(c)) {
res.push.apply(res, normalizeChildren(c, ns, i))
} else if (isPrimitive(c)) {
if (last && last.text) {
last.text += String(c)
} else if (c !== '') {
// convert primitive to vnode
res.push(createTextVNode(c))
}
} else if (c instanceof VNode) {
if (c.text && last && last.text) {
last.text += c.text
} else {
// inherit parent namespace
if (ns) {
applyNS(c, ns)
}
// default key for nested array children (likely generated by v-for)
if (c.tag && c.key == null && nestedIndex != null) {
c.key = `__vlist_${nestedIndex}_${i}__`
}
res.push(c)
}
}
}
return res
}
}
function createTextVNode (val) {
return new VNode(undefined, undefined, undefined, String(val))
}
function applyNS (vnode, ns) {
if (vnode.tag && !vnode.ns) {
vnode.ns = ns
if (vnode.children) {
for (let i = 0, l = vnode.children.length; i < l; i++) {
applyNS(vnode.children[i], ns)
}
}
}
}

68
src/core/vdom/helpers/update-listeners.js

@ -0,0 +1,68 @@
/* @flow */
import { warn } from 'core/util/index'
export function updateListeners (
on: Object,
oldOn: Object,
add: Function,
remove: Function,
vm: Component
) {
let name, cur, old, fn, event, capture
for (name in on) {
cur = on[name]
old = oldOn[name]
if (!cur) {
process.env.NODE_ENV !== 'production' && warn(
`Invalid handler for event "${name}": got ` + String(cur),
vm
)
} else if (!old) {
capture = name.charAt(0) === '!'
event = capture ? name.slice(1) : name
if (Array.isArray(cur)) {
add(event, (cur.invoker = arrInvoker(cur)), capture)
} else {
if (!cur.invoker) {
fn = cur
cur = on[name] = {}
cur.fn = fn
cur.invoker = fnInvoker(cur)
}
add(event, cur.invoker, capture)
}
} else if (cur !== old) {
if (Array.isArray(old)) {
old.length = cur.length
for (let i = 0; i < old.length; i++) old[i] = cur[i]
on[name] = old
} else {
old.fn = cur
on[name] = old
}
}
}
for (name in oldOn) {
if (!on[name]) {
event = name.charAt(0) === '!' ? name.slice(1) : name
remove(event, oldOn[name].invoker)
}
}
}
function arrInvoker (arr: Array<Function>): Function {
return function (ev) {
const single = arguments.length === 1
for (let i = 0; i < arr.length; i++) {
single ? arr[i](ev) : arr[i].apply(null, arguments)
}
}
}
function fnInvoker (o: { fn: Function }): Function {
return function (ev) {
const single = arguments.length === 1
single ? o.fn(ev) : o.fn.apply(null, arguments)
}
}

2
src/core/vdom/modules/directives.js

@ -1,7 +1,7 @@
/* @flow */ /* @flow */
import { resolveAsset } from 'core/util/options' import { resolveAsset } from 'core/util/options'
import { mergeVNodeHook } from 'core/vdom/helpers' import { mergeVNodeHook } from 'core/vdom/helpers/index'
import { emptyNode } from 'core/vdom/patch' import { emptyNode } from 'core/vdom/patch'
export default { export default {

2
src/platforms/web/runtime/components/transition.js

@ -5,7 +5,7 @@
import { warn } from 'core/util/index' import { warn } from 'core/util/index'
import { camelize, extend } from 'shared/util' import { camelize, extend } from 'shared/util'
import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers' import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers/index'
export const transitionProps = { export const transitionProps = {
name: String, name: String,

2
src/platforms/web/runtime/modules/events.js

@ -1,7 +1,7 @@
// skip type checking this file because we need to attach private properties // skip type checking this file because we need to attach private properties
// to elements // to elements
import { updateListeners } from 'core/vdom/helpers' import { updateListeners } from 'core/vdom/helpers/index'
function updateDOMListeners (oldVnode, vnode) { function updateDOMListeners (oldVnode, vnode) {
if (!oldVnode.data.on && !vnode.data.on) { if (!oldVnode.data.on && !vnode.data.on) {

2
src/platforms/web/runtime/modules/transition.js

@ -2,7 +2,7 @@
import { inBrowser, isIE9 } from 'core/util/index' import { inBrowser, isIE9 } from 'core/util/index'
import { cached, extend } from 'shared/util' import { cached, extend } from 'shared/util'
import { mergeVNodeHook } from 'core/vdom/helpers' import { mergeVNodeHook } from 'core/vdom/helpers/index'
import { activeInstance } from 'core/instance/lifecycle' import { activeInstance } from 'core/instance/lifecycle'
import { import {
nextFrame, nextFrame,

Loading…
Cancel
Save