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

Commit

Permalink
fix(vdom): childNodes no sync; class not set svg; capture error
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake committed Jul 24, 2017
1 parent db306ca commit 70a23c8
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 238 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ typings/
/dist/
/test/test.js
/build/
/coverage/
/test/coverage/

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"karma": "^1.7.0",
"karma-chai-sinon": "^0.1.5",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.3",
"karma-phantomjs-launcher": "^1.0.4",
Expand Down
3 changes: 2 additions & 1 deletion src/clone-element.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { h } from "./h";
import { VNode } from "./vnode";
import { extend } from "./util";

export function cloneElement(vnode: VNode, props: any, ...children: any[]) {
return h(
vnode.nodeName,
{ ...vnode.attributes, ...props },
extend({}, vnode.attributes, props),
children.length > 2 ? children : vnode.children,
);
}
2 changes: 1 addition & 1 deletion src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class Component {
const s: any = this.state;
if (!this.prevState) {
// 把旧的状态保存起来
this.prevState = { ...s };
this.prevState = extend({}, s);
}
if (typeof state === "function") {
const newState = state(s, this.props);
Expand Down
28 changes: 2 additions & 26 deletions src/create-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,18 @@ import { extend } from "./util";

export function createClass(obj: any) {
const cl: any = function(props: any, context: any) {
// bindAll(this);
Component.call(this, props, context, {});
// newComponentHook.call(this, props, context);
};

obj = extend({ constructor: cl }, obj);
if (obj.defaultProps) {
cl.defaultProps = obj.defaultProps;
}

F.prototype = Component.prototype;
cl.prototype = extend(new F(), obj);

cl.displayName = obj.displayName || "Component";

return cl;
}

function F() {}
// const AUTOBIND_BLACKLIST = {
// componentDidMount: 1,
// componentDidUnmount: 1,
// componentDidUpdate: 1,
// componentWillMount: 1,
// componentWillReceiveProps: 1,
// componentWillUnmount: 1,
// componentWillUpdate: 1,
// constructor: 1,
// render: 1,
// shouldComponentUpdate: 1,
// };
// function bindAll(ctx: any) {
// for (const i in ctx) {
// const v = ctx[i];
// if (typeof v === "function" && !v.__bound && !AUTOBIND_BLACKLIST.hasOwnProperty(i)) {
// (ctx[i] = v.bind(ctx)).__bound = true;
// }
// }
// }
class F {
}
12 changes: 10 additions & 2 deletions src/dom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function setAccessor(
if (value) {
value(node);
}
} else if ("class" === name) {
} else if ("class" === name && !isSvg) {
node.className = value || "";
} else if ("style" === name) {
if (!value || typeof value === "string" || typeof old === "string") {
Expand All @@ -58,11 +58,19 @@ export function setAccessor(
} else if ("dangerouslySetInnerHTML" === name) {
if (value) {
node.innerHTML = value.__html || "";
// child.children = [];
// const childNodes = node.childNodes;
// for (let i = 0, len = childNodes.length; i < len ; i++) {
// child.children.push({
// base: childNodes[i],
// });
// }

}
} else if (name[0] === "o" && name[1] === "n") {
const oldName = name;
name = name.replace(/Capture$/, "");
const useCapture = oldName !== oldName;
const useCapture = oldName !== name;
name = name.toLowerCase().substring(2);
if (value) {
if (!old) {
Expand Down
18 changes: 13 additions & 5 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
declare const Promise: any;
declare class Object {
public static assign: (...args: any[]) => any;
}

export let defer: (fn: () => void) => void;
if (typeof Promise === "function") {
Expand All @@ -8,9 +11,14 @@ if (typeof Promise === "function") {
defer = setTimeout;
}

export function extend(obj: any, props: any) {
for (const i in props) {
obj[i] = props[i];
export const extend = Object.assign || function assign_(t: any) {
for (let s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (const p in s) {
if (Object.prototype.hasOwnProperty.call(s, p)) {
t[p] = s[p];
}
}
}
return obj;
}
return t;
};
5 changes: 3 additions & 2 deletions src/vdom/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { VNode } from "../vnode";
import { createComponent, collectComponent } from "./component-recycler";
import { getNodeProps } from "./index";
import { removeNode } from "../dom/index";
import { extend } from "../util";

import { diff, diffLevel, flushMounts, mounts, recollectNodeTree, removeChildren } from "./diff";

Expand Down Expand Up @@ -129,7 +130,7 @@ export function renderComponent(component: Component, opts?: number, mountALL?:
//
let inst: Component | undefined;
if (component.getChildContext) {
context = { ...context, ...component.getChildContext() };
context = extend(context, component.getChildContext());
}
// 取出VNode的nodeName
const childComponent = rendered && rendered.nodeName;
Expand All @@ -152,7 +153,7 @@ export function renderComponent(component: Component, opts?: number, mountALL?:
if (inst) {
// 设置到toUnmount等待unmount
toUnmount = inst;
toUnmount.child = {...toUnmount.child};
toUnmount.child = extend({}, toUnmount.child);
// 防止共享子dom
inst.child.children = [];
}
Expand Down
44 changes: 34 additions & 10 deletions src/vdom/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@ export function diff(
componentRoot: boolean,
child: any,
): Element {
if (child.base && dom !== child.base) {
// 原preact使用dom存放数据,现在,如果dom不存在,且pchild内有dom就卸载掉
removeDomChild(child);
}
if (!diffLevel++) {
// 在diff调用递归层数为0时设置isSvgMode,hydrating
isSvgMode = parent != null && parent.ownerSVGDocument !== undefined;
hydrating = dom != null && !(child && ATTR_KEY in child);
hydrating = dom != null && !(child && child[ATTR_KEY]);
}
// 调用idiff生成dom
const ret = idiff(
Expand Down Expand Up @@ -89,13 +93,10 @@ function idiff(
componentRoot?: boolean,
child?: any,
) {
if (
dom == null
&& child.base != null
) {
// 原preact使用dom存放数据,现在,如果dom不存在,且pchild内有dom就卸载掉
removeDomChild(child);
}
// if (child.base && dom !== child.base) {
// // 原preact使用dom存放数据,现在,如果dom不存在,且pchild内有dom就卸载掉
// removeDomChild(child);
// }
let out = dom;
const prevSvgMode = isSvgMode;

Expand Down Expand Up @@ -205,14 +206,13 @@ function innerDiffNode(
isHydrating: boolean,
domChild: any,
) {
const originalChildren = domChild.children;
let originalChildren = domChild.children;
const children = [];
const keyed: {
[name: string]: any;
} = {};
let keyedLen = 0;
let min = 0;
const len = originalChildren.length;
let childrenLen = 0;
const vlen = vchildren ? vchildren.length : 0;
let j;
Expand All @@ -222,7 +222,31 @@ function innerDiffNode(
let child;
const pchildren = [];
const childNodes = dom.childNodes;
const unChildren = [];

if (childNodes.length !== originalChildren.length) {
let offset = 0;
const nodeList = childNodes;
const nodeLen = nodeList.length;
const newChildren = [];
for (let i = 0; i < nodeLen; i++) {
const node = nodeList[i];
let vdom = originalChildren[i + offset];
while (vdom && node !== vdom.base) {
offset ++;
vdom = originalChildren[i + offset];
}
if (vdom) {
newChildren.push(vdom);
} else {
newChildren.push({
base: node,
});
}
}
originalChildren = newChildren;
}
const len = originalChildren.length;
// Build up a map of keyed children and an Array of unkeyed children:
if (len !== 0) {
for (let i = 0; i < len; i++) {
Expand Down
3 changes: 2 additions & 1 deletion src/vdom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { VNode } from "../vnode";
import { Component } from "../component";
import { isTextNode } from "../dom/index";
import { ATTR_KEY } from "../constants";
import { extend } from "../util";

export function isSameNodeType(node: any, vnode: VNode, hydrating: boolean) {
if (typeof vnode === "string" || typeof vnode === "number") {
Expand All @@ -26,7 +27,7 @@ export function isNamedNode(
}

export function getNodeProps(vnode: VNode) {
const props = { ...vnode.attributes };
const props = extend({}, vnode.attributes);
props.children = vnode.children;
const nodeName: any = vnode.nodeName;
const defaultProps = nodeName.defaultProps;
Expand Down
14 changes: 10 additions & 4 deletions test/browser/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,19 @@ describe('context', () => {
getChildContext() {
return { innerContext };
}
render() {
render(props, state, context) {
expect(props.children).to.be.empty
expect(state).to.deep.equal({});
expect(context).to.deep.equal({ outerContext });
return <InnerMost />;
}
}

class InnerMost extends Component {
render() {
render(props, state, context) {
expect(props.children).to.be.empty
expect(state).to.deep.equal({});
expect(context).to.deep.equal({ outerContext, innerContext });
return <strong>test</strong>;
}
}
Expand All @@ -168,7 +174,7 @@ describe('context', () => {

render(<Outer />, scratch);

expect(Inner.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext });
expect(InnerMost.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext, innerContext });
// expect(Inner.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext });
// expect(InnerMost.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext, innerContext });
});
});
File renamed without changes.
2 changes: 1 addition & 1 deletion test/browser/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ describe('render()', () => {
};

const DOMElement = html`<div><a foo="bar"></a></div>`;
const preactElement = <div><a></a></div>;
const preactElement = <div><a></a></div>;

render(preactElement, scratch, DOMElement);
expect(scratch).to.have.property('innerHTML', '<div><a></a></div>');
Expand Down
File renamed without changes.
File renamed without changes.
13 changes: 5 additions & 8 deletions test/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ var localBrowsers = realBrowser ? Object.keys(travisLaunchers) : ['PhantomJS'];

module.exports = function(config) {
config.set({
browsers: ['Chrome'], //sauceLabs ? Object.keys(sauceLabsLaunchers) : localBrowsers,
browsers: ["Chrome"],//sauceLabs ? Object.keys(sauceLabsLaunchers) : localBrowsers,

frameworks: ['mocha', 'chai-sinon'],

reporters: ['mocha'].concat(
sauceLabs ? 'saucelabs' : []
sauceLabs ? 'saucelabs' : [],
coverage ? 'coverage-istanbul' : []
),

coverageReporter: {
dir: __dirname+'/../coverage',
reporters: [
Expand Down Expand Up @@ -143,14 +143,11 @@ module.exports = function(config) {
test: /\.jsx?$/,
use: 'istanbul-instrumenter-loader',
include: /build/,
exclude: /(node_modules|\.spec\.js$)/
exclude: /node_modules/
}: {}
]
},
resolve: {
// The React DevTools integration requires preact as a module
// rather than referencing source files inside the module
// directly
alias: { preact: '../src/zreact.ts' },
modules: [__dirname, 'node_modules']
},
Expand All @@ -169,7 +166,7 @@ module.exports = function(config) {
},
coverageIstanbulReporter: {
reports: ['html', 'lcovonly', 'text-summary'],
dir: 'coverage',
dir: 'test/coverage',
fixWebpackSourcePaths: true,
'report-config': {
html: {
Expand Down
19 changes: 13 additions & 6 deletions test/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="../dist/zreact.js"></script>
<script src="./preact.dev.js"></script>
<!-- <script src="./preact.dev.js"></script> -->
<title>Document</title>
</head>
<body>
<div id="app">
</div>
<script>

var Zreact = preact;
if (typeof preact !== "undefined")
var Zreact = preact;
// var Foo = Zreact.createClass({
// state: {
// num: [1,2,3]
Expand Down Expand Up @@ -43,9 +43,16 @@
var render = Zreact.render
var Component = Zreact.Component;
var rerender = Zreact.rerender;
let html = '<b>foo &amp; bar</b>';
let root = render(h("div", {dangerouslySetInnerHTML: { __html: html }}), scratch);
root = render(h("div", null, "a", h("strong", null, "b")), scratch, root);
const html = (htmlString) => {
const div = document.createElement('div');
div.innerHTML = htmlString;
return div.firstChild;
};

const DOMElement = html('<div><a foo="bar"></a></div>');
const preactElement = h("div", null, h("a"));

render(preactElement, scratch, DOMElement);
</script>
</body>
</html>

0 comments on commit 70a23c8

Please sign in to comment.