“Add Tags” 技術方案并行對比:React Hooks vs dagger.js(含核心 JS 代碼)
源碼:
- React Hooks:https://codepen.io/prvnbist/pen/jJzROe?editors=1010
- dagger.js:https://codepen.io/dagger8224/pen/ZErjzwm
一、對比總覽(表格)
維度 | React Hooks 實現(prvnbist) | dagger.js 實現(dagger8224) | 結論 |
---|---|---|---|
框架/依賴 | 依賴 React/ReactDOM + Babel/JSX;ReactDOM.render 掛載 | 原生 DOM + 指令(+load /*each /*value#trim /+click /+keyup ),零構建可跑 | dagger 依賴更輕;React 生態更全 |
狀態管理 | useState (不可變更新) | 作用域對象可變更新(push /splice ) | React 可預測性強;dagger 上手直觀 |
事件/輸入 | onKeyUp 手寫回調讀取/清空輸入 | *value#trim 雙向綁定,+keyup#every:-Enter 聲明式觸發 | dagger 更少樣板 |
列表渲染/刪除 | tags.map(...) + onClick | *each="tags" + +click="removeTags(...)" | 均直觀;dagger 更貼 HTML |
對外通信 | props.selectedTags([...]) 向父級冒泡 | 示例未展示(可拓展自定義事件/全局 store) | React 更現成 |
A11y | 刪除控件是 span “x”,無按鈕角色/ARIA(兩邊均是) | 同左 | 建議兩者都改 <button aria-label="Remove tag"> |
性能(本例) | VDOM diff 開銷極小 | 直達 DOM 綁定 | 小組件差異可忽略 |
適用場景 | 工程化/組件生態/團隊協作 | 免構建/輕量嵌入/快速原型 | 視項目體量取舍 |
二、代碼量差異(粗略非空行統計)
注:僅為量級參考;CSS 兩邊大致一致。
面板 | React Hooks | dagger.js |
---|---|---|
HTML | ~1 行(<div id="root"> ) | ~10 行(含指令模板) |
JS | ~33 行(TagsInput + App + render ) | ~12 行(loading /removeTags /addTags ) |
CSS | ~80+ 行(兩者近似) | ~80+ 行 |
合計(HTML+JS) | ~34 行 | ~22 行 |
結論:dagger.js 顯著減少 JS 體量,把交互“下沉”到 HTML 指令;React JS 更多但 HTML 更薄,符合組件化/狀態提升的常規模式。
三、核心 JS 代碼對照
1) React Hooks(核心 JS)
const TagsInput = props => {const [tags, setTags] = React.useState(props.tags);const removeTags = indexToRemove => {setTags([...tags.filter((_, index) => index !== indexToRemove)]);};const addTags = event => {if (event.target.value !== "") {setTags([...tags, event.target.value]);props.selectedTags([...tags, event.target.value]);event.target.value = "";}};return (<div className="tags-input"><ul id="tags">{tags.map((tag, index) => (<li key={index} className="tag"><span className='tag-title'>{tag}</span><span className='tag-close-icon'onClick={() => removeTags(index)}>x</span></li>))}</ul><inputtype="text"onKeyUp={event => event.key === "Enter" ? addTags(event) : null}placeholder="Press enter to add tags"/></div>);
};
const App = () => {const selectedTags = tags => {console.log(tags);};return (<div className="App"><TagsInput selectedTags={selectedTags} tags={['Nodejs', 'MongoDB']}/></div>);
};
ReactDOM.render(<App />, document.getElementById("root"));
2) dagger.js(核心 JS)
const loading = () => ({tag: '',tags: ['Nodejs', 'MongoDB']
});
const removeTags = (index, tags) => tags.splice(index, 1);
const addTags = $scope => {const { tag, tags } = $scope;if (tag) {tags.push(tag);$scope.tag = '';}
};
dagger 對應模板(片段),可見通過指令表達列表、事件與雙向綁定:
<div dg-cloak class="App" +load="loading()"><div class="tags-input"><ul id="tags"><li class="tag" *each="tags"><span class='tag-title'>${ item }</span><span class='tag-close-icon' +click="removeTags(index, tags)">x</span></li></ul><input type="text" placeholder="Press enter to add tags"*value#trim="tag" +keyup#every:-Enter="addTags($scope)"></div>
</div>
四、與代碼對應的實現分析
A. 初始化與掛載
- React:
const [tags, setTags] = useState(props.tags);
為局部狀態;通過ReactDOM.render(<App/>, #root)
掛載。組件化邊界清晰,便于復用與組合。 - dagger:
+load="loading()"
在容器上注入初始作用域(tag
/tags
),無需顯式渲染入口,適合在任意靜態頁“就地”增強。
B. 輸入與校驗
- React:
addTags(event)
里手動讀取/清空event.target.value
;默認不trim
,可在函數中補充校驗與去重。 - dagger:
*value#trim="tag"
天然裁剪空白,結合+keyup#every:-Enter
讓“回車新增”無需手寫鍵值判斷。
C. 列表渲染與刪除
- React:
tags.map(...)
渲染項,onClick={() => removeTags(index)}
刪除。不可變更新(filter
)便于可預測渲染、狀態回溯。 - dagger:
*each="tags"
迭代;+click="removeTags(index, tags)"
直接調用,常配合可變更新(splice
)寫法簡潔。
D. 對外通信
- React:
props.selectedTags([...])
將內部變更上報給父組件或外層應用(常見于表單控件封裝)。 - dagger:示例未展示;可通過自定義事件(
dispatchEvent
)或外層監聽指令來完成數據冒泡。
E. 可訪問性(A11y)
- 兩邊刪除控件均為
span
,建議替換為:
并配合鍵盤支持(Enter/Space)和更明確的焦點樣式。<button type="button" class="tag-close-icon" aria-label="Remove tag">x</button>
五、改進建議(兩邊通用)
- 輸入規則:去重、最大標簽數、禁止全空白;支持粘貼多標簽(按逗號/空格分割)。
- 錯誤反饋:同名標簽時給出可視化提示(如 shake 動畫/輔助文本)。
- 測試:React 側可配合 Testing Library;dagger 側可通過 DOM 測試/端到端測試保障交互。
- 樣式與主題:抽離 tokens/vars,支持暗色模式與尺寸變體。
六、選型參考
- 需要工程化、強生態、多人協作 —— 傾向 React:組件化邊界清晰、工具鏈與第三方庫成熟。
- 追求零構建、輕量嵌入、快速上線 —— 傾向 dagger:指令式綁定 + 原生 DOM,代碼量更小,上手極快。
本文內容就到這里,后續文章將為大家帶來更多案例和講解。
如果對dagger.js感興趣的話,請您點贊收藏、分享本系列文章,也歡迎留言或者私信作者提出問題和建議,您的關注是對我最大的支持和鼓勵。感謝您的閱讀,祝工作學習順利!