CHACHA 和 HTML 模板
框架提供了它們自己表達(dá)可觀察列表的方式?,F(xiàn)在很多開發(fā)者也依賴提供這種功能的非框架庫(kù),如 MobX。
通用的可觀察列表的主要問題在于它們是通用的。這以性能為代價(jià)增加了便利性,而且還需要特殊的開發(fā)者工具來調(diào)試那些庫(kù)在后臺(tái)做的復(fù)雜動(dòng)作。
使用這些庫(kù)并理解它們的作用是可以的,無論選擇什么樣的 UI 框架,它們都是有用的,但使用替代方案可能不會(huì)更復(fù)雜,而且可以避免一些在你試圖推出自己的模型時(shí)產(chǎn)生的陷阱。
變化通道(或 CHACHA)
CHACHA——也被稱為變化通道(Changes Channel)——是一個(gè)雙向流,其目的是通知意圖方向和觀察方向的變化。
- 在意圖方向上,UI 將用戶意圖的變化通知給模型。
- 在觀察方向上,模型將對(duì)模型所做的改變通知給 UI,而這些改變需要顯示給用戶。
這也許是一個(gè)有趣的名字,但它不是一個(gè)復(fù)雜或新穎的模式。雙向流在 Web 和軟件中隨處可見(例如,MessagePort)。在這種情況下,我們正在創(chuàng)建一個(gè)雙向流,它有一個(gè)特殊的目的:向 UI 報(bào)告實(shí)際的模型變化,并向模型報(bào)告意圖。
CHACHA 的接口通??梢詮膽?yīng)用的規(guī)范中導(dǎo)出,而不需要任何 UI 代碼。
例如,一個(gè)允許你添加和刪除聯(lián)系人并從服務(wù)器加載初始列表的應(yīng)用程序(帶有刷新選項(xiàng))可以有一個(gè) CHACHA,它看起來像這樣:
interface Contact {
id: string;
name: string;
email: string;
}
// "Observe" Direction
interface ContactListModelObserver {
onAdd(contact: Contact);
onRemove(contact: Contact);
onUpdate(contact: Contact);
}
// "Intent" Direction
interface ContactListModel {
add(contact: Contact);
remove(contact: Contact);
reloadFromServer();
}
請(qǐng)注意,這兩個(gè)接口中的所有函數(shù)都是無效的,只接收普通對(duì)象。這是故意的。CHACHA 被構(gòu)建成一個(gè)通道,有兩個(gè)端口來發(fā)送消息,這使得它可以在 EventSource、HTML MessageChannel、服務(wù)工作者或任何其他協(xié)議中工作。
CHACHA 的好處是,它們很容易測(cè)試。你發(fā)送動(dòng)作并期待對(duì)觀察者的特定調(diào)用作為回報(bào)。
列表項(xiàng)的 HTML 模板元素
HTML 模板是存在于 DOM 中的特殊元素,但不會(huì)被顯示。它們的目的是生成動(dòng)態(tài)元素。
當(dāng)我們使用 template 元素時(shí),我們可以避免在 JavaScript 中創(chuàng)建元素和填充它們的所有模板代碼。
下面將使用 template 為列表添加名稱:
<ul id="names">
<template>
<li><label class="name" /><span class="hljs-name"li>
<span class="hljs-name"template>
<span class="hljs-name"ul>
<script>
function addName(name) {
const list = document.querySelector('#names');
const item = list.querySelector('template').content.cloneNode(true).firstElementChild;
item.querySelector('label').innerText = name;
list.appendChild(item);
}
class="hljs-name"script>
通過使用列表項(xiàng)的 template 元素,我們可以在原始 HTML 中看到列表項(xiàng)——它不是用 JSX 或其他語言“渲染”的。你的 HTML 文件現(xiàn)在包含了應(yīng)用程序的所有 HTML——靜態(tài)部分是渲染的 DOM 的一部分,而動(dòng)態(tài)部分在模板中表達(dá),準(zhǔn)備在時(shí)機(jī)成熟時(shí)被克隆并追加到文檔中。
集大成者:TodoMVC
TodoMVC 是一個(gè) TODO 列表的應(yīng)用規(guī)范,用于展示不同的框架。TodoMVC 模板帶有現(xiàn)成的 HTML 和 CSS,幫助你專注于框架。
你可以在 GitHub 資源庫(kù)中使用這個(gè)結(jié)果,并且可以獲得完整的源代碼。
從規(guī)范派生的 CHACHA 開始
我們將從規(guī)范開始,并使用它來構(gòu)建 CHACHA 接口:
interface Task {
title: string;
completed: boolean;
}
interface TaskModelObserver {
onAdd(key: number, value: Task);
onUpdate(key: number, value: Task);
onRemove(key: number);
onCountChange(count: {active: number, completed: number});
}
interface TaskModel {
constructor(observer: TaskModelObserver);
createTask(task: Task): void;
updateTask(key: number, task: Task): void;
deleteTask(key: number): void;
clearCompleted(): void;
markAll(completed: boolean): void;
}
任務(wù)模型中的函數(shù)直接來自規(guī)范和用戶可以做的事情(清除已完成的任務(wù),將所有任務(wù)標(biāo)記為已完成或正在進(jìn)行,獲得正在進(jìn)行和已完成的計(jì)數(shù))。
請(qǐng)注意,它遵循 CHACHA 的準(zhǔn)則。
- 有兩個(gè)界面,一個(gè)是動(dòng)作的,一個(gè)是觀察的。
- 所有的參數(shù)類型都是基元或普通對(duì)象(很容易翻譯成 JSON)。
- 所有的函數(shù)都返回 void。
TodoMVC 的實(shí)現(xiàn)使用 localStorage 作為后端。
該模型非常簡(jiǎn)單,與關(guān)于 UI 框架的討論沒有多大關(guān)系。它在需要的時(shí)候保存到 localStorage,并在某些情況發(fā)生變化時(shí)向觀察者觸發(fā)回調(diào),這些變化可能是用戶操作的結(jié)果,也可能是模型第一次從 localStorage 加載的時(shí)候。
精簡(jiǎn)的、面向表單的 HTML
接下來,我將采用 TodoMVC 模板,并將其修改為面向表單的模板:表單的層次結(jié)構(gòu),輸入和輸出元素代表可以用 JavaScript 改變的數(shù)據(jù)。
我怎么知道某個(gè)東西是否需要成為表單元素?作為一個(gè)經(jīng)驗(yàn)法則,如果它與模型中的數(shù)據(jù)綁定,那么它就應(yīng)該是一個(gè)表單元素。
完整的 HTML 文件是可用的,但這里是其主要部分:
class="todoapp">
<header class="header">
todosclass="hljs-name"h1>
-
Web
+關(guān)注
關(guān)注
2文章
1265瀏覽量
69526 -
框架
+關(guān)注
關(guān)注
0文章
403瀏覽量
17510 -
編程
+關(guān)注
關(guān)注
88文章
3627瀏覽量
93809
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論