Skip to content
This repository has been archived by the owner on Aug 16, 2023. It is now read-only.

Commit

Permalink
feat(vdom): add VDom context replace dom context
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake committed Jul 31, 2017
1 parent ca1fd8c commit aac1783
Show file tree
Hide file tree
Showing 24 changed files with 6,030 additions and 5,388 deletions.
802 changes: 546 additions & 256 deletions dist/zreact.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/zreact.esm.js.map

Large diffs are not rendered by default.

801 changes: 546 additions & 255 deletions dist/zreact.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/zreact.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/zreact.min.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"chai": "^4.1.0",
"conventional-changelog-cli": "^1.3.2",
"cross-env": "^5.0.1",
"istanbul-instrumenter-loader": "^2.0.0",
"istanbul-instrumenter-loader": "^3.0.0",
"karma": "^1.7.0",
"karma-chai-sinon": "^0.1.5",
"karma-chrome-launcher": "^2.2.0",
Expand All @@ -43,12 +43,12 @@
"rollup-plugin-typescript": "zeromake/rollup-plugin-typescript",
"rollup-plugin-uglify": "^2.0.1",
"rollup-watch": "^4.3.1",
"sinon": "^2.3.8",
"sinon": "^2.4.1",
"sinon-chai": "^2.12.0",
"ts-loader": "^2.3.0",
"ts-loader": "^2.3.1",
"tslint": "^5.5.0",
"typescript": "^2.4.1",
"uglify-es": "^3.0.26",
"webpack": "^3.3.0"
"uglify-es": "^3.0.27",
"webpack": "^3.4.1"
}
}
17 changes: 7 additions & 10 deletions src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { VNode } from "./vnode";
import { enqueueRender } from "./render-queue";
import { extend } from "./util";
import { IKeyValue } from "./types";
import { VDom } from "./vdom/index";

export class Component {
/**
Expand All @@ -23,9 +24,13 @@ export class Component {
*/
public context: IKeyValue;
/**
* 组件挂载后的dom
* 组件挂载后的vdom
*/
public base?: Element;
public vdom?: VDom;
/**
* 被移除时的vdom缓存
*/
public nextVDom?: VDom;
/**
* 自定义组件名
*/
Expand All @@ -42,10 +47,6 @@ export class Component {
* 上一次的上下文
*/
public prevContext?: IKeyValue;
/**
* 被移除时的dom缓存
*/
public nextBase?: Element;
/**
* 在一个组件被渲染到 DOM 之前
*/
Expand Down Expand Up @@ -118,10 +119,6 @@ export class Component {
* react标准用于设置component实例
*/
public _ref?: (component: Component | null) => void;
/**
* VDom暂定用于存放组件根dom的上下文
*/
public child?: any;
constructor(props: IKeyValue, context: IKeyValue) {
// 初始化为true
this._dirty = true;
Expand Down
71 changes: 38 additions & 33 deletions src/dom/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IS_NON_DIMENSIONAL } from "../constants";
import { VDom } from "../vdom/index";
import options from "../options";

/**
Expand All @@ -11,15 +12,15 @@ export function createNode(nodeName: string, isSvg: boolean): HTMLElement {
? document.createElementNS("http://www.w3.org/2000/svg", nodeName)
: document.createElement(nodeName);
// 设置原始的nodeName到dom上normalizedNodeName
node.normalizedNodeName = nodeName;
// node.normalizedNodeName = nodeName;
return node;
}

/**
* 移除dom
* @param node 需要移除的node
*/
export function removeNode(node: HTMLElement) {
export function removeNode(node: Element | Text | Node) {
const parentNode = node.parentNode;
if (parentNode) {
parentNode.removeChild(node);
Expand All @@ -36,13 +37,13 @@ export function removeNode(node: HTMLElement) {
* @param child VDom原dom上的props,和上下文环境,事件就在其中
*/
export function setAccessor(
node: any,
vdom: VDom,
name: string,
old: any,
value: any,
isSvg: boolean,
child: any,
) {
const node: any = vdom.base;
if (name === "className") {
// 把className重名为class
name = "class";
Expand All @@ -55,8 +56,8 @@ export function setAccessor(
old(null);
}
if (value) {
// 给新方法设置dom
value(node);
// 给新方法设置vdom
value(vdom);
}
} else if ("class" === name && !isSvg) {
// 直接通过className设置class
Expand Down Expand Up @@ -106,17 +107,17 @@ export function setAccessor(
if (value) {
if (!old) {
// 保证只有一次绑定事件
addEventListener(node, name, useCapture, child);
addEventListener(vdom, name, useCapture);
}
} else {
// 移除事件
removeEventListener(node, name, useCapture, child);
removeEventListener(vdom, name, useCapture);
}
if (!child._listeners) {
if (!vdom.listeners) {
// 在上下文中创建存放绑定的方法的对象
child._listeners = {};
vdom.listeners = {};
}
child._listeners[name] = value;
vdom.listeners[name] = value;
} else if (name !== "list" && name !== "type" && !isSvg && name in node) {
// 安全设置属性
setProperty(node, name, value == null ? "" : value);
Expand Down Expand Up @@ -150,6 +151,8 @@ export function setAccessor(
}
}

const isIe8 = typeof document.addEventListener !== "function";

function setProperty(node: any, name: string, value: string) {
try {
node[name] = value;
Expand All @@ -161,22 +164,24 @@ function setProperty(node: any, name: string, value: string) {
* @param child 上下文
* @param useCapture 是否冒泡(兼容ie8)
*/
function eventProxy(child: any, useCapture: boolean): (e: Event) => void {
function eventProxy(vdom: VDom, useCapture: boolean): (e: Event) => void {
return (e: Event) => {
if (child.isIe8 && !useCapture) {
if (isIe8 && !useCapture) {
// ie8事件默认冒泡所以需要阻止
e.cancelBubble = !useCapture;
}
// 取出对于的props事件
const listener = child._listeners[e.type];
const listener = vdom.listeners && vdom.listeners[e.type];
// 事件钩子
const event = options.event && options.event(e) || e;
if (options.eventBind && child._component) {
// 自动使用所属自定义组件来做this
return listener.call(child._component, event);
if (listener) {
if (options.eventBind && vdom.component) {
// 自动使用所属自定义组件来做this
return listener.call(vdom.component, event);
}
// 直接调用事件
return listener(event);
}
// 直接调用事件
return listener(event);
};
}

Expand All @@ -203,19 +208,16 @@ export function isTextNode(node: Text | any): boolean {
* @param useCapture 是否冒泡
* @param child 上下文
*/
function addEventListener(node: any, name: string, useCapture: boolean, child: any) {
if (typeof child.isIe8 !== "number") {
// 判断是否为ie9以下的浏览器
child.isIe8 = node.addEventListener ? 0 : 1;
}
function addEventListener(vdom: VDom, name: string, useCapture: boolean) {
// 生成当前事件的代理方法
const eventProxyFun = eventProxy(child, useCapture);
if (!child.event) {
child.event = {};
const eventProxyFun = eventProxy(vdom, useCapture);
if (!vdom.eventProxy) {
vdom.eventProxy = {};
}
// 把事件代理方法挂载到child.event上等待卸载时使用
child.event[name] = eventProxyFun;
if (!child.isIe8) {
vdom.eventProxy[name] = eventProxyFun;
const node: any = vdom.base;
if (!isIe8) {
node.addEventListener(name, eventProxyFun, useCapture);
} else {
node.attachEvent("on" + name, eventProxyFun);
Expand All @@ -229,11 +231,14 @@ function addEventListener(node: any, name: string, useCapture: boolean, child: a
* @param useCapture 是否冒泡
* @param child 上下文
*/
function removeEventListener(node: any, name: string, useCapture: boolean, child: any) {
function removeEventListener(vdom: VDom, name: string, useCapture: boolean) {
// 把上下文中的存储的代理事件解绑
const eventProxyFun = child.event[name];
child.event[name] = undefined;
if (!child.isIe8) {
const eventProxyFun = vdom.eventProxy && vdom.eventProxy[name];
if (vdom.eventProxy && eventProxyFun) {
vdom.eventProxy[name] = undefined;
}
const node: any = vdom.base;
if (!isIe8) {
node.removeEventListener(name, eventProxyFun, useCapture);
} else {
node.detachEvent("on" + name, eventProxyFun);
Expand Down
11 changes: 3 additions & 8 deletions src/render.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { diff } from "./vdom/diff";
import { VNode } from "./vnode";

const child = {};
import { VDom } from "./vdom/index";

/**
* 创建组件到dom上
Expand All @@ -10,11 +9,7 @@ const child = {};
* @param merge 原dom元素
* @param domChild 虚拟dom用于挂载原来挂载在dom元素上的属性
*/
export function render(vnode: VNode, parent: Element, merge: Element, domChild?: any) {
const pchild = domChild || child;
const base: any = diff(merge, vnode, {}, false, parent, false, pchild);
if (pchild._component) {
base._component = pchild._component;
}
export function render(vnode: VNode, parent: Element, vdom: VDom): VDom {
const base = diff(vdom, vnode, {}, false, parent, false);
return base;
}
2 changes: 1 addition & 1 deletion src/vdom/component-recycler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function createComponent(Ctor: any, props: IKeyValue, context: IKeyValue)
for (let i = list.length; i-- ; ) {
const item = list[i];
if (item.constructor === Ctor) {
inst.nextBase = item.nextBase;
inst.nextVDom = item.nextVDom;
list.splice(i, 1);
break;
}
Expand Down

0 comments on commit aac1783

Please sign in to comment.