diff --git a/apps/demo/src/components/blench/button/index.html b/apps/demo/src/components/blench/button/index.html
index 8b37a63..bf8dc80 100644
--- a/apps/demo/src/components/blench/button/index.html
+++ b/apps/demo/src/components/blench/button/index.html
@@ -1,3 +1,3 @@
-
+
diff --git a/apps/demo/src/components/blench/button/index.ts b/apps/demo/src/components/blench/button/index.ts
index 609857e..8dd543d 100644
--- a/apps/demo/src/components/blench/button/index.ts
+++ b/apps/demo/src/components/blench/button/index.ts
@@ -1,17 +1,11 @@
import template from "./index.html?raw";
-import { createComponent, useMount } from "@sourcebug/extreme/dev";
+import { createComponent } from "@sourcebug/extreme/dev";
export const MyButton = createComponent<{
sid: string;
cb: () => void;
title: string;
}>("MyButton", ({ sid, cb, title }) => {
- useMount(() => {
- document.getElementById(sid)?.addEventListener("click", cb);
- return () => {
- document.getElementById(sid)?.removeEventListener("click", cb);
- };
- });
return {
template,
diff --git a/apps/demo/src/components/blench/row/index.ts b/apps/demo/src/components/blench/row/index.ts
index 26c6763..de7c9b8 100644
--- a/apps/demo/src/components/blench/row/index.ts
+++ b/apps/demo/src/components/blench/row/index.ts
@@ -3,20 +3,20 @@ import template from "./index.html?raw";
export const Row = createComponent<{
selected: () => number;
- item: { id: number; label: string };
+ item: () => { id: number; label: string };
dispatch: (action: { type: string; id: number }) => void;
}>("Row", ({ selected, item, dispatch }) => {
return {
template,
state: {
item,
- containerClass: () => (selected() === item.id ? "danger" : ""),
+ containerClass: () => (selected() === item().id ? "danger" : ""),
},
methods: {
handleSelect: () => {
- dispatch({ type: "SELECT", id: item.id });
+ dispatch({ type: "SELECT", id: item().id });
},
- handleRemove: () => dispatch({ type: "REMOVE", id: item.id }),
+ handleRemove: () => dispatch({ type: "REMOVE", id: item().id }),
},
};
});
diff --git a/packages/extreme/package.json b/packages/extreme/package.json
index f65e4cb..31b751a 100644
--- a/packages/extreme/package.json
+++ b/packages/extreme/package.json
@@ -1,6 +1,6 @@
{
"name": "@sourcebug/extreme",
- "version": "1.0.13",
+ "version": "1.0.15",
"description": "",
"main": "./dist/extreme.umd.js",
"module": "./dist/extreme.mjs",
diff --git a/packages/extreme/src/core/dom-str.ts b/packages/extreme/src/core/dom-str.ts
index 6f50853..9993439 100644
--- a/packages/extreme/src/core/dom-str.ts
+++ b/packages/extreme/src/core/dom-str.ts
@@ -1,6 +1,12 @@
export const getRandomID = () => "W" + Math.random().toString(36).slice(2, 10);
+const domStrCache = new Map();
export const findDomStr = (index: number, htmlText: string) => {
+ const key = `${index}#-${htmlText}`;
+ if (domStrCache.has(key)) {
+ return domStrCache.get(key)!;
+ }
+
let firstDOMIndex = htmlText.lastIndexOf("<", index);
let tag = "";
@@ -30,7 +36,9 @@ export const findDomStr = (index: number, htmlText: string) => {
break;
}
}
- return htmlText.slice(firstDOMIndex, lastIndex);
+ const result = htmlText.slice(firstDOMIndex, lastIndex);
+ domStrCache.set(key, result);
+ return result;
};
export const getDomAttr = (domStr: string, attr: string) => {
@@ -65,7 +73,7 @@ export const addDomID = (domStr: string, newID: string | (() => string)) => {
return [domStrWithID, id || getRandomID()];
};
-export const getHash = (str: string) => "W" + btoa(str).replace(/=/g, "ace");
+export const getHash = (str: string) => "W" + btoa(str).replace(/=/g, "~");
const analyzeDomCache = new Map();
diff --git a/packages/extreme/src/core/render.ts b/packages/extreme/src/core/render.ts
index b94159c..c44953d 100644
--- a/packages/extreme/src/core/render.ts
+++ b/packages/extreme/src/core/render.ts
@@ -1,4 +1,5 @@
-import { type Ref } from "../hooks";
+import { useState, type Ref } from "../hooks";
+import { markIdHandler } from "../worker/render";
import {
findDomStr,
getDomID,
@@ -26,6 +27,10 @@ const getValue = (state: Record, key: string) => {
let value = state;
for (let i = 0; i < keys.length; i++) {
if (!value) return;
+ if (typeof value === "function") {
+ // @ts-ignore
+ return (...rest) => value(...rest)[keys[i]];
+ }
value = value[keys[i]];
}
return value;
@@ -73,30 +78,7 @@ export async function render(
};
// 第一阶段,为所有使用了{{}}的dom添加id,或者对id="{{ref}}"的dom进行替换
- {
- const usageDomSet = new Set();
- template.replace(/{{(.*?)}}/g, (_, _key, start) => {
- usageDomSet.add(findDomStr(start, template));
- return _;
- });
- usageDomSet.forEach((dom) => {
- if (dom.indexOf("id=") === -1) {
- const [newDom] = addDomID(dom, getRandomID);
- template = template.replace(dom, newDom);
- }
- });
- template = template.replace(/id="{{(.*?)}}"/g, (_, key) => {
- const _key = key.trim();
- if (ref && _key in ref) {
- return `id="${ref[_key]}"`;
- }
- if (state && _key in state && typeof state[_key] === "string") {
- // TODO: 增加对state function的支持
- return `id="${state[_key]}"`;
- }
- return _;
- });
- }
+ template = markIdHandler(template, { ref, state });
// 第二阶段,收集所有methods和对应的DOM节点
{
@@ -194,6 +176,7 @@ export async function render(
testForResult.push([_, key, start]);
return _;
});
+
for (const [_, key, start] of testForResult) {
const [itemName, listName] = key
.trim()
@@ -211,8 +194,16 @@ export async function render(
const list = getValue(state, listName);
+ const signalCache = new Map();
const renderItem = async (item: any, index: number) => {
- const listID = getHash(String(item[keyIndex] ?? index));
+ const curKey = String(item[keyIndex] ?? index);
+ if (signalCache.has(curKey)) {
+ const fn = signalCache.get(curKey)!;
+ fn(item);
+ return "";
+ }
+
+ const listID = getHash(curKey);
let [newDom] = addDomID(dom, listID);
newDom = newDom.replace(/id="(.*?)"/g, (source, key) => {
if (key === listID) {
@@ -232,11 +223,14 @@ export async function render(
});
const template = document.createElement("template");
const cloneProps = { ...props };
+ const [sign, setSign] = useState(item);
+ signalCache.set(curKey, setSign);
+
if (cloneProps.state && typeof cloneProps.state === "object") {
cloneProps.state = {
...cloneProps.state,
- // TODO:通过设置state()的render,可以在item改变时触发render快速得到新的dom,不用重计算
- ...{ [itemName]: item },
+ // TODO:通过设置state()的render,可以在item改变时触发render快速得到新的dom,不用重计算item
+ ...{ [itemName]: sign },
key: item[keyIndex] ?? index,
};
}
@@ -301,6 +295,7 @@ export async function render(
const oldIndex = oldKeyToIndex.get(oldKey) ?? -1;
const dom = parent.children[oldIndex];
dom && toRemove.push(dom);
+ signalCache.delete(oldKey);
}
}
for (const dom of toRemove) {
@@ -326,10 +321,10 @@ export async function render(
if (index === oldIndex) {
// 位置正确,不需要移动
if (oldData !== newData && newList[index]) {
- const renderDom = await renderItem(newList[index], index);
- if (renderDom !== childNode.outerHTML) {
- childNode.outerHTML = renderDom;
- }
+ await renderItem(newList[index], index);
+ // if (renderDom !== childNode.outerHTML) {
+ // childNode.outerHTML = renderDom;
+ // }
}
} else {
if (index > oldIndex) {
@@ -346,10 +341,10 @@ export async function render(
}
}
if (oldData !== newData && newList[index]) {
- const renderDom = await renderItem(newList[index], index);
- if (renderDom !== childNode.outerHTML) {
- childNode.outerHTML = renderDom;
- }
+ await renderItem(newList[index], index);
+ // if (renderDom !== childNode.outerHTML) {
+ // childNode.outerHTML = renderDom;
+ // }
}
}
usagKeyList.delete(curKey);
@@ -494,14 +489,25 @@ export async function render(
/{{(.*?)}}/g,
(source, key, start) => {
const value = getValue(state, key);
+ // debugger;
if (typeof value === "function") {
- const analyzeUpdateKey = analyzeKey(baseDomStr, source, start);
+ const updateDom = findDomStr(start, baseDomStr);
+ const updateDomId = getDomID(updateDom);
+ const analyzeUpdateKey = analyzeKey(
+ updateDom,
+ source,
+ updateDom !== baseDomStr ? updateDom.indexOf(source) : start
+ );
if (analyzeUpdateKey === null) {
+ // debugger;
console.error(`[extreme] ${source} is not a valid UpdateKey`);
return source;
}
const rerenderDom = () => {
- const dom = document.getElementById(ele?.id || id);
+ const dom =
+ document.getElementById(updateDomId ?? ele?.id ?? id) ||
+ document.getElementById(ele?.id ?? id);
+ // debugger
if (!dom) return;
const newValue = encodeValue(value());
switch (analyzeUpdateKey.type) {
diff --git a/packages/extreme/src/hooks/useEffect.ts b/packages/extreme/src/hooks/useEffect.ts
index 800bcdf..d9ae4e0 100644
--- a/packages/extreme/src/hooks/useEffect.ts
+++ b/packages/extreme/src/hooks/useEffect.ts
@@ -1,7 +1,10 @@
import type { GetState } from "./useState";
-
import { idleCallback } from "./useState";
export const useEffect = (fn: Function, deps: GetState[]) => {
- for (const dep of deps) dep((v) => idleCallback(() => fn(v)))
+ for (const dep of deps)
+ dep((v) => {
+ idleCallback(() => fn(v));
+ return;
+ });
};
diff --git a/packages/extreme/src/utils/index.ts b/packages/extreme/src/utils/index.ts
new file mode 100644
index 0000000..fd87a10
--- /dev/null
+++ b/packages/extreme/src/utils/index.ts
@@ -0,0 +1 @@
+export * from './worker'
\ No newline at end of file
diff --git a/packages/extreme/src/utils/worker.ts b/packages/extreme/src/utils/worker.ts
new file mode 100644
index 0000000..2ea4c54
--- /dev/null
+++ b/packages/extreme/src/utils/worker.ts
@@ -0,0 +1 @@
+export const MAX_WORKER_COUNT = navigator.hardwareConcurrency / 2 + 1;
diff --git a/packages/extreme/src/worker/render.ts b/packages/extreme/src/worker/render.ts
new file mode 100644
index 0000000..89f1427
--- /dev/null
+++ b/packages/extreme/src/worker/render.ts
@@ -0,0 +1,44 @@
+import { getRandomID, findDomStr, addDomID } from "../core/dom-str";
+import type { Ref } from "../hooks";
+
+export type PropsRef = Record | null;
+export type PropsState = Record string)> | null;
+
+export const markIdHandler = (
+ template: string,
+ {
+ ref,
+ state,
+ }: {
+ ref?: PropsRef;
+ state?: PropsState;
+ } = {}
+) => {
+ const usageDomSet = new Set();
+ template.replace(/{{(.*?)}}/g, (_, _key, start) => {
+ usageDomSet.add(findDomStr(start, template));
+ return _;
+ });
+ usageDomSet.forEach((dom) => {
+ if (dom.indexOf("id=") === -1) {
+ const [newDom] = addDomID(dom, getRandomID);
+ template = template.replace(dom, newDom);
+ }
+ });
+ template = template.replace(/id="{{(.*?)}}"/g, (_, key) => {
+ const _key = key.trim();
+ if (ref && _key in ref) {
+ return `id="${ref[_key]}"`;
+ }
+ if (state && _key in state && typeof state[_key] === "string") {
+ // TODO: 增加对state function的支持
+ return `id="${state[_key]}"`;
+ }
+ return _;
+ });
+ return template;
+};
+
+export const collectMethodHanlder=()=>{
+
+}
\ No newline at end of file