代碼來源:https://codepen.io/dagger8224/pen/myeKgVQ
任務:實現“按鈕點擊 +1”計數器,對比不同框架的寫法與特性,并給出選型建議。
目錄
- 代碼解讀(逐框架)
- jQuery(命令式 DOM)
- AngularJS(作用域 + 指令)
- Vue(響應式 + 模板指令)
- React(狀態 + 渲染函數)
- dagger.js(原生 DOM 上的聲明式指令,零樣板)
- 方案對照(要點一覽)
- 技術觀察與解讀
- 什么時候選誰?
- 附:關鍵代碼片段
代碼解讀(逐框架)
jQuery(命令式 DOM)
HTML 一個按鈕 #jquery
,JS 里手動掛事件并改 innerHTML
,用 - 0
把字符串轉數值:
$('#jquery').on('click', e => e.target.innerHTML = e.target.innerHTML - 0 + 1);
這完全把 DOM 當“狀態源”,簡單直接,但沒有數據層,后續可維護性與可組合性較弱。
AngularJS(作用域 + 指令)
ng-app="ngApp" ng-controller="buttonController"
聲明應用與控制器,$scope.count
放狀態,ng-click
觸發 handleClick()
:
<div ng-app="ngApp" ng-controller="buttonController"><button ng-click="handleClick()">{{ count }}</button>
</div>
<script>
angular.module('ngApp', [])
.controller('buttonController', function($scope){$scope.count = 0;$scope.handleClick = function(){ $scope.count++; };
});
</script>
模板 {{ count }}
與 $scope
綁定,靠 digest 循環驅動更新。對這個微例子而言,樣板代碼相對偏多。
Vue(響應式 + 模板指令)
數據在 data
,事件在 methods
,點擊只改數據、視圖自動更新:
<div id="vue"><button v-on:click="handleClick">{{ count }}</button>
</div>
<script>
new Vue({el:'#vue',data:{ count:0 },methods:{ handleClick(){ this.count++; } }
});
</script>
結構清晰,體量中等。
React(狀態 + 渲染函數)
使用 class 組件:
class ReactButton extends React.Component {state = { count: 0 };handleClick = () => this.setState({ count: this.state.count + 1 });render(){return <button onClick={this.handleClick}>{this.state.count}</button>;}
}
ReactDOM.render(<ReactButton/>, document.getElementById('react'));
狀態在 this.state
,用 setState
觸發重渲染。樣板代碼偏多(尤其在無需組件化時),但在大規模組件樹、生態配套下優勢明顯。
dagger.js(原生 DOM 上的聲明式指令,零樣板)
一行 HTML 解決:
<button id="dagger" dg-cloak +load="{ count: 0 }" +click="count++">${ count }</button>
+load
初始化局部作用域(當前宿主元素)。${ count }
插值。+click
直接寫表達式增量。dg-cloak
防止閃爍。
無需單獨 JS 模塊與掛載點,狀態與視圖強“同位(colocation)”。
方案對照(要點一覽)
維度 | jQuery | AngularJS | Vue | React | dagger.js |
---|---|---|---|---|---|
狀態歸屬 | DOM 即狀態 | $scope | data | this.state | 元素局部作用域(+load ) |
事件綁定 | 代碼里手綁 | ng-click | v-on:click | onClick | +click (表達式) |
視圖更新 | 手改 DOM | digest | 響應式 | 重渲染 | 直接驅動 DOM(無 VDOM) |
樣板/文件數 | 最少,但可維護性弱 | 偏多 | 適中 | 偏多 | 極少(常一行搞定) |
學習/心智 | 低,命令式 | 指令+作用域 | 模板+響應式 | 組件/狀態/JSX | 原生 DOM + 輕指令 |
適配復雜度 | 組件化弱 | 過時生態 | 生態完善 | 生態最強 | 輕量、無構建亦可 |
注:上表依據本例的寫法與常見范式總結。
技術觀察與解讀
-
“狀態在哪里”決定復雜度走向
- jQuery:把 DOM 當真相源,最輕,但交互增多時難控。
- Vue/React:數據為真相源,模板/JSX 由狀態驅動,易規模化。
- dagger.js:把“小狀態”就地掛在元素作用域,天然就近,適合局部交互。
-
事件寫法的表達力與可組合性
- Vue/Angular/React:聲明事件名 → 調函數。
- dagger.js:
+click="count++"
直接表達更新意圖,減少樣板(無需methods
/this.setState
)。
-
引導方式與掛載點
- AngularJS:
ng-app
/ng-controller
。 - Vue:
new Vue({ el })
。 - React:
ReactDOM.render()
。 - dagger.js:元素上聲明即可,不依賴全局掛載點,適合“就地增強”。
- AngularJS:
-
樣板與可讀性
- 本例中,從多到少大致是:React ≥ AngularJS ≥ Vue > jQuery ≈ dagger.js。
- 對“按鈕 + 計數”這類微交互,dagger 的“一行式”復制擴散成本最低。
-
可規模化與生態
- 組件通信、路由、狀態管理、SSR、工程化鏈路:React/Vue 生態占優。
- dagger.js:無需構建的輕交互、內嵌到現有頁面、分散微部件;與 jQuery 滲透場景重疊,但更現代、聲明式。
什么時候選誰?
- 給現有頁面補幾個小交互/小掛件:首選 dagger.js(或其他輕量范式),因為“就地聲明 + 無樣板”。
- 中大型單頁應用:React / Vue 更穩,生態豐富、協作友好。
- 快速腳本式改動:jQuery 可用,但謹慎可維護性與狀態一致性。
- AngularJS 存量:按存量維護;新項目不建議再啟用 AngularJS。
附:關鍵代碼片段
以下為本示例中各技術棧的最小可用版本,便于復制到自己的實驗頁面。
jQuery
<button id="jquery">0</button>
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<script>
$('#jquery').on('click', e => e.target.innerHTML = e.target.innerHTML - 0 + 1);
</script>
AngularJS
<div ng-app="ngApp" ng-controller="buttonController"><button ng-click="handleClick()">{{ count }}</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script>
angular.module('ngApp', [])
.controller('buttonController', function($scope){$scope.count = 0;$scope.handleClick = function(){ $scope.count++; };
});
</script>
Vue
<div id="vue"><button v-on:click="handleClick">{{ count }}</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
<script>
new Vue({el:'#vue',data:{ count:0 },methods:{ handleClick(){ this.count++; } }
});
</script>
React
<div id="react"></div>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script type="text/babel">
class ReactButton extends React.Component {state = { count: 0 };handleClick = () => this.setState({ count: this.state.count + 1 });render(){return <button onClick={this.handleClick}>{this.state.count}</button>;}
}
ReactDOM.render(<ReactButton/>, document.getElementById('react'));
</script>
dagger.js
<script type="module" crossorigin="anonymous" src="https://assets.codepen.io/5782383/dagger-1.0.0-RC.js" defer></script>
<button id="dagger" dg-cloak +load="{ count: 0 }" +click="count++">${ count }</button>
本文內容就到這里,后續文章將為大家帶來更多案例和講解。
如果對dagger.js感興趣的話,請您點贊收藏、分享本系列文章,也歡迎留言或者私信作者提出問題和建議,您的關注是對我最大的支持和鼓勵。感謝您的閱讀,祝工作學習順利!