使用原生JavaScript实现简易MVVM框架详解

作者:青柠时间:2026-10-22 11:51:03浏览:105

本文分享一个基于原生JavaScript实现的简易MVVM框架,代码仅300余行。框架支持属性绑定、复杂属性处理、自定义指令(如val、template)及事件监听。通过data-context绑定控制器,利用bind-和on-语法实现视图与模型的双向交互,适合用于理解前端响应式原理及扩展通用组件。

简易MVVM框架概述

此前多是在技术社区阅读文章并默默点赞,今日决定分享自己使用JavaScript编写的一个简易MVVM框架实现。

该框架最初仅具备自动事件绑定功能,后续参考了Vue、Knockout及Angular的实现思路,并结合个人在WPF开发中的经验,增加了属性绑定机制。经过整理与功能完善,完整代码已托管至码云:https://gitee.com/zlj_fy/Simple-MVVM。

以下简要介绍该框架的基本使用方法。


<form class="form-horizontal" role="form" data-context="TestController">
  <div class="form-group">
   <legend>Form title</legend>
  </div>
  <div class="form-group">
   <div class="col-sm-6 col-sm-offset-2">
    <input type="text" class="form-control" bind-val="age,format=format" style="margin:5px 0" />
    <input type="text" class="form-control" bind-val="desc" style="margin:5px 0" />
    <input type="range" min="10" max="300" bind-val="age" step="10" class="form-control" style="margin:5px 0" />
    <input type="button" class="btn btn-primary" value="更新" style="margin:5px 0" on-click="update" />
   </div>
  </div>
 </form>
 <script>
  var TestController = {
   data: {
    name: 'xiaoming',
    age: 3,
    desc: function() {
            return this.name + ' likes looking little movie. he should take care of his body' 
    }
   },
   format: function(val) {
    return val + '岁'
   },
   update: function() {
    this.name = 'this is a test'
    this.age = 18
   }
  }
  $('body').controller()
 </script>

控制器绑定与作用域

首先需定义一个控制器,其形式可以是JSON对象或函数。在顶层HTML元素上设置data-context属性为控制器名称,即可将该控制器绑定至该节点及其所有子元素。若子元素中存在嵌套的Controller,则其子元素的作用域将指向对应的子控制器。

属性监控与复杂属性处理

1. 监控属性及复杂属性处理

所有数据属性必须定义在data节点下。若某属性被定义为函数,则视为复杂属性(如desc示例)。复杂属性默认只读,若尝试直接重新赋值,系统将抛出错误提示。

HTML元素中的绑定格式为“{属性名, format=[控制器方法]}”。属性名支持嵌套访问(如a.b),但不支持表达式,因复杂属性已能替代表达式功能。当前限制在于业务逻辑复杂时可能导致大量复杂属性定义。属性名右侧为可选参数,目前仅支持format,即用于转换属性在HTML中显示格式的方法。

指令系统扩展机制

2. 指令系统扩展

指令绑定语法采用bind-{指令}形式。目前已实现val、attr、text、html及template指令。前四项均为对jQuery方法的简单封装,而template指令依赖jquery-tmpl插件。如需扩展更多指令,只需实现init方法(接收当前observer参数)及update方法(参数包括jQuery元素、最新值及当前控制器实例)。扩展已有指令将默认覆盖原有实现。具体示例如下:


$.controller.addDirective("val", {
  init: function (observer) {
   if (observer.$ele.is('input,select')) {
    //监听onchange事件
    observer.$ele.on('input propertychange', function () {
     var newVal = $(this).val()
     observer.writeValue(newVal)
    })
   }
  },
  update: function ($ele, newVal, controller) {
   $ele.val && $ele.val(newVal)
  }
 })

事件绑定与生命周期钩子

3. 事件绑定机制

事件绑定语法为on-{事件}=“{控制器方法},type=on/one”。控制器方法右侧同样支持可选参数,目前仅支持绑定类型on或one,默认为on。控制器方法接收两个参数:一为可在对应事件元素上设置的初始参数,二为event事件对象。


<button type="button" class="btn btn-primary" data-page="1" on-click="refesh">查询</button>

4. 方法访问方式

在控制器内部,直接通过this.属性名即可访问data节点下的对应属性。

5. 生命周期钩子

框架提供了init和created两个钩子。init在监听所有属性之后、DOM编译之前执行,可用于初始化参数;created则在DOM元素编译完成后触发。

控制器默认实现了extend继承方法,用于继承其他控制器,且必须在init方法中调用。用户也可自行通过原型链继承方式实现。示例如下:


init: function () {
    this.extend(PageController)
   },
   created: function () {
    //TODO
   },

通用组件扩展与最佳实践

6. 通用组件扩展建议

在项目开发中,通常有一套公用组件库。可通过如下方式扩展,将对应组件挂载至所有控制器实例下,从而在任意方法中直接调用,例如this.http.post()。

建议尽量统一将回调方法的作用域指向控制器,以避免开发过程中频繁出现作用域引用问题。


$.controller.extend({
   utils: utils,
   notify: $.notify,
   modal: $.modal,
   http: $.http,
   alert: $.alert
  })

7. 原理及代码分析(待续...)

整个JavaScript代码量仅300余行,实现较为简单,部分场景尚未考虑,部分功能计划实现但未完成。目前框架不支持数组变化检测及局部DOM更新。

以上关于使用JavaScript实现简易MVVM框架的示例内容即为全部分享,希望能对读者有所参考,也欢迎大家支持本站。

作者最新文章