核心概念
RJS 實例(src/model/RJS.ts)如何建立與重新渲染,以及每次渲染為何是單次、非響應式。
實例生命週期
"#selector".RJS(body) 透過 body.id 查找目標元素,複製一份作為原始模板(#model),並將 data/event/when 儲存於實例上。若選擇器解析結果為 null,建構子會提早返回,不會初始化任何實例。
graph TB
Entry["#selector.RJS(body)"] --> Ctor["建構子: 查找節點, cloneNode(true)"]
Ctor --> Init["#init()"]
Init --> Before["when.before_render()"]
Before -->|"回傳 false"| Cancel["渲染中止"]
Before -->|"繼續"| SetDOM["#SET_DOM(body, data) — 遞迴走訪"]
SetDOM --> After["when.rendered()"]
app.renew(body) 會從複製的 #model 還原 DOM(replaceChildren(...this.#model.children)),將傳入的 data/event/when 鍵合併進現有實例狀態(未提及的鍵維持原值),並重新執行 #init()。這是 RJS 實例重新渲染的唯一方式——沒有自動響應式或髒值檢查機制。
before_render 回傳 false 會中止這次渲染,rendered 不會執行,模板文字維持原樣:
<div id="app"><p>{{ msg }}</p></div>
<script>
"#app".RJS({
data: { msg: "rendered" },
when: {
before_render: () => {
console.log("before_render");
return false;
},
rendered: () => console.log("rendered")
}
});
console.log("#app".$.textContent);
</script>
非響應式是刻意設計
RJS.ts 中每一段被註解掉的程式碼(#dataListener、Object.defineProperty 的 getter/setter 對)都是被移除的響應式 observer 機制。現行設計每次 #init() 只渲染一次,需要明確呼叫 renew() 才會更新——這項取捨正是 README 所述「移除自動監聽帶來的效能負擔」。