[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, '');
}
~~~
- 框架概述
- 框架目录
- 总目录(inferno-master)
- 配置目录(config)
- 示例目录(examples)
- 包目录(packages)
- 源代码目录(src)
- 工具目录(tools)
- 其他文件
- 框架结构
- (0)依赖关系
- (1)Inferno模块
- (2)InfernoDOM模块
- (3)InfernoServer模块
- (4)InfernoComponent模块
- (5)InfernoTestUtils模块
- (6)InfernoCreateElement模块
- (7)InfernoRouter模块
- 框架实现
- (1)Router
- (2)Redux
- (3)Component
- (4)CreateElement
- (5)Core(Vnode)
- (6)Dom(Render)
- (7)Server
- (8)TestUtils
- (9)Utils
- 框架流程
- 框架示例
- 框架更新
- 基础原理
- 框架总结