🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] * * * * * # 1 Core/utils.js ~~~ // 合并children到props export function addChildrenToProps(children, props) { if (!isNullOrUndefined(children)) { const isChildrenArray = isArray(children); if (isChildrenArray && children.length > 0 || !isChildrenArray) { if (props) { props = Object.assign({}, props, { children }); } else { props = { children: children }; } } } return props; } // NO_RENDER常量 export const NO_RENDER = 'NO_RENDER'; // isBrowser 浏览器运行环境检测 // Runs only once in applications lifetime export const isBrowser = typeof window !== 'undefined' && window.document; // 转换为数组 export function toArray(children) { return isArray(children) ? children : (children ? [children] : children ); } // isArray() export function isArray(obj) { return obj instanceof Array; } // isStatefulComponent() export function isStatefulComponent(obj) { return obj.prototype.render !== undefined; } // isStringOrNumber() export function isStringOrNumber(obj) { return isString(obj) || isNumber(obj); } // isNullOrUndefined export function isNullOrUndefined(obj) { return isUndefined(obj) || isNull(obj); } // isInvalidNode() export function isInvalidNode(obj) { return isNull(obj) || obj === false || obj === true || isUndefined(obj); } // isFunction() export function isFunction(obj) { return typeof obj === 'function'; } // isAttrAnEvent() export function isAttrAnEvent(attr) { return attr[0] === 'o' && attr[1] === 'n' && attr.length > 3; } // isString() export function isString(obj) { return typeof obj === 'string'; } // isNumber() export function isNumber(obj) { return typeof obj === 'number'; } // isNull() export function isNull(obj) { return obj === null; } // isTrue() export function isTrue(obj) { return obj === true; } // isUndefined() export function isUndefined(obj) { return obj === undefined; } // isAttrAHook() export function isAttrAHook(hook) { return hook === 'onCreated' || hook === 'onAttached' || hook === 'onWillDetach' || hook === 'onWillUpdate' || hook === 'onDidUpdate'; } // isAttrAComponentHook() export function isAttrAComponentHook(hook) { return hook === 'onComponentWillMount' || hook === 'onComponentDidMount' || hook === 'onComponentWillUnmount' || hook === 'onComponentShouldUpdate' || hook === 'onComponentWillUpdate' || hook === 'onComponentDidUpdate'; } // deepScanChildrenForNode() function deepScanChildrenForNode(children, node) { if (!isInvalidNode(children)) { if (isArray(children)) { for (let i = 0; i < children.length; i++) { const child = children[i]; if (!isInvalidNode(child)) { if (child === node) { return true; } else if (child.children) { return deepScanChildrenForNode(child.children, node); } } } } else { if (children === node) { return true; } else if (children.children) { return deepScanChildrenForNode(children.children, node); } } } return false; } // getRefInstance() export function getRefInstance(node, instance) { const children = instance.props.children; if (deepScanChildrenForNode(children, node)) { return getRefInstance(node, instance._parentComponent); } return instance; } ~~~ # 2 DOM/util.js ~~~ // constructDefaults() 以,切分字符串为对象索引。使用value作为所有值 function constructDefaults(string, object, value) { /* eslint no-return-assign: 0 */ string.split(',').forEach(i => object[i] = value); } // xlink,xml命名空间 const xlinkNS = 'http://www.w3.org/1999/xlink'; const xmlNS = 'http://www.w3.org/XML/1998/namespace'; // 待注册对象 export const strictProps = {}; export const booleanProps = {}; export const namespaces = {}; export const isUnitlessNumber = {}; // xlink命名空间注册 constructDefaults('xlink:href,xlink:arcrole,xlink:actuate,xlink:role,xlink:titlef,xlink:type', namespaces, xlinkNS); // xml命名空间注册 constructDefaults('xml:base,xml:lang,xml:space', namespaces, xmlNS); // strict属性注册 constructDefaults('volume,value', strictProps, true); // boolean属性注册 constructDefaults('muted,scoped,loop,open,checked,default,capture,disabled,selected,readonly,multiple,required,autoplay,controls,seamless,reversed,allowfullscreen,novalidate', booleanProps, true); // UnitlessNumber属性注册 constructDefaults('animationIterationCount,borderImageOutset,borderImageSlice,borderImageWidth,boxFlex,boxFlexGroup,boxOrdinalGroup,columnCount,flex,flexGrow,flexPositive,flexShrink,flexNegative,flexOrder,gridRow,gridColumn,fontWeight,lineClamp,lineHeight,opacity,order,orphans,tabSize,widows,zIndex,zoom,fillOpacity,floodOpacity,stopOpacity,strokeDasharray,strokeDashoffset,strokeMiterlimit,strokeOpacity,strokeWidth,', isUnitlessNumber, true); // Vnode类型判断 // VText类型 export function isVText(o) { return o.text !== undefined; } // VPlaceholder类型 export function isVPlaceholder(o) { return o.placeholder === true; } // VList类型 export function isVList(o) { return o.items !== undefined; } // VNode export function isVNode(o) { return o.tag !== undefined || o.bp !== undefined; } // DOM操作 // 增加 insertOrAppend() export function insertOrAppend(parentDom, newNode, nextNode) { if (isNullOrUndefined(nextNode)) { parentDom.appendChild(newNode); } else { parentDom.insertBefore(newNode, nextNode); } } // 更新 replaceVListWithNode() export function replaceVListWithNode(parentDom, vList, dom) { const pointer = vList.pointer; unmountVList(vList, parentDom, false); replaceNode(parentDom, dom, pointer); } // 创建 documentCreateElement() export function documentCreateElement(tag, isSVG) { let dom; if (isSVG === true) { dom = document.createElementNS('http://www.w3.org/2000/svg', tag); } else { dom = document.createElement(tag); } return dom; } // 添加文本内容 appendText() export function appendText(text, parentDom, singleChild) { if (parentDom === null) { return document.createTextNode(text); } else { if (singleChild) { if (text !== '') { parentDom.textContent = text; return parentDom.firstChild; } else { const textNode = document.createTextNode(''); parentDom.appendChild(textNode); return textNode; } } else { const textNode = document.createTextNode(text); parentDom.appendChild(textNode); return textNode; } } } // 替换 replaceWithNewNode() export function replaceWithNewNode(lastNode, nextNode, parentDom, lifecycle, context, instance, isSVG) { let lastInstance = null; const instanceLastNode = lastNode._lastNode; if (!isNullOrUndefined(instanceLastNode)) { lastInstance = lastNode; lastNode = instanceLastNode; } unmount(lastNode, false); const dom = mount(nextNode, null, lifecycle, context, instance, isSVG); nextNode.dom = dom; replaceNode(parentDom, dom, lastNode.dom); if (lastInstance !== null) { lastInstance._lastNode = nextNode; } } // 替换 replaceNode() export function replaceNode(parentDom, nextDom, lastDom) { parentDom.replaceChild(nextDom, lastDom); } // 单个节点智能创建 normalise() export function normalise(object) { if (isStringOrNumber(object)) { return createVText(object); } else if (isInvalidNode(object)) { return createVPlaceholder(); } else if (isArray(object)) { return createVList(object); } return object; } // 数组单个节点智能创建 normaliseChild() export function normaliseChild(children, i) { const child = children[i]; return children[i] = normalise(child); } // 删除 remove() export function remove(node, parentDom) { if (isVList(node)) { return unmount(node, parentDom); } const dom = node.dom; if (dom === parentDom) { dom.innerHTML = ''; } else { removeChild(parentDom, dom); if (recyclingEnabled) { pool(node); } } unmount(node, false); } // 删除 removeChild() export function removeChild(parentDom, dom) { parentDom.removeChild(dom); } // 删除 removeEventes() export function removeEvents(events, lastEventKeys, dom) { const eventKeys = lastEventKeys || Object.keys(events); for (let i = 0; i < eventKeys.length; i++) { const event = eventKeys[i]; dom[event] = null; } } // TODO: for node we need to check if document is valid // 获取焦点元素 getActiveNode() export function getActiveNode() { return document.activeElement; } // 删除 removeAllChildren() export function removeAllChildren(dom, children) { if (recyclingEnabled) { const childrenLength = children.length; if (childrenLength > 5) { for (let i = 0; i < childrenLength; i++) { const child = children[i]; if (!isInvalidNode(child)) { pool(child); } } } } dom.textContent = ''; } // 重置焦点元素 resetActiveNode() export function resetActiveNode(activeNode) { if (activeNode !== null && activeNode !== document.body && document.activeElement !== activeNode) { activeNode.focus(); // TODO: verify are we doing new focus event, if user has focus listener this might trigger it } } // 是否包含Key isKeyed() export function isKeyed(lastChildren, nextChildren) { if (lastChildren.complex) { return false; } return nextChildren.length && !isNullOrUndefined(nextChildren[0]) && !isNullOrUndefined(nextChildren[0].key) && lastChildren.length && !isNullOrUndefined(lastChildren[0]) && !isNullOrUndefined(lastChildren[0].key); } // select元素处理 function selectOptionValueIfNeeded(vdom, values) { if (vdom.tag !== 'option') { for (let i = 0, len = vdom.children.length; i < len; i++) { selectOptionValueIfNeeded(vdom.children[i], values); } // NOTE! Has to be a return here to catch optGroup elements return; } const value = vdom.attrs && vdom.attrs.value; if (values[value]) { vdom.attrs = vdom.attrs || {}; vdom.attrs.selected = 'selected'; vdom.dom.selected = true; } else { vdom.dom.selected = false; } } // select值处理 export function selectValue(vdom) { let value = vdom.attrs && vdom.attrs.value; let values = {}; if (isArray(value)) { for (let i = 0, len = value.length; i < len; i++) { values[value[i]] = value[i]; } } else { values[value] = value; } for (let i = 0, len = vdom.children.length; i < len; i++) { selectOptionValueIfNeeded(vdom.children[i], values); } if (vdom.attrs && vdom.attrs[value]) { delete vdom.attrs.value; // TODO! Avoid deletion here. Set to null or undef. Not sure what you want to usev } } // hooks钩子处理 export function handleAttachedHooks(hooks, lifecycle, dom) { if (!isNullOrUndefined(hooks.created)) { hooks.created(dom); } if (!isNullOrUndefined(hooks.attached)) { lifecycle.addListener(() => { hooks.attached(dom); }); } } // 设置元素值 export function setValueProperty(nextNode) { const value = nextNode.attrs.value; if (!isNullOrUndefined(value)) { nextNode.dom.value = value; } } // 表单元素属性 export function setFormElementProperties(nextTag, nextNode) { if (nextTag === 'input') { const inputType = nextNode.attrs.type; if (inputType === 'text') { setValueProperty(nextNode); } else if (inputType === 'checkbox' || inputType === 'radio') { const checked = nextNode.attrs.checked; nextNode.dom.checked = !!checked; } } else if (nextTag === 'textarea') { setValueProperty(nextNode); } } ~~~ # 3 Redux/utils.js # 4 Router/utils.js ~~~ const EMPTY = {}; function segmentize(url) { return strip(url).split('/'); } function strip(url) { return url.replace(/(^\/+|\/+$)/g, ''); } ~~~