[TOC]
*****
## 2 (web\runtime\) web運行時目錄
### 2-1 目錄層次
~~~
web\runtime\
directives\
index.js
model.js
show.js
modules\
attrs.js
class.js
events.js
props.js
style.js
transition.js
index.js
class-util.js
node-ops.js
~~~
### 2-2 directives\model.js (model指令)
>[info] import
~~~
;(導入)平臺判斷工具
import { isAndroid, isIE9 } from 'web/util/index'
~~~
>[info] module
~~~
;ie9下selectionchane修正
if (isIE9) {
// http://www.matts411.com/post/internet-explorer-9-oninput/
document.addEventListener('selectionchange', () => {
const el = document.activeElement
if (el && el.vmodel) {
trigger(el)
}
})
}
;model事件監聽注冊與銷毀
export default {
bind (el) {
if (!isAndroid) {
el.addEventListener('compositionstart', onCompositionStart)
el.addEventListener('compositionend', onCompositionEnd)
}
if (isIE9) {
el.vmodel = true
}
},
unbind (el) {
if (!isAndroid) {
el.removeEventListener('compositionstart', onCompositionStart)
el.removeEventListener('compositionend', onCompositionEnd)
}
}
}
;
function onCompositionStart (e) {
e.target.composing = true
}
;
function onCompositionEnd (e) {
e.target.composing = false
trigger(e.target)
}
;手動觸發事件
function trigger (el) {
const e = document.createEvent('HTMLEvents')
e.initEvent('input', true, true)
el.dispatchEvent(e)
}
~~~
>[info] export
~~~
export default {
bind
unbind
}
~~~
### 2-3 directives\show.js
>[info] import
~~~
;(導入)平臺判斷,動畫效果
import { isIE9 } from 'web/util/index'
import { enter, leave } from '../modules/transition'
~~~
>[info] module
~~~
;動畫綁定,動畫刷新
export default {
bind (el, value, _, vnode) {
const transition = getTransition(vnode)
if (value && transition && transition.appea && !isIE9) {
enter(vnode)
}
el.style.display = value ? '' : 'none'
},
update (el, value, _, vnode) {
const transition = getTransition(vnode)
if (transition && !isIE9) {
if (value) {
enter(vnode)
el.style.display = ''
} else {
leave(vnode, () => {
el.style.display = 'none'
})
}
} else {
el.style.display = value ? '' : 'none'
}
}
}
;獲取動畫信息
function getTransition (vnode) {
const parent = vnode.parent
return parent && parent.data.transition != null
? parent.data.transition
: vnode.data.transition
}
~~~
>[info] export
~~~
;(導出)動畫接口
export default {
bind
update
}
~~~
### 2-4 directives\index.js
>[info] import
~~~
;(導入)model與show運行時指令
import model from './model'
import show from './show'
~~~
>[info] export
~~~
;(導出)model與show運行時指令
export default {
model,
show
}
~~~
### 2-5 modules\attrs.js
>[info] import
~~~
;(導入)web基礎工具
import { isBooleanAttr, isEnumeratedAttr, isXlink, xlinkNS } from 'web/util/index'
~~~
>[info] module
~~~
;節點屬性更新
function updateAttrs (oldVnode, vnode) {
if (!oldVnode.data.attrs && !vnode.data.attrs) {
return
}
let key, cur, old
const elm = vnode.elm
const oldAttrs = oldVnode.data.attrs || {}
const attrs = vnode.data.attrs || {}
;添加屬性
for (key in attrs) {
cur = attrs[key]
old = oldAttrs[key]
if (old !== cur) {
setAttr(elm, key, cur)
}
}
;刪除屬性
for (key in oldAttrs) {
if (attrs[key] == null) {
if (isXlink(key)) {
elm.removeAttributeNS(xlinkNS, key)
} else {
elm.removeAttribute(key)
}
}
}
}
;添加屬性
function setAttr (el, key, value) {
if (isBooleanAttr(key)) {
if (value == null) {
el.removeAttribute(key)
} else {
el.setAttribute(key, key)
}
} else if (isEnumeratedAttr(key)) {
el.setAttribute(key, value == null ? 'false' : 'true')
} else if (isXlink(key)) {
el.setAttributeNS(xlinkNS, key, value)
} else {
el.setAttribute(key, value)
}
}
;attrs屬性操作模型
export default {
create: function (_, vnode) {
const attrs = vnode.data.staticAttrs
if (attrs) {
for (const key in attrs) {
if (!vnode.elm) debugger
setAttr(vnode.elm, key, attrs[key])
}
}
updateAttrs(_, vnode)
},
update: updateAttrs
}
~~~
>[info] export
~~~
;(導出)運行時attr模型
export default {
create
update
}
~~~
### 2-6 modules\class.js
>[info] import
~~~
;(導入)class操作工具
import { setClass } from '../class-util'
import { genClassForVnode, concat, stringifyClass } from 'web/util/index'
~~~
>[info] module
~~~
;更新節點class
function updateClass (oldVnode, vnode) {
const el = vnode.elm
const data = vnode.data
if (!data.staticClass && !data.class) {
return
}
let cls = genClassForVnode(vnode)
// handle transition classes
const transitionClass = el._transitionClasses
if (transitionClass) {
cls = concat(cls, stringifyClass(transitionClass))
}
// set the class
if (cls !== el._prevClass) {
setClass(el, cls)
el._prevClass = cls
}
}
;class操作接口
export default {
create: updateClass,
update: updateClass
}
~~~
>[info] export
~~~
;(導出)class模型操作接口
export default {
create: updateClass,
update: updateClass
}
~~~
### 2-7 modules\events.js
>[info] import
~~~
;(導入)事件監聽更新工具
import { updateListeners } from 'core/vdom/helpers'
~~~
>[info] module
~~~
;更新dom事件監聽
function updateDOMListeners (oldVnode, vnode) {
if (!oldVnode.data.on && !vnode.data.on) {
return
}
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
}
~~~
>[info] export
~~~
;事件監聽操作接口
export default {
create: updateDOMListeners,
update: updateDOMListeners
}
~~~
### 2-8 modules\props.js
>[info] module
~~~
;屬性更新
function updateProps (oldVnode, vnode) {
if (!oldVnode.data.props && !vnode.data.props) {
return
}
let key, cur, old
const elm = vnode.elm
const oldProps = oldVnode.data.props || {}
const props = vnode.data.props || {}
for (key in oldProps) {
if (props[key] == null) {
elm[key] = undefined
}
}
for (key in props) {
cur = props[key]
old = oldProps[key]
if (key === 'value') {
// store value as _value as well since
// non-string values will be stringified
elm._value = cur
// avoid resetting cursor position when value is the same
if (elm.value != cur) { // eslint-disable-line
elm.value = cur
}
} else if (old !== cur) {
elm[key] = cur
}
}
}
;屬性操作接口
export default {
create: updateProps,
update: updateProps
}
~~~
>[info] export
~~~
;(導出)屬性操作接口
export default {
create: updateProps,
update: updateProps
}
~~~
### 2-9 modules\style.js
>[info] import
~~~
;(導入)基礎工具,運行環境
import { extend, isArray, cached, camelize } from 'shared/util'
import { inBrowser } from 'core/util/env'
~~~
>[info] module
~~~
;前綴,el
const prefixes = ['Webkit', 'Moz', 'ms']
const testEl = inBrowser && document.createElement('div')
;解駝峰化
const normalize = cached(function (prop) {
prop = camelize(prop)
if (prop !== 'filter' && (prop in testEl.style)) {
return prop
}
const upper = prop.charAt(0).toUpperCase() + prop.slice(1)
for (let i = 0; i < prefixes.length; i++) {
const prefixed = prefixes[i] + upper
if (prefixed in testEl.style) {
return prefixed
}
}
})
;style更新
function updateStyle (oldVnode, vnode) {
if (!oldVnode.data.style && !vnode.data.style) {
return
}
let cur, name
const elm = vnode.elm
const oldStyle = oldVnode.data.style || {}
let style = vnode.data.style || {}
// handle array syntax
if (isArray(style)) {
style = vnode.data.style = toObject(style)
}
for (name in oldStyle) {
if (!style[name]) {
elm.style[normalize(name)] = ''
}
}
for (name in style) {
cur = style[name]
if (cur !== oldStyle[name]) {
elm.style[normalize(name)] = cur
}
}
}
;數組轉換為對象
function toObject (arr) {
const res = arr[0] || {}
for (let i = 1; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
~~~
>[info] export
~~~
;style操作接口
export default {
create: updateStyle,
update: updateStyle
}
~~~
### 2-10 modules\transition.js
>[info] import
~~~
import { addClass, removeClass } from '../class-util'
import { inBrowser, resolveAsset } from 'core/util/index'
import { cached, remove } from 'shared/util'
import { isIE9 } from 'web/util/index'
~~~
>[info] module
~~~
const TRANSITION = 'transition'
const ANIMATION = 'animation'
~~~
>[info] export
~~~
export function enter (vnode) {}
export function leave (vnode, rm) {}
export default !transitionEndEvent ? {} : {
create
remove
}
~~~
### 2-11 modules\index.js
>[info] import
~~~
;(導入)運行時模型接口
import attrs from './attrs'
import klass from './class'
import events from './events'
import props from './props'
import style from './style'
import transition from './transition'
~~~
>[info] export
~~~
;(導出)運行時模型接口
export default [
attrs,
klass,
events,
props,
style,
transition
]
~~~
### 2-11 class-util.js class操作工具
>[info] import
~~~
import { isIE9, namespaceMap } from 'web/util/index'
~~~
>[info] module
~~~
const svgNS = namespaceMap.svg
;修改節點的class
export function setClass (el, cls) {
/* istanbul ignore else */
if (!isIE9 || el.namespaceURI === svgNS) {
el.setAttribute('class', cls)
} else {
el.className = cls
}
}
;為節點添加class
export function addClass (el, cls) {
if (el.classList) {
if (cls.indexOf(' ') > -1) {
cls.split(/\s+/).forEach(c => el.classList.add(c))
} else {
el.classList.add(cls)
}
} else {
const cur = ' ' + getClass(el) + ' '
if (cur.indexOf(' ' + cls + ' ') < 0) {
setClass(el, (cur + cls).trim())
}
}
}
;刪除節點的class
export function removeClass (el, cls) {
if (el.classList) {
if (cls.indexOf(' ') > -1) {
cls.split(/\s+/).forEach(c => el.classList.remove(c))
} else {
el.classList.remove(cls)
}
} else {
let cur = ' ' + getClass(el) + ' '
const tar = ' ' + cls + ' '
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ')
}
setClass(el, cur.trim())
}
if (!el.className) {
el.removeAttribute('class')
}
}
;獲取節點class
function getClass (el) {
let classname = el.className
if (typeof classname === 'object') {
classname = classname.baseVal || ''
}
return classname
}
~~~
>[info] export
~~~
;修改元素節點class
export function setClass (el, cls) {}
;添加元素節點class
export function addClass (el, cls) {}
;刪除元素節點class
export function removeClass (el, cls) {}
~~~
### 2-12 node-ops.js node操作
>[info] import
~~~
;(導入)命名空間
import { namespaceMap } from 'web/util/index'
~~~
>[info] module
~~~
;節點操作接口
export function createElement (tagName) {
return document.createElement(tagName)
}
export function createElementNS (namespace, tagName) {
return document.createElementNS(namespaceMap[namespace], tagName)
}
export function createTextNode (text) {
return document.createTextNode(text)
}
export function insertBefore (parentNode, newNode, referenceNode) {
parentNode.insertBefore(newNode, referenceNode)
}
export function removeChild (node, child) {
node.removeChild(child)
}
export function appendChild (node, child) {
node.appendChild(child)
}
export function parentNode (node) {
return node.parentElement
}
export function nextSibling (node) {
return node.nextSibling
}
export function tagName (node) {
return node.tagName
}
export function setTextContent (node, text) {
node.textContent = text
}
~~~
>[info] export
~~~
;(導出)節點操作接口
export function createElement (tagName) {}
export function createElementNS (namespace, tagName) {}
export function createTextNode (text) {}
export function insertBefore (parentNode, newNode, referenceNode) {}
export function removeChild (node, child) {}
export function appendChild (node, child) {}
export function parentNode (node) {}
export function nextSibling (node) {}
export function tagName (node) {}
export function setTextContent (node, text) {}
~~~
- 概述
- 框架結構
- 編譯入口(\entries)
- web-compiler.js(web編譯)
- web-runtime.js(web運行時)
- web-runtime-wih-compiler.js(web編譯運行)
- web-server-renderer.js(web服務器渲染)
- 核心實現 (\core)
- index.js(核心入口)
- config.js(核心配置)
- core\util(核心工具)
- core\observer(雙向綁定)
- core\vdom(虛擬DOM)
- core\global-api(核心api)
- core\instance(核心實例)
- 模板編譯(\compiler)
- compiler\parser(模板解析)
- events.js(事件解析)
- helper.js(解析助手)
- directives\ref.js(ref指令)
- optimizer.js(解析優化)
- codegen.js(渲染生成)
- index.js(模板編譯入口)
- web渲染(\platforms\web)
- compiler(web編譯目錄)
- runtime(web運行時目錄)
- server(web服務器目錄)
- util(web工具目錄)
- 服務器渲染(\server)
- render-stream.js(流式渲染)
- render.js(服務器渲染函數)
- create-renderer.js(創建渲染接口)
- 框架流程
- Vue初始化
- Vue視圖數據綁定
- Vue數據變化刷新
- Vue視圖操作刷新
- 框架工具
- 基礎工具(\shared)
- 模板編譯助手
- 核心實例工具
- Web渲染工具
- 基礎原理
- dom
- string
- array
- function
- object
- es6
- 模塊(Module)
- 類(Class)
- 函數(箭頭)
- 字符串(擴展)
- 代理接口(Proxy)
- 數據綁定基礎
- 數據綁定實現
- mvvm簡單實現
- mvvm簡單使用
- vdom算法
- vdom實現
- vue源碼分析資料