ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
[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) {} ~~~