!135 fix(no-vdom): delete no-vnode module
* fix(no-vdom): delete no-vnode module * fix(no-vdom): update render function * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge remote-tracking branch 'origin/reactive' into reactive * fix(no-vdom): add TS * fix(no-vdom): change js 2 ts
This commit is contained in:
parent
a2e27d163a
commit
05f11d2c35
|
@ -17,76 +17,20 @@ import {insert} from './dom';
|
|||
|
||||
type ComponentConstructor<T> = (props: T) => any;
|
||||
type CodeFunction = () => any;
|
||||
type InitFunction = () => void;
|
||||
type Options = Record<string, any>;
|
||||
type RootFunction = () => () => void;
|
||||
type UpdateFunction = () => any;
|
||||
|
||||
export function createComponent<T>(Comp: ComponentConstructor<T>, props?: T): any {
|
||||
return Comp(props || ({} as T));
|
||||
export function createComponent<T>(Comp: ComponentConstructor<T>, props: T = {} as T): any {
|
||||
return Comp(props);
|
||||
}
|
||||
|
||||
export function render(code: CodeFunction, element: HTMLElement, init: InitFunction): () => void {
|
||||
let disposer: () => void;
|
||||
export function render(codeFn: CodeFunction, element: HTMLElement): () => void {
|
||||
const disposer = (): void => {
|
||||
// TODO
|
||||
};
|
||||
|
||||
createRoot(dispose => {
|
||||
disposer = dispose;
|
||||
if (element === document) {
|
||||
code();
|
||||
} else {
|
||||
insert(element, code(), element.firstChild ? null : undefined, init);
|
||||
}
|
||||
});
|
||||
insert(element, codeFn(), element.firstChild ? null : undefined);
|
||||
|
||||
return () => {
|
||||
disposer();
|
||||
element.textContent = '';
|
||||
};
|
||||
}
|
||||
|
||||
let Owner: any;
|
||||
let Listener: any;
|
||||
|
||||
function createRoot(fn: RootFunction): any {
|
||||
const listener = Listener;
|
||||
const owner = Owner;
|
||||
const unowned = fn.length === 0;
|
||||
const current = owner;
|
||||
const root = {
|
||||
owned: null,
|
||||
cleanups: null,
|
||||
context: current ? current.context : null,
|
||||
owner: current,
|
||||
};
|
||||
const updateFn = () => {
|
||||
fn(() => {
|
||||
});
|
||||
};
|
||||
|
||||
Owner = root;
|
||||
Listener = null;
|
||||
try {
|
||||
return runUpdates(updateFn, true);
|
||||
} finally {
|
||||
Listener = listener;
|
||||
Owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
let Updates: UpdateFunction[] | null;
|
||||
let Effects: any[] | null;
|
||||
let ExecCount = 0;
|
||||
|
||||
function runUpdates(fn: UpdateFunction, init: boolean): any {
|
||||
if (Updates) return fn();
|
||||
let wait = false;
|
||||
if (!init) Updates = [];
|
||||
if (Effects) {
|
||||
wait = true;
|
||||
} else {
|
||||
Effects = [];
|
||||
}
|
||||
ExecCount++;
|
||||
const res = fn();
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -13,20 +13,21 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { watch } from 'inula-reactive';
|
||||
import { isReactiveObj, ReactiveObj } from 'inula-reactive';
|
||||
import { isReactiveObj, ReactiveObj, watch } from 'inula-reactive';
|
||||
|
||||
/**
|
||||
* Creates a function that returns a Node created from the provided HTML string.
|
||||
* @param {string} html - The HTML string to be used for creating the Node.
|
||||
* @returns {() => Node} A function that returns a Node created from the provided HTML string.
|
||||
*/
|
||||
export function template(html: string): () => Node {
|
||||
let node: Node | null;
|
||||
const create = (): Node => {
|
||||
const t = document.createElement('template');
|
||||
t.innerHTML = html;
|
||||
return t.content.firstChild as Node;
|
||||
};
|
||||
|
||||
const fn = (): Node => (node || (node = create())).cloneNode(true);
|
||||
fn.cloneNode = fn;
|
||||
return fn;
|
||||
return (): Node => create();
|
||||
}
|
||||
|
||||
export function insert(parent: Node, accessor: ReactiveObj<any> | any, marker?: Node, initial?: any[]): any {
|
||||
|
@ -160,11 +161,11 @@ function appendNodes(parent: Node, array: Node[], marker: Node | null = null): v
|
|||
}
|
||||
|
||||
// 拆解数组,如:[[a, b], [c, d], ...] to [a, b, c, d]
|
||||
function normalizeIncomingArray(normalized, array, unwrap) {
|
||||
function normalizeIncomingArray(normalized: Node[], array: any[], unwrap?: boolean): boolean {
|
||||
let dynamic = false;
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
let item = array[i],
|
||||
t;
|
||||
let item = array[i];
|
||||
let t: string;
|
||||
if (item == null || item === true || item === false) {
|
||||
// matches null, undefined, true or false
|
||||
// skip
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { JSXElement } from '../../renderer/Types';
|
||||
import { computed } from '../../reactive/Computed';
|
||||
import { untrack } from '../../reactive/RNode';
|
||||
|
||||
// TODO 需要优化为精细更新
|
||||
export function For<T>(props: { each: any; children?: (value: any, index: number) => JSXElement }) {
|
||||
let list = props.each,
|
||||
mapFn = props.children,
|
||||
items = [],
|
||||
mapped = [],
|
||||
disposers = [],
|
||||
len = 0;
|
||||
|
||||
return () => {
|
||||
let newItems = list.get() || [];
|
||||
|
||||
untrack(() => {
|
||||
let i, j;
|
||||
|
||||
let newLen = newItems.length,
|
||||
newIndices,
|
||||
newIndicesNext,
|
||||
temp,
|
||||
start,
|
||||
end,
|
||||
newEnd,
|
||||
item;
|
||||
|
||||
if (newLen === 0) {
|
||||
// 没新数据
|
||||
if (len !== 0) {
|
||||
disposers = [];
|
||||
items = [];
|
||||
mapped = [];
|
||||
len = 0;
|
||||
}
|
||||
} else if (len === 0) {
|
||||
// 上一次没有数据
|
||||
mapped = new Array(newLen);
|
||||
for (j = 0; j < newLen; j++) {
|
||||
items[j] = newItems[j];
|
||||
mapped[j] = mapFn(list[j]);
|
||||
}
|
||||
len = newLen;
|
||||
} else { // 都有数据
|
||||
// temp = new Array(newLen);
|
||||
//
|
||||
// // 从前往后,判断相等。但是这种前度比较经常是不生效的,比如数组的值相同,指针不一样
|
||||
// for (start = 0, end = Math.min(len, newLen); start < end && items[start] === newItems[start]; start++);
|
||||
//
|
||||
// // 从后往前
|
||||
// for (
|
||||
// end = len - 1, newEnd = newLen - 1;
|
||||
// end >= start && newEnd >= start && items[end] === newItems[newEnd]; // 值相等
|
||||
// end--, newEnd--
|
||||
// ) {
|
||||
// temp[newEnd] = mapped[end]; // 把dom取出来
|
||||
// }
|
||||
// // 从start -> newEnd就是不相等的
|
||||
//
|
||||
// newIndices = new Map();
|
||||
// newIndicesNext = new Array(newEnd + 1);
|
||||
// for (j = newEnd; j >= start; j--) {
|
||||
// item = newItems[j];
|
||||
// i = newIndices.get(item);
|
||||
// newIndicesNext[j] = i === undefined ? -1 : i; // item数据可能指针相同,重复。因为是倒序遍历,所以i就是相同数据下一个位置。
|
||||
// newIndices.set(item, j); // 新数据,放到map中
|
||||
// }
|
||||
//
|
||||
// // 遍历旧数据
|
||||
// for (i = start; i <= end; i++) {
|
||||
// item = items[i];
|
||||
// j = newIndices.get(item); // j 是相同数据的第一个
|
||||
// // 旧行数据,在新数据中存在,在j位置
|
||||
// if (j !== undefined && j !== -1) {
|
||||
// temp[j] = mapped[i]; // 把就dom放到新的j位置
|
||||
// j = newIndicesNext[j];
|
||||
// newIndices.set(item, j); // 修改map里面的位置,改为下一个
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 往mapped中放入start - newLen的dom数据
|
||||
// for (j = start; j < newLen; j++) { // 按新数据来遍历
|
||||
// if (j in temp) {
|
||||
// mapped[j] = temp[j]; // 直接取旧的
|
||||
// } else {
|
||||
// mapped[j] = mapFn(list[j]); // 创建新的dom
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 0 - start 数据没有变动
|
||||
// mapped = mapped.slice(0, (len = newLen)); // 如果newLen小于len,就截断
|
||||
// items = newItems.slice(0);
|
||||
|
||||
// 假设新旧相同行数据已经更新
|
||||
if (newLen > len) {
|
||||
for (let i = len; i < newLen; i++) {
|
||||
mapped[i] = mapFn(list[i]); // 创建新的dom
|
||||
}
|
||||
}
|
||||
|
||||
// 0 - start 数据没有变动
|
||||
mapped = mapped.slice(0, (len = newLen)); // 如果newLen小于len,就截断
|
||||
items = newItems.slice(0);
|
||||
}
|
||||
});
|
||||
|
||||
return mapped;
|
||||
};
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { JSXElement } from '../../renderer/Types';
|
||||
import { Show as RShow } from '../../reactive/components/Show';
|
||||
|
||||
export function Show<T>(props: {
|
||||
if: any | (() => T);
|
||||
else?: any;
|
||||
children: JSXElement | (() => JSXElement);
|
||||
}): any {
|
||||
return () => RShow(props);
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { insert } from './dom';
|
||||
|
||||
export function createComponent<T>(Comp, props) {
|
||||
return Comp(props || ({} as T));
|
||||
}
|
||||
|
||||
export function render(code, element, init, options = {}) {
|
||||
let disposer;
|
||||
|
||||
createRoot(dispose => {
|
||||
disposer = dispose;
|
||||
if (element === document) {
|
||||
code();
|
||||
} else {
|
||||
insert(element, code(), element.firstChild ? null : undefined, init);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposer();
|
||||
element.textContent = '';
|
||||
};
|
||||
}
|
||||
|
||||
let Owner;
|
||||
let Listener;
|
||||
|
||||
function createRoot(fn) {
|
||||
const listener = Listener;
|
||||
const owner = Owner;
|
||||
const unowned = fn.length === 0;
|
||||
const current = owner;
|
||||
const root = {
|
||||
owned: null,
|
||||
cleanups: null,
|
||||
context: current ? current.context : null,
|
||||
owner: current,
|
||||
};
|
||||
const updateFn = () => {
|
||||
// fn(() => cleanNode(root));
|
||||
fn(() => {});
|
||||
};
|
||||
|
||||
Owner = root;
|
||||
Listener = null;
|
||||
try {
|
||||
return runUpdates(updateFn, true);
|
||||
} finally {
|
||||
Listener = listener;
|
||||
Owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
let Updates, Effects;
|
||||
let ExecCount = 0;
|
||||
|
||||
function runUpdates(fn, init) {
|
||||
if (Updates) return fn();
|
||||
let wait = false;
|
||||
if (!init) Updates = [];
|
||||
if (Effects) {
|
||||
wait = true;
|
||||
} else {
|
||||
Effects = [];
|
||||
}
|
||||
ExecCount++;
|
||||
// try {
|
||||
const res = fn();
|
||||
// completeUpdates(wait);
|
||||
return res;
|
||||
// } catch (err) {
|
||||
// if (!wait) Effects = null;
|
||||
// Updates = null;
|
||||
// // handleError(err);
|
||||
// }
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { watch } from '../reactive/Watch';
|
||||
import { isReactiveObj } from '../reactive/Utils';
|
||||
|
||||
export function template(html) {
|
||||
let node;
|
||||
const create = () => {
|
||||
const t = document.createElement('template');
|
||||
t.innerHTML = html;
|
||||
return t.content.firstChild;
|
||||
};
|
||||
|
||||
const fn = () => (node || (node = create())).cloneNode(true);
|
||||
fn.cloneNode = fn;
|
||||
return fn;
|
||||
}
|
||||
|
||||
export function insert(parent, accessor, marker, initial) {
|
||||
if (marker !== undefined && !initial) {
|
||||
initial = [];
|
||||
}
|
||||
|
||||
if (isReactiveObj(accessor)) {
|
||||
watchRender(current => {
|
||||
return insertExpression(parent, accessor.get(), current, marker);
|
||||
}, initial);
|
||||
} else {
|
||||
return insertExpression(parent, accessor, initial, marker);
|
||||
}
|
||||
}
|
||||
|
||||
function watchRender(fn, prevValue) {
|
||||
let nextValue = prevValue;
|
||||
watch(() => {
|
||||
nextValue = fn(nextValue);
|
||||
});
|
||||
}
|
||||
|
||||
function insertExpression(parent, value, current, marker, unwrapArray) {
|
||||
while (typeof current === 'function') current = current();
|
||||
if (value === current) return value;
|
||||
|
||||
const t = typeof value,
|
||||
multi = marker !== undefined;
|
||||
|
||||
if (t === 'string' || t === 'number') {
|
||||
if (t === 'number') value = value.toString();
|
||||
if (multi) {
|
||||
let node = current[0];
|
||||
if (node && node.nodeType === 3) {
|
||||
node.data = value;
|
||||
} else {
|
||||
node = document.createTextNode(value);
|
||||
}
|
||||
current = cleanChildren(parent, current, marker, node);
|
||||
} else {
|
||||
if (current !== '' && typeof current === 'string') {
|
||||
current = parent.firstChild.data = value;
|
||||
} else current = parent.textContent = value;
|
||||
}
|
||||
} else if (value == null || t === 'boolean') {
|
||||
current = cleanChildren(parent, current, marker);
|
||||
} else if (t === 'function') {
|
||||
// 在watch里面执行
|
||||
watch(() => {
|
||||
let v = value();
|
||||
while (isReactiveObj(v)) {
|
||||
v = v.get();
|
||||
}
|
||||
|
||||
current = insertExpression(parent, v, current, marker);
|
||||
});
|
||||
return () => current;
|
||||
} else if (Array.isArray(value)) {
|
||||
// return [() => {}, () => {}, ...]
|
||||
const array = [];
|
||||
const currentArray = current && Array.isArray(current);
|
||||
if (normalizeIncomingArray(array, value, current, unwrapArray)) {
|
||||
watchRender(() => (current = insertExpression(parent, array, current, marker, true)));
|
||||
return () => current;
|
||||
}
|
||||
|
||||
if (array.length === 0) {
|
||||
// 当前没有节点
|
||||
current = cleanChildren(parent, current, marker);
|
||||
if (multi) return current;
|
||||
} else if (currentArray) {
|
||||
if (current.length === 0) {
|
||||
appendNodes(parent, array, marker); // 原来没有节点
|
||||
} else {
|
||||
reconcileArrays(parent, current, array); // 原本有节点,现在也有节点
|
||||
}
|
||||
} else {
|
||||
current && cleanChildren(parent);
|
||||
appendNodes(parent, array);
|
||||
}
|
||||
current = array;
|
||||
} else if (value.nodeType) {
|
||||
if (Array.isArray(current)) {
|
||||
if (multi) return (current = cleanChildren(parent, current, marker, value));
|
||||
cleanChildren(parent, current, null, value);
|
||||
} else if (current == null || current === '' || !parent.firstChild) {
|
||||
parent.appendChild(value);
|
||||
} else {
|
||||
parent.replaceChild(value, parent.firstChild);
|
||||
}
|
||||
current = value;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
function cleanChildren(parent, current, marker, replacement) {
|
||||
if (marker === undefined) {
|
||||
return (parent.textContent = '');
|
||||
}
|
||||
|
||||
const node = replacement || document.createTextNode('');
|
||||
if (current.length) {
|
||||
let inserted = false;
|
||||
for (let i = current.length - 1; i >= 0; i--) {
|
||||
const el = current[i];
|
||||
if (node !== el) {
|
||||
const isParent = el.parentNode === parent;
|
||||
if (!inserted && !i) {
|
||||
isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker);
|
||||
} else {
|
||||
isParent && el.remove();
|
||||
}
|
||||
} else {
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent.insertBefore(node, marker);
|
||||
}
|
||||
|
||||
return [node];
|
||||
}
|
||||
|
||||
function appendNodes(parent, array, marker = null) {
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
parent.insertBefore(array[i], marker);
|
||||
}
|
||||
}
|
||||
|
||||
// 拆解数组,如:[[a, b], [c, d], ...] to [a, b, c, d]
|
||||
function normalizeIncomingArray(normalized, array, unwrap) {
|
||||
let dynamic = false;
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
let item = array[i],
|
||||
t;
|
||||
if (item == null || item === true || item === false) {
|
||||
// matches null, undefined, true or false
|
||||
// skip
|
||||
} else if (Array.isArray(item)) {
|
||||
dynamic = normalizeIncomingArray(normalized, item) || dynamic;
|
||||
} else if ((t = typeof item) === 'string' || t === 'number') {
|
||||
normalized.push(document.createTextNode(item));
|
||||
} else if (t === 'function') {
|
||||
if (unwrap) {
|
||||
while (typeof item === 'function') item = item();
|
||||
dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic;
|
||||
} else {
|
||||
normalized.push(item);
|
||||
dynamic = true;
|
||||
}
|
||||
} else {
|
||||
normalized.push(item);
|
||||
}
|
||||
}
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
// 原本有节点,现在也有节点
|
||||
export default function reconcileArrays(parentNode, oldChildren, newChildren) {
|
||||
let nLength = newChildren.length,
|
||||
oEnd = oldChildren.length,
|
||||
nEnd = nLength,
|
||||
oStart = 0,
|
||||
nStart = 0,
|
||||
after = oldChildren[oEnd - 1].nextSibling,
|
||||
map = null;
|
||||
|
||||
while (oStart < oEnd || nStart < nEnd) {
|
||||
// 从前到后对比相同内容
|
||||
if (oldChildren[oStart] === newChildren[nStart]) {
|
||||
oStart++;
|
||||
nStart++;
|
||||
continue;
|
||||
}
|
||||
// 从后往前对比相同内容
|
||||
while (oldChildren[oEnd - 1] === newChildren[nEnd - 1]) {
|
||||
oEnd--;
|
||||
nEnd--;
|
||||
}
|
||||
// append
|
||||
if (oEnd === oStart) {
|
||||
// 旧节点全部和新节点相同(不是完全相同, 如:旧 abcd 新 abefcd)
|
||||
const node = nEnd < nLength ? (nStart ? newChildren[nStart - 1].nextSibling : newChildren[nEnd - nStart]) : after;
|
||||
|
||||
while (nStart < nEnd) {
|
||||
parentNode.insertBefore(newChildren[nStart++], node);
|
||||
}
|
||||
// remove
|
||||
} else if (nEnd === nStart) {
|
||||
// 新节点全部和新节点相同(不是完全相同, 如:旧 abefcd 新 abcd)
|
||||
while (oStart < oEnd) {
|
||||
if (!map || !map.has(oldChildren[oStart])) {
|
||||
oldChildren[oStart].remove();
|
||||
}
|
||||
oStart++;
|
||||
}
|
||||
// swap backward
|
||||
} else if (oldChildren[oStart] === newChildren[nEnd - 1] && newChildren[nStart] === oldChildren[oEnd - 1]) {
|
||||
// 如:旧 ab ef cd 新 ab fe cd
|
||||
const node = oldChildren[--oEnd].nextSibling;
|
||||
parentNode.insertBefore(newChildren[nStart++], oldChildren[oStart++].nextSibling); // 如:旧 abe f fcd
|
||||
parentNode.insertBefore(newChildren[--nEnd], node); // 如:旧 abeff e cd
|
||||
|
||||
oldChildren[oEnd] = newChildren[nEnd];
|
||||
// fallback to map
|
||||
} else {
|
||||
// 如:旧 ab feww cd 新 ab hgeht cd
|
||||
if (!map) {
|
||||
map = new Map();
|
||||
let i = nStart;
|
||||
|
||||
while (i < nEnd) {
|
||||
map.set(newChildren[i], i++); // 收集 hgeht
|
||||
}
|
||||
}
|
||||
|
||||
const index = map.get(oldChildren[oStart]);
|
||||
if (index != null) {
|
||||
// 如:e就在newChildren中
|
||||
if (nStart < index && index < nEnd) {
|
||||
// 且位置在新节点 之间
|
||||
let i = oStart,
|
||||
sequence = 1,
|
||||
t;
|
||||
|
||||
while (++i < oEnd && i < nEnd) {
|
||||
// 如:旧 ab feww cd 新 ab hgeht cd, e 的 sequence 是 2 ?
|
||||
if ((t = map.get(oldChildren[i])) == null || t !== index + sequence) break;
|
||||
sequence++;
|
||||
}
|
||||
|
||||
if (sequence > index - nStart) {
|
||||
const node = oldChildren[oStart];
|
||||
while (nStart < index) {
|
||||
parentNode.insertBefore(newChildren[nStart++], node);
|
||||
}
|
||||
} else {
|
||||
parentNode.replaceChild(newChildren[nStart++], oldChildren[oStart++]);
|
||||
}
|
||||
} else {
|
||||
oStart++;
|
||||
}
|
||||
} else {
|
||||
oldChildren[oStart++].remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setAttribute(node, name, value) {
|
||||
if (value == null) {
|
||||
node.removeAttribute(name);
|
||||
} else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
export function className(node, value) {
|
||||
if (value == null) {
|
||||
node.removeAttribute('class');
|
||||
} else {
|
||||
node.className = value;
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
const $$EVENTS = "_$DX_DELEGATE";
|
||||
|
||||
/**
|
||||
* 在 document上注册事件
|
||||
* @param eventNames
|
||||
* @param document
|
||||
*/
|
||||
export function delegateEvents(eventNames, document = window.document) {
|
||||
const e = document[$$EVENTS] || (document[$$EVENTS] = new Set());
|
||||
for (let i = 0, l = eventNames.length; i < l; i++) {
|
||||
const name = eventNames[i];
|
||||
if (!e.has(name)) {
|
||||
e.add(name);
|
||||
document.addEventListener(name, eventHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
export function clearDelegatedEvents(document = window.document) {
|
||||
if (document[$$EVENTS]) {
|
||||
for (let name of document[$$EVENTS].keys()) document.removeEventListener(name, eventHandler);
|
||||
delete document[$$EVENTS];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function eventHandler(e) {
|
||||
const key = `$$${e.type}`;
|
||||
let node = (e.composedPath && e.composedPath()[0]) || e.target;
|
||||
if (e.target !== node) {
|
||||
Object.defineProperty(e, "target", {
|
||||
configurable: true,
|
||||
value: node
|
||||
});
|
||||
}
|
||||
Object.defineProperty(e, "currentTarget", {
|
||||
configurable: true,
|
||||
get() {
|
||||
return node || document;
|
||||
}
|
||||
});
|
||||
|
||||
// 冒泡执行事件
|
||||
while (node) {
|
||||
const handler = node[key];
|
||||
if (handler && !node.disabled) {
|
||||
const data = node[`${key}Data`];
|
||||
data !== undefined ? handler.call(node, data, e) : handler.call(node, e);
|
||||
if (e.cancelBubble) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
node = node._$host || node.parentNode || node.host;
|
||||
}
|
||||
}
|
||||
|
||||
export function addEventListener(node, name, handler, delegate) {
|
||||
if (delegate) {
|
||||
if (Array.isArray(handler)) {
|
||||
node[`$$${name}`] = handler[0];
|
||||
node[`$$${name}Data`] = handler[1];
|
||||
} else {
|
||||
node[`$$${name}`] = handler;
|
||||
}
|
||||
} else if (Array.isArray(handler)) {
|
||||
const handlerFn = handler[0];
|
||||
node.addEventListener(name, (handler[0] = e => handlerFn.call(node, handler[1], e)));
|
||||
} else {
|
||||
node.addEventListener(name, handler);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue