瀏覽代碼

restructure

Evan You 10 年之前
父節點
當前提交
4512406f77

+ 4 - 4
build/build.js

@@ -26,7 +26,7 @@ fs.writeFileSync('src/runtime/index.js', main)
 // runtime only, because it's meant to be
 // used with vue-loader which pre-compiles the template.
 rollup.rollup({
-  entry: 'src/runtime/index.js',
+  entry: 'src/entries/web-runtime.js',
   plugins: [babel()]
 })
 .then(function (bundle) {
@@ -39,7 +39,7 @@ rollup.rollup({
 // production CommonJS build, just for file size monitoring.
 .then(function () {
   return rollup.rollup({
-    entry: 'src/runtime/index.js',
+    entry: 'src/entries/web-runtime',
     plugins: [
       replace({
         'process.env.NODE_ENV': "'production'"
@@ -75,7 +75,7 @@ rollup.rollup({
 // Standalone Dev Build
 .then(function () {
   return rollup.rollup({
-    entry: 'src/runtime-with-compiler.js',
+    entry: 'src/entries/web-runtime-with-compiler.js',
     plugins: [
       alias({
         entities: './entity-decoder'
@@ -97,7 +97,7 @@ rollup.rollup({
 .then(function () {
   // Standalone Production Build
   return rollup.rollup({
-    entry: 'src/runtime-with-compiler.js',
+    entry: 'src/entries/web-runtime-with-compiler.js',
     plugins: [
       alias({
         entities: './entity-decoder'

+ 1 - 1
build/dev-entry.js

@@ -1 +1 @@
-module.exports = require('../src/runtime-with-compiler')['default']
+module.exports = require('../src/entries/web-runtime-with-compiler')['default']

+ 22 - 4
src/runtime-with-compiler.js → src/entries/web-runtime-with-compiler.js

@@ -1,7 +1,7 @@
-import config from './runtime/config'
-import { compile } from './compiler/index'
-import { getOuterHTML, query, warn } from './runtime/util/index'
-import Vue from './runtime/index'
+import config from '../runtime/config'
+import { compile } from '../compiler/index'
+import { query, warn } from '../runtime/util/index'
+import Vue from './web-runtime'
 
 const mount = Vue.prototype.$mount
 const idTemplateCache = Object.create(null)
@@ -38,6 +38,24 @@ Vue.prototype.$mount = function (el) {
   mount.call(this, el)
 }
 
+/**
+ * Get outerHTML of elements, taking care
+ * of SVG elements in IE as well.
+ *
+ * @param {Element} el
+ * @return {String}
+ */
+
+export function getOuterHTML (el) {
+  if (el.outerHTML) {
+    return el.outerHTML
+  } else {
+    var container = document.createElement('div')
+    container.appendChild(el.cloneNode(true))
+    return container.innerHTML
+  }
+}
+
 Vue.compile = compile
 
 export default Vue

+ 6 - 0
src/entries/web-runtime.js

@@ -0,0 +1,6 @@
+import Vue from '../runtime/index'
+import { update } from '../runtime/dom-updater/index'
+
+Vue.prototype.__update__ = update
+
+export default Vue

+ 20 - 0
src/runtime/dom-updater/index.js

@@ -0,0 +1,20 @@
+import createUpdater from '../vdom/create-updater'
+import * as nodeOps from './node-ops'
+import classes from './modules/class'
+import style from './modules/style'
+import props from './modules/props'
+import attrs from './modules/attrs'
+import events from './modules/events'
+import directives from './modules/directives'
+
+export const update = createUpdater({
+  nodeOps,
+  modules: [
+    classes,
+    props,
+    attrs,
+    style,
+    events,
+    directives
+  ]
+})

+ 0 - 0
src/runtime/vdom/modules/attrs.js → src/runtime/dom-updater/modules/attrs.js


+ 32 - 13
src/runtime/vdom/modules/class.js → src/runtime/dom-updater/modules/class.js

@@ -1,4 +1,19 @@
-import { isArray, isObject, setClass } from '../../util/index'
+import { isIE9, isArray, isObject } from '../../util/index'
+
+function updateClass (oldVnode, vnode) {
+  let dynamicClass = vnode.data.class
+  let staticClass = vnode.data.staticClass
+  if (staticClass || dynamicClass) {
+    dynamicClass = genClass(dynamicClass)
+    let cls = staticClass
+      ? staticClass + (dynamicClass ? ' ' + dynamicClass : '')
+      : dynamicClass
+    if (cls !== oldVnode.class) {
+      setClass(vnode.elm, cls)
+    }
+    vnode.class = cls
+  }
+}
 
 function genClass (data) {
   if (!data) {
@@ -23,18 +38,22 @@ function genClass (data) {
   }
 }
 
-function updateClass (oldVnode, vnode) {
-  let dynamicClass = vnode.data.class
-  let staticClass = vnode.data.staticClass
-  if (staticClass || dynamicClass) {
-    dynamicClass = genClass(dynamicClass)
-    let cls = staticClass
-      ? staticClass + (dynamicClass ? ' ' + dynamicClass : '')
-      : dynamicClass
-    if (cls !== oldVnode.class) {
-      setClass(vnode.elm, cls)
-    }
-    vnode.class = cls
+/**
+ * In IE9, setAttribute('class') will result in empty class
+ * if the element also has the :class attribute; However in
+ * PhantomJS, setting `className` does not work on SVG elements...
+ * So we have to do a conditional check here.
+ *
+ * @param {Element} el
+ * @param {String} cls
+ */
+
+export function setClass (el, cls) {
+  /* istanbul ignore if */
+  if (isIE9 && !/svg$/.test(el.namespaceURI)) {
+    el.className = cls
+  } else {
+    el.setAttribute('class', cls)
   }
 }
 

+ 0 - 0
src/runtime/vdom/modules/directives.js → src/runtime/dom-updater/modules/directives.js


+ 14 - 0
src/runtime/dom-updater/modules/events.js

@@ -0,0 +1,14 @@
+import { updateListeners } from '../../vdom/helpers'
+
+function updateDOMListeners (oldVnode, vnode) {
+  const on = vnode.data.on
+  const oldOn = oldVnode.data.on || {}
+  updateListeners(on, oldOn, (event, handler, capture) => {
+    vnode.elm.addEventListener(event, handler, capture)
+  })
+}
+
+export default {
+  create: updateDOMListeners,
+  update: updateDOMListeners
+}

+ 0 - 0
src/runtime/vdom/modules/pre.js → src/runtime/dom-updater/modules/pre.js


+ 0 - 0
src/runtime/vdom/modules/props.js → src/runtime/dom-updater/modules/props.js


+ 0 - 0
src/runtime/vdom/modules/style.js → src/runtime/dom-updater/modules/style.js


+ 0 - 0
src/runtime/vdom/dom.js → src/runtime/dom-updater/node-ops.js


+ 1 - 1
src/runtime/instance/events.js

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

+ 32 - 8
src/runtime/instance/lifecycle.js

@@ -40,14 +40,7 @@ export function lifecycleMixin (Vue) {
     callHook(this, 'beforeMount')
     el = this.$el = el && query(el)
     if (el) {
-      // clean element
-      el.innerHTML = ''
-      if (el.hasAttributes()) {
-        const attrs = toArray(el.attributes)
-        for (let i = 0; i < attrs.length; i++) {
-          el.removeAttribute(attrs[i].name)
-        }
-      }
+      cleanElement(el)
     }
     this._watcher = new Watcher(this, this._render, this._update)
     this._update(this._watcher.value)
@@ -60,6 +53,27 @@ export function lifecycleMixin (Vue) {
     return this
   }
 
+  Vue.prototype._update = function (vnode) {
+    if (this._mounted) {
+      callHook(this, 'beforeUpdate')
+    }
+    if (!this._vnode) {
+      // Vue.prototype.__update__ is injected in entry points
+      // based on the rendering backend used.
+      this.$el = this.__update__(this.$el, vnode)
+    } else {
+      this.$el = this.__update__(this._vnode, vnode)
+    }
+    this._vnode = vnode
+    if (this._mounted) {
+      callHook(this, 'updated')
+    }
+  }
+
+  Vue.prototype.$forceUpdate = function () {
+    this._watcher.update()
+  }
+
   Vue.prototype.$destroy = function () {
     if (this._isDestroyed) {
       return
@@ -103,3 +117,13 @@ export function callHook (vm, hook) {
   }
   vm.$emit('hook:' + hook)
 }
+
+function cleanElement (el) {
+  el.innerHTML = ''
+  if (el.hasAttributes()) {
+    const attrs = toArray(el.attributes)
+    for (let i = 0; i < attrs.length; i++) {
+      el.removeAttribute(attrs[i].name)
+    }
+  }
+}

+ 3 - 27
src/runtime/instance/render.js

@@ -1,11 +1,6 @@
-import { callHook } from './lifecycle'
 import { observerState } from '../observer/index'
-import {
-  createElement,
-  patch,
-  updateListeners,
-  flatten
-} from '../vdom/index'
+import createElement from '../vdom/create-element'
+import { flatten, updateListeners } from '../vdom/helpers'
 import {
   bind,
   resolveAsset,
@@ -24,7 +19,7 @@ export function initRender (vm) {
   vm.$slots = {}
   // bind the public createElement fn to this instance
   // so that we get proper render context inside it.
-  vm.$createElement = bind(vm.__h__, vm)
+  vm.$createElement = bind(createElement, vm)
   if (vm.$options.el) {
     vm.$mount(vm.$options.el)
   }
@@ -94,21 +89,6 @@ export function renderMixin (Vue) {
     }
   }
 
-  Vue.prototype._update = function (vnode) {
-    if (this._mounted) {
-      callHook(this, 'beforeUpdate')
-    }
-    if (!this._vnode) {
-      this.$el = patch(this.$el, vnode)
-    } else {
-      this.$el = patch(this._vnode, vnode)
-    }
-    this._vnode = vnode
-    if (this._mounted) {
-      callHook(this, 'updated')
-    }
-  }
-
   Vue.prototype._updateFromParent = function (parentData, children, key) {
     const oldParentData = this.$options._renderData
     this.$options._renderData = parentData
@@ -147,10 +127,6 @@ export function renderMixin (Vue) {
     renderState.activeInstance = prev
     return vnode
   }
-
-  Vue.prototype.$forceUpdate = function () {
-    this._watcher.update()
-  }
 }
 
 function resolveSlots (vm, children) {

+ 1 - 58
src/runtime/util/dom.js

@@ -1,4 +1,4 @@
-import { inBrowser, isIE9 } from './env'
+import { inBrowser } from './env'
 import { warn } from './debug'
 import { makeMap } from '../../shared/util'
 
@@ -62,60 +62,3 @@ export function query (el) {
   }
   return el
 }
-
-/**
- * Check if a node is in the document.
- * Note: document.documentElement.contains should work here
- * but always returns false for comment nodes in phantomjs,
- * making unit tests difficult. This is fixed by doing the
- * contains() check on the node's parentNode instead of
- * the node itself.
- *
- * @param {Node} node
- * @return {Boolean}
- */
-
-export function inDoc (node) {
-  var doc = document.documentElement
-  var parent = node && node.parentNode
-  return doc === node ||
-    doc === parent ||
-    !!(parent && parent.nodeType === 1 && (doc.contains(parent)))
-}
-
-/**
- * In IE9, setAttribute('class') will result in empty class
- * if the element also has the :class attribute; However in
- * PhantomJS, setting `className` does not work on SVG elements...
- * So we have to do a conditional check here.
- *
- * @param {Element} el
- * @param {String} cls
- */
-
-export function setClass (el, cls) {
-  /* istanbul ignore if */
-  if (isIE9 && !/svg$/.test(el.namespaceURI)) {
-    el.className = cls
-  } else {
-    el.setAttribute('class', cls)
-  }
-}
-
-/**
- * Get outerHTML of elements, taking care
- * of SVG elements in IE as well.
- *
- * @param {Element} el
- * @return {String}
- */
-
-export function getOuterHTML (el) {
-  if (el.outerHTML) {
-    return el.outerHTML
-  } else {
-    var container = document.createElement('div')
-    container.appendChild(el.cloneNode(true))
-    return container.innerHTML
-  }
-}

+ 2 - 29
src/runtime/vdom/create-element.js

@@ -1,14 +1,8 @@
 import VNode from './vnode'
 import Component from './component'
+import { flatten } from './helpers'
 import { renderState } from '../instance/render'
-import {
-  warn,
-  isPrimitive,
-  isArray,
-  isReservedTag,
-  isUnknownElement,
-  resolveAsset
-} from '../util/index'
+import { warn, isReservedTag, isUnknownElement, resolveAsset } from '../util/index'
 
 export default function createElement (tag, data, children) {
   data = data || {}
@@ -36,24 +30,3 @@ export default function createElement (tag, data, children) {
     return Component(tag, data, parent, children)
   }
 }
-
-export function flatten (children) {
-  if (isArray(children)) {
-    let res = []
-    for (let i = 0, l = children.length; i < l; i++) {
-      let c = children[i]
-      // flatten nested
-      if (isArray(c)) {
-        res.push.apply(res, flatten(c))
-      } else if (isPrimitive(c)) {
-        // convert primitive to vnode
-        res.push(VNode(undefined, undefined, undefined, c))
-      } else if (c) {
-        res.push(c)
-      }
-    }
-    return res
-  } else {
-    return children
-  }
-}

+ 30 - 25
src/runtime/vdom/patch.js → src/runtime/vdom/create-updater.js

@@ -1,5 +1,10 @@
+/**
+ * Virtual DOM implementation based on Snabbdom by
+ * Simon Friis Vindum (@paldepind)
+ * with custom modifications.
+ */
+
 import VNode from './vnode'
-import * as dom from './dom'
 import { isPrimitive, warn } from '../util/index'
 
 const emptyNode = VNode('', {}, [])
@@ -32,11 +37,11 @@ function createKeyToOldIdx (children, beginIdx, endIdx) {
   return map
 }
 
-export default function createPatchFunction (modules, api) {
+export default function createUpdater (backend) {
   let i, j
   const cbs = {}
 
-  if (isUndef(api)) api = dom
+  const { modules, nodeOps } = backend
 
   for (i = 0; i < hooks.length; ++i) {
     cbs[hooks[i]] = []
@@ -46,14 +51,14 @@ export default function createPatchFunction (modules, api) {
   }
 
   function emptyNodeAt (elm) {
-    return VNode(api.tagName(elm).toLowerCase(), {}, [], undefined, elm)
+    return VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
   }
 
   function createRmCb (childElm, listeners) {
     return function remove () {
       if (--listeners === 0) {
-        const parent = api.parentNode(childElm)
-        api.removeChild(parent, childElm)
+        const parent = nodeOps.parentNode(childElm)
+        nodeOps.removeChild(parent, childElm)
       }
     }
   }
@@ -72,14 +77,14 @@ export default function createPatchFunction (modules, api) {
     const tag = vnode.tag
     if (isDef(tag)) {
       elm = vnode.elm = isDef(data) && data.svg
-        ? api.createElementNS(svgNS, tag)
-        : api.createElement(tag)
+        ? nodeOps.createElementNS(svgNS, tag)
+        : nodeOps.createElement(tag)
       if (Array.isArray(children)) {
         for (i = 0; i < children.length; ++i) {
-          api.appendChild(elm, createElm(children[i], insertedVnodeQueue))
+          nodeOps.appendChild(elm, createElm(children[i], insertedVnodeQueue))
         }
       } else if (isPrimitive(vnode.text)) {
-        api.appendChild(elm, api.createTextNode(vnode.text))
+        nodeOps.appendChild(elm, nodeOps.createTextNode(vnode.text))
       }
       for (i = 0; i < cbs.create.length; ++i) cbs.create[i](emptyNode, vnode)
       i = vnode.data.hook // Reuse variable
@@ -88,14 +93,14 @@ export default function createPatchFunction (modules, api) {
         if (i.insert) insertedVnodeQueue.push(vnode)
       }
     } else {
-      elm = vnode.elm = api.createTextNode(vnode.text)
+      elm = vnode.elm = nodeOps.createTextNode(vnode.text)
     }
     return vnode.elm
   }
 
   function addVnodes (parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
     for (; startIdx <= endIdx; ++startIdx) {
-      api.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before)
+      nodeOps.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before)
     }
   }
 
@@ -130,7 +135,7 @@ export default function createPatchFunction (modules, api) {
             rm()
           }
         } else { // Text node
-          api.removeChild(parentElm, ch.elm)
+          nodeOps.removeChild(parentElm, ch.elm)
         }
       }
     }
@@ -162,19 +167,19 @@ export default function createPatchFunction (modules, api) {
         newEndVnode = newCh[--newEndIdx]
       } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
         patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
-        api.insertBefore(parentElm, getElm(oldStartVnode), api.nextSibling(getElm(oldEndVnode)))
+        nodeOps.insertBefore(parentElm, getElm(oldStartVnode), nodeOps.nextSibling(getElm(oldEndVnode)))
         oldStartVnode = oldCh[++oldStartIdx]
         newEndVnode = newCh[--newEndIdx]
       } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
         patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
-        api.insertBefore(parentElm, getElm(oldEndVnode), getElm(oldStartVnode))
+        nodeOps.insertBefore(parentElm, getElm(oldEndVnode), getElm(oldStartVnode))
         oldEndVnode = oldCh[--oldEndIdx]
         newStartVnode = newCh[++newStartIdx]
       } else {
         if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
         idxInOld = oldKeyToIdx[newStartVnode.key]
         if (isUndef(idxInOld)) { // New element
-          api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), getElm(oldStartVnode))
+          nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), getElm(oldStartVnode))
           newStartVnode = newCh[++newStartIdx]
         } else {
           elmToMove = oldCh[idxInOld]
@@ -186,7 +191,7 @@ export default function createPatchFunction (modules, api) {
           }
           patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
           oldCh[idxInOld] = undefined
-          api.insertBefore(parentElm, getElm(elmToMove), getElm(oldStartVnode))
+          nodeOps.insertBefore(parentElm, getElm(elmToMove), getElm(oldStartVnode))
           newStartVnode = newCh[++newStartIdx]
         }
       }
@@ -214,9 +219,9 @@ export default function createPatchFunction (modules, api) {
     const ch = vnode.children
     if (oldVnode === vnode) return
     if (!sameVnode(oldVnode, vnode)) {
-      var parentElm = api.parentNode(oldVnode.elm)
+      var parentElm = nodeOps.parentNode(oldVnode.elm)
       elm = createElm(vnode, insertedVnodeQueue)
-      api.insertBefore(parentElm, elm, oldVnode.elm)
+      nodeOps.insertBefore(parentElm, elm, oldVnode.elm)
       removeVnodes(parentElm, [oldVnode], 0, 0)
       return
     }
@@ -229,22 +234,22 @@ export default function createPatchFunction (modules, api) {
       if (isDef(oldCh) && isDef(ch)) {
         if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue)
       } else if (isDef(ch)) {
-        if (isDef(oldVnode.text)) api.setTextContent(elm, '')
+        if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
         addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
       } else if (isDef(oldCh)) {
         removeVnodes(elm, oldCh, 0, oldCh.length - 1)
       } else if (isDef(oldVnode.text)) {
-        api.setTextContent(elm, '')
+        nodeOps.setTextContent(elm, '')
       }
     } else if (oldVnode.text !== vnode.text) {
-      api.setTextContent(elm, vnode.text)
+      nodeOps.setTextContent(elm, vnode.text)
     }
     if (isDef(hook) && isDef(i = hook.postpatch)) {
       i(oldVnode, vnode)
     }
   }
 
-  return function patch (oldVnode, vnode) {
+  return function update (oldVnode, vnode) {
     var i, elm, parent
     var insertedVnodeQueue = []
     for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]()
@@ -260,12 +265,12 @@ export default function createPatchFunction (modules, api) {
         patchVnode(oldVnode, vnode, insertedVnodeQueue)
       } else {
         elm = oldVnode.elm
-        parent = api.parentNode(elm)
+        parent = nodeOps.parentNode(elm)
 
         createElm(vnode, insertedVnodeQueue)
 
         if (parent !== null) {
-          api.insertBefore(parent, getElm(vnode), api.nextSibling(elm))
+          nodeOps.insertBefore(parent, getElm(vnode), nodeOps.nextSibling(elm))
           removeVnodes(parent, [oldVnode], 0, 0)
         }
       }

+ 27 - 18
src/runtime/vdom/modules/events.js → src/runtime/vdom/helpers.js

@@ -1,17 +1,27 @@
-import { isArray } from '../../util/index'
+import { isArray, isPrimitive } from '../util/index'
+import VNode from './vnode'
 
-function arrInvoker (arr) {
-  return function (ev) {
-    for (let i = 0; i < arr.length; i++) {
-      arr[i](ev)
+export function flatten (children) {
+  if (isArray(children)) {
+    let res = []
+    for (let i = 0, l = children.length; i < l; i++) {
+      let c = children[i]
+      // flatten nested
+      if (isArray(c)) {
+        res.push.apply(res, flatten(c))
+      } else if (isPrimitive(c)) {
+        // convert primitive to vnode
+        res.push(VNode(undefined, undefined, undefined, c))
+      } else if (c) {
+        res.push(c)
+      }
     }
+    return res
+  } else {
+    return children
   }
 }
 
-function fnInvoker (o) {
-  return function (ev) { o.fn(ev) }
-}
-
 export function updateListeners (on, oldOn, add) {
   let name, cur, old, event, capture
   for (name in on) {
@@ -38,15 +48,14 @@ export function updateListeners (on, oldOn, add) {
   }
 }
 
-function updateDOMListeners (oldVnode, vnode) {
-  const on = vnode.data.on
-  const oldOn = oldVnode.data.on || {}
-  updateListeners(on, oldOn, (event, handler, capture) => {
-    vnode.elm.addEventListener(event, handler, capture)
-  })
+function arrInvoker (arr) {
+  return function (ev) {
+    for (let i = 0; i < arr.length; i++) {
+      arr[i](ev)
+    }
+  }
 }
 
-export default {
-  create: updateDOMListeners,
-  update: updateDOMListeners
+function fnInvoker (o) {
+  return function (ev) { o.fn(ev) }
 }

+ 0 - 25
src/runtime/vdom/index.js

@@ -1,25 +0,0 @@
-/**
- * Virtual DOM implementation based on Snabbdom by
- * Simon Friis Vindum (@paldepind)
- * with custom modifications.
- */
-
-import createPatchFunction from './patch'
-import createElement, { flatten } from './create-element'
-import classes from './modules/class'
-import style from './modules/style'
-import props from './modules/props'
-import attrs from './modules/attrs'
-import events, { updateListeners } from './modules/events'
-import directives from './modules/directives'
-
-const patch = createPatchFunction([
-  classes,
-  props,
-  attrs,
-  style,
-  events,
-  directives
-])
-
-export { patch, createElement, updateListeners, flatten }