[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源码分析资料