From 05f11d2c35ba7d3978954c4ce30675a4fa743696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B6=85=E6=B6=9B?= <10857776+chaoling83@user.noreply.gitee.com> Date: Mon, 5 Feb 2024 09:40:56 +0000 Subject: [PATCH] !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 --- packages/inula-novdom/src/core.ts | 70 +---- packages/inula-novdom/src/dom.ts | 19 +- .../inula/src/no-vnode/components/For.tsx | 125 -------- .../inula/src/no-vnode/components/Show.tsx | 25 -- packages/inula/src/no-vnode/core.ts | 91 ------ packages/inula/src/no-vnode/dom.ts | 295 ------------------ packages/inula/src/no-vnode/event.ts | 85 ----- 7 files changed, 17 insertions(+), 693 deletions(-) delete mode 100644 packages/inula/src/no-vnode/components/For.tsx delete mode 100644 packages/inula/src/no-vnode/components/Show.tsx delete mode 100644 packages/inula/src/no-vnode/core.ts delete mode 100644 packages/inula/src/no-vnode/dom.ts delete mode 100644 packages/inula/src/no-vnode/event.ts diff --git a/packages/inula-novdom/src/core.ts b/packages/inula-novdom/src/core.ts index e4c5fc39..e71ac0cd 100644 --- a/packages/inula-novdom/src/core.ts +++ b/packages/inula-novdom/src/core.ts @@ -17,76 +17,20 @@ import {insert} from './dom'; type ComponentConstructor = (props: T) => any; type CodeFunction = () => any; -type InitFunction = () => void; -type Options = Record; -type RootFunction = () => () => void; -type UpdateFunction = () => any; -export function createComponent(Comp: ComponentConstructor, props?: T): any { - return Comp(props || ({} as T)); +export function createComponent(Comp: ComponentConstructor, 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; -} diff --git a/packages/inula-novdom/src/dom.ts b/packages/inula-novdom/src/dom.ts index 15bada2f..2b52487f 100644 --- a/packages/inula-novdom/src/dom.ts +++ b/packages/inula-novdom/src/dom.ts @@ -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, 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 diff --git a/packages/inula/src/no-vnode/components/For.tsx b/packages/inula/src/no-vnode/components/For.tsx deleted file mode 100644 index 221b9710..00000000 --- a/packages/inula/src/no-vnode/components/For.tsx +++ /dev/null @@ -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(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; - }; -} diff --git a/packages/inula/src/no-vnode/components/Show.tsx b/packages/inula/src/no-vnode/components/Show.tsx deleted file mode 100644 index 15e2199d..00000000 --- a/packages/inula/src/no-vnode/components/Show.tsx +++ /dev/null @@ -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(props: { - if: any | (() => T); - else?: any; - children: JSXElement | (() => JSXElement); -}): any { - return () => RShow(props); -} diff --git a/packages/inula/src/no-vnode/core.ts b/packages/inula/src/no-vnode/core.ts deleted file mode 100644 index 3d8c3c76..00000000 --- a/packages/inula/src/no-vnode/core.ts +++ /dev/null @@ -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(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); - // } -} diff --git a/packages/inula/src/no-vnode/dom.ts b/packages/inula/src/no-vnode/dom.ts deleted file mode 100644 index 9b9ad2d6..00000000 --- a/packages/inula/src/no-vnode/dom.ts +++ /dev/null @@ -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; - } -} diff --git a/packages/inula/src/no-vnode/event.ts b/packages/inula/src/no-vnode/event.ts deleted file mode 100644 index 661a6e0d..00000000 --- a/packages/inula/src/no-vnode/event.ts +++ /dev/null @@ -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); - } -}