Skip to content

Commit

Permalink
feat: now extreme can render :for for custom component,but the perfor…
Browse files Browse the repository at this point in the history
…mance is not good
  • Loading branch information
GrinZero committed Feb 26, 2024
1 parent 32a7c7c commit cf260b5
Show file tree
Hide file tree
Showing 15 changed files with 239 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import template from "./index.html?raw";
import { createComponent } from "@sourcebug/extreme/dev";
import { createComponent, useMount } from "@sourcebug/extreme/dev";

export const MyButton = createComponent<{
id: string;
cb: () => void;
title: string;
}>("MyButton", ({ id, cb, title }) => {
useMount(() => {
document.getElementById(id)?.addEventListener("click", cb);
return () => {
document.getElementById(id)?.removeEventListener("click", cb);
};
});

return {
template,
state: {
Expand Down
4 changes: 4 additions & 0 deletions apps/demo/src/components/blench/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./button"
export * from './jumbotron'
export * from './main'
export * from './row'
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ <h1>React Hooks keyed</h1>
</div>
<div class="col-md-6">
<div class="row">
<MyButton :for="item in items" title="{{item.title}}"></MyButton>
<!-- <MyButton id="runlots" title="Create 10,000 rows" cb="{{runLots}}" />
<MyButton id="run" title="Create 1,000 rows" cb="{{run}}" />
<MyButton id="runlots" title="Create 10,000 rows" cb="{{runLots}}" />
<MyButton id="add" title="Append 1,000 rows" cb="{{add}}" />
<MyButton id="update" title="Update every 10th row" cb="{{update}}" />
<MyButton id="clear" title="Clear" cb="{{clear}}" />
<MyButton id="swaprows" title="Swap Rows" cb="{{swaprows}}" /> -->
<MyButton id="swaprows" title="Swap Rows" cb="{{swapRows}}" />
</div>
</div>
</div>
Expand Down
18 changes: 18 additions & 0 deletions apps/demo/src/components/blench/jumbotron/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import template from "./index.html?raw";
import { createComponent } from "@sourcebug/extreme/dev";

export const Jumbotron = createComponent<{
dispatch: (action: { type: string }) => void;
}>("Jumbotron", ({ dispatch }) => {
return {
template,
state: {
run: () => dispatch({ type: "RUN" }),
runLots: () => dispatch({ type: "RUN_LOTS" }),
add: () => dispatch({ type: "ADD" }),
update: () => dispatch({ type: "UPDATE" }),
clear: () => dispatch({ type: "CLEAR" }),
swapRows: () => dispatch({ type: "SWAP_ROWS" }),
},
};
});
9 changes: 9 additions & 0 deletions apps/demo/src/components/blench/main/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="container">
<Jumbotron dispatch="{{dispatch}}" />
<table class="table table-hover table-striped test-data">
<tbody>
<Row :for="item in data" key="{{item.id}}" item="{{item}}" dispatch="{{dispatch}}"></Row>
</tbody>
</table>
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true"></span>
</div>
127 changes: 127 additions & 0 deletions apps/demo/src/components/blench/main/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { createComponent, useState } from "@sourcebug/extreme/dev";
import template from "./index.html?raw";

const random = (max: number) => Math.round(Math.random() * 1000) % max;

const A = [
"pretty",
"large",
"big",
"small",
"tall",
"short",
"long",
"handsome",
"plain",
"quaint",
"clean",
"elegant",
"easy",
"angry",
"crazy",
"helpful",
"mushy",
"odd",
"unsightly",
"adorable",
"important",
"inexpensive",
"cheap",
"expensive",
"fancy",
];
const C = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
const N = [
"table",
"chair",
"house",
"bbq",
"desk",
"car",
"pony",
"cookie",
"sandwich",
"burger",
"pizza",
"mouse",
"keyboard",
];

let nextId = 1;

const buildData = (count: number) => {
const data = new Array(count);

for (let i = 0; i < count; i++) {
data[i] = {
id: nextId++,
label: `${A[random(A.length)]} ${C[random(C.length)]} ${N[random(N.length)]}`,
};
}

return data;
};

export const Main = createComponent("Main", () => {
const [data, setData] = useState<any[]>([]);
const [selected, setSelected] = useState(0);

const dispatch = (action: { type: string; id: number }) => {
switch (action.type) {
case "RUN":
debugger
setData(buildData(1000));
setSelected(0);
break;
case "RUN_LOTS":
setData(buildData(10000));
setSelected(0);
break;
case "ADD":
setData(data().concat(buildData(1000)));
break;
case "UPDATE": {
const newData = data().slice(0);
for (let i = 0; i < newData.length; i += 10) {
const r = newData[i];
newData[i] = { id: r.id, label: r.label + " !!!" };
}
setData(newData);
break;
}
case "CLEAR":
setData([]);
setSelected(0);
break;
case "SWAP_ROWS":
const newdata = [...data()];
if (data().length > 998) {
const d1 = newdata[1];
const d998 = newdata[998];
newdata[1] = d998;
newdata[998] = d1;
}
setData(newdata);
break;
case "REMOVE": {
const idx = data().findIndex((d) => d.id === action.id);
setData([...data().slice(0, idx), ...data().slice(idx + 1)]);
break;
}
case "SELECT":
setSelected(action.id);
break;
default:
break;
}
};

return {
template,
state: {
data,
selected,
dispatch,
},
};
});
12 changes: 12 additions & 0 deletions apps/demo/src/components/blench/row/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<tr class="{{containerClass}}">
<td class="col-md-1">{{item.id}}</td>
<td class="col-md-4">
<a @click="{{handleSelect}}">{{item.label}}</a>
</td>
<td class="col-md-1">
<a @click="{{handleRemove}}">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</a>
</td>
<td class="col-md-6"></td>
</tr>
20 changes: 20 additions & 0 deletions apps/demo/src/components/blench/row/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createComponent } from "@sourcebug/extreme/dev";
import template from "./index.html?raw";

export const Row = createComponent<{
selected: number;
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" : ""),
},
methods: {
handleSelect: () => dispatch({ type: "SELECT", id: item.id }),
handleRemove: () => dispatch({ type: "REMOVE", id: item.id }),
},
};
});
3 changes: 1 addition & 2 deletions apps/demo/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from "./counter"
export * from "./list"
export * from "./custom-component"
export * from './my-button'
export * from './jumbotron'
export * from './blench'
14 changes: 0 additions & 14 deletions apps/demo/src/components/jumbotron/index.ts

This file was deleted.

5 changes: 4 additions & 1 deletion apps/demo/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import "./style.css";
import { App, Demo } from "./modules";
export * from "./components"
import { Main } from "./components";
export * from "./components";

const handleHashChange = () => {
if (window.location.hash.match(/#\/demo/)) {
Demo(document.getElementById("app")!, {}, false);
} else if (window.location.hash.match(/#\/blench/)) {
Main(document.getElementById("app")!, {}, false);
} else {
App(document.getElementById("app")!, {}, false);
}
Expand Down
5 changes: 2 additions & 3 deletions apps/demo/src/modules/demo/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="demo-container" id="{{demoRef}}">
<!-- <a href="https://vitejs.dev" target="_blank">
<a href="https://vitejs.dev" target="_blank">
<img src="{{viteLogo}}" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
Expand All @@ -10,6 +10,5 @@ <h1>Vite + Extreme</h1>
<Counter />
<CustomComponent open="{{open}}" />
</div>
<p class="read-the-docs">open list</p> -->
<Jumbotron/>
<p class="read-the-docs">open list</p>
</div>
11 changes: 8 additions & 3 deletions packages/extreme/src/core/extreme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ export const createComponent = <Props extends Record<any, unknown>>(
const fn: ExtremeComponent<Props> = (
element: HTMLElement,
props: Props,
replace: boolean = true
replace: boolean = true,
isTemplate?: boolean
) => {
const result = component(props);
const ele = render(element, result.template, result, replace);
const pushElement = isTemplate
? document.createElement("template")
: element;

const ele = render(pushElement, result.template, result, replace, isTemplate);
currentCell.mount?.();
resetCurrentCell();
return ele;
Expand All @@ -45,4 +50,4 @@ export const createComponent = <Props extends Record<any, unknown>>(
}
extreme.store[name] = fn;
return fn;
};
};
30 changes: 23 additions & 7 deletions packages/extreme/src/core/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ export function render<T extends HTMLElement | HTMLTemplateElement>(
ref: null,
methods: null,
},
replace: boolean = true
replace: boolean = true,
isTemplate?: boolean
): ExtremeElement<T> {
const { state, ref, methods } = props;

const isTemplateNode = element.nodeName === "TEMPLATE";
const isTemplateNode = element.nodeName === "TEMPLATE" || isTemplate;
const stateSet = new Set<string>();
const customJobs: [string, Function, Record<string, unknown>][] = [];
const methodsMap = new Map<string, [string, Function][]>();
Expand Down Expand Up @@ -193,12 +194,25 @@ export function render<T extends HTMLElement | HTMLTemplateElement>(
return `id="${listID}Y${key}"`;
});
newDom = newDom.replace(/{{(.*?)}}/g, (_, key) => {
if (key === itemName) {
return _;
}
const value = getValue(item, key.replace(`${itemName}.`, ""));
if (value === undefined) {
return _;
}
return encodeValue(typeof value === "function" ? value() : value);
});
return newDom;
});
return domList;
return domList.map((domStr, i) => {
const template = document.createElement("template");
if (props.state && typeof props.state === "object") {
props.state = { ...props.state, ...{ [itemName]: data[i] } };
}
const d = render(template, domStr, props, false, true);
return d?.outerHTML || '';
});
};

if (typeof list === "function") {
Expand Down Expand Up @@ -305,11 +319,9 @@ export function render<T extends HTMLElement | HTMLTemplateElement>(
const fn = extreme.store[componentName];
const propsCurrent: Record<string, unknown> = {};
dom.replace(/\s(.*?)="(.*?)"/g, (_, _attrKey, _valueKey) => {
// TODO: 这里应该拿走每一个属性
const attrName = _attrKey.trim();
const valueKey = _valueKey.trim();


if (/{{(.*?)}}/.test(valueKey)) {
const newValueKey = valueKey.split("{{")[1].split("}}")[0];

Expand All @@ -324,7 +336,6 @@ export function render<T extends HTMLElement | HTMLTemplateElement>(
}

if (state && !attrName.startsWith("@")) {

propsCurrent[attrName] = getValue(state, newValueKey);
return _;
}
Expand Down Expand Up @@ -463,7 +474,12 @@ export function render<T extends HTMLElement | HTMLTemplateElement>(
const isFirst = backElement.firstElementChild === newEle;

if (newEle) {
const newElement: HTMLElement = fn(newEle, propsCurrent);
const newElement: HTMLElement = fn(
newEle,
propsCurrent,
false,
isTemplate
);
newElement.id = newElement.id || id;
if (isRoot || isFirst) {
ele = newElement;
Expand Down

0 comments on commit cf260b5

Please sign in to comment.