代码来源:https://codepen.io/dagger8224/pen/myeKgVQ

任务:实现“按钮点击 +1”计数器,对比不同框架的写法与特性,并给出选型建议。


目录


代码解读(逐框架)

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 + 轻指令
适配复杂度 组件化弱 过时生态 生态完善 生态最强 轻量、无构建亦可

注:上表依据本例的写法与常见范式总结。


技术观察与解读

  1. “状态在哪里”决定复杂度走向

    • jQuery:把 DOM 当真相源,最轻,但交互增多时难控。
    • Vue/React:数据为真相源,模板/JSX 由状态驱动,易规模化。
    • dagger.js:把“小状态”就地挂在元素作用域,天然就近,适合局部交互。
  2. 事件写法的表达力与可组合性

    • Vue/Angular/React:声明事件名 → 调函数。
    • dagger.js:+click="count++" 直接表达更新意图,减少样板(无需 methods / this.setState)。
  3. 引导方式与挂载点

    • AngularJS:ng-app / ng-controller
    • Vue:new Vue({ el })
    • React:ReactDOM.render()
    • dagger.js:元素上声明即可,不依赖全局挂载点,适合“就地增强”。
  4. 样板与可读性

    • 本例中,从多到少大致是:React ≥ AngularJS ≥ Vue > jQuery ≈ dagger.js。
    • 对“按钮 + 计数”这类微交互,dagger 的“一行式”复制扩散成本最低。
  5. 可规模化与生态

    • 组件通信、路由、状态管理、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感兴趣的话,请您点赞收藏、分享本系列文章,也欢迎留言或者私信作者提出问题和建议,您的关注是对我最大的支持和鼓励。感谢您的阅读,祝工作学习顺利!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐