摘要: ## 简述 React 是一个视图层的 UI 框架, 以常见的 MVC 来讲 React 仅是 View, 而我们在编写应用时, 通常还需要关注更加重要的 model, 对于 React 来讲, 我们常常需要一个状态管理库然而, 目前大多数针对 React 的状态管理库都是强依赖过多的侵入本应该独立的业务模型中, 导致业务逻辑对应的代码并不能轻易在其它地方重用, 往往这些框架还具有强排它
简述
React 是一个视图层的 UI 框架, 以常见的 MVC 来讲 React 仅是 View, 而我们在编写应用时, 通常还需要关注更加重要的 model, 对于 React 来讲, 我们常常需要一个状态管理库然而, 目前大多数针对 React 的状态管理库都是强依赖过多的侵入本应该独立的业务模型中, 导致业务逻辑对应的代码并不能轻易在其它地方重用, 往往这些框架还具有强排它性, 但是业务模型应该是没有过多依赖, 应该是无关框架的, 它应该随时可以被用在任何合适的 JavaScript 环境中, 使用 mota 你可以用原生的普通的 JavaScript 代码编写你的业务模型, 并让你的业务模型在不同框架不同运行环境下重用更为容易
mota 是一个主张面向对象的支持双向绑定的 React 应用辅助库, 基于 mota 你可以用纯 JavaScript 为应用编写完全面向对象的业务模型, 并轻易的将业务模型关联到 React 应用中
安装
通过 npm 安装, 如下
或通过 dawn 脚手脚加创建工程, 如下
需要先安装 dawn
工程结构
一个 mota 工程的通常结构如下
编写业务模型
在 mota 中模型可以是由一个 class 或普通的的 Object, 整个业务模型层会由多个 class 和多个 Object 组成, 而编写模型所需要的知识就是 JavaScript 固有的面向对象编程的知识
如下示例通过编写一个名为 User 的 class 创建了一个用户模型
也可以是一个 Object, 通常这个模型需要是单例时, 可采用这种方式, 如下
在业务模型编写完成后, 可以通过 @model 将某个类或类的实例关联到指定组件, 关联后便可以在组件中使用 this.model 访问模型的成员变量或方法了, mota 还会自动收集组件依赖, 在组件依赖的模型数据发生变化时, 自动响应变化并驱动组件重新渲染, 如下
值得注意的是, 在使用 @model 时如果传入的是一个 class 最终每个组件实例都会自动创建一个 独立的实例, 这样带来的好处是当一个页面中有同一个组件的多个实例时, 不会相互影响
属性映射
在 React 中通常会将应用折分为多个组件重用它们, 并在用时传递给它属性, mota 提供了将组件属性映射到模型数据的能力, 基于 model 编程会让视图层更单一, 专注于 UI 的呈现,, 如下
上边的代码通过 mapping 将 Demo 这个组件的 value 属性映射到了 model.value 上, 在组件的属性 value 发生变化时, 会自动同步到 model.value 中
通过一个 map 进行映射, 还可以让组件属性和模型的成员使用不同名称, 如下:
上边的代码, 将组件 demo 的 content 属性映射到了 model.value 上
自执行函数
mota 中提供了一个 autorun 函数, 可用于装饰 React 组件的成员方法, 被装饰的成员方法将会在组件挂载后自动执行一次, mota 将收集方法中依赖的模型数据, 在依赖的模型数据发生变化时会自动重新执行对应的组件方法
示例
上边的示例代码中, 组件在被挂载后将会自动执行 test 方法, 同时 mota 会发现方法中依赖了 model.name, 那么, 在 model.name 发生变化时, 就会重新执行 test 方法
监听模型变化
mota 中提供了一个 watch 函数, 可用于装饰 React 组件的成员方法, watch 可以指定要观察的模型数据, 在模型数据发变化时, 就会自动执行被装饰的组件方法, watch 还可以像 autorun 一样自动执行一次, 但它和 autorun 还是不尽相同, 主要有如下区别
1.autorun 会自动收集依赖, 而 watch 不会关心组件方法中有何依赖, 需要手动指定依赖的模型数据
2.watch 默认不会自动执行, 需显式的指定立即执行参数为 true, 才会自动执行首次
3.autorun 依赖的是模型数据本身, 而 watch 依赖的是计算函数每次的计算结果
示例
上边的代码, 通过 watch 装饰了 test 方法, 并指定了观察的模型数据 model.name, 那么每当 model.name 发生变化时, 都会打印 name 发生了变化.
watch 是否重新执行, 取决于 watch 的作为第一个参数传给它的计算函数的计算结果, 每当依赖的模型数据发生变化时 watch 都会重执行计算函数, 当计算结果有变化时, 才会执行被装饰的组件方法, 示例
有时, 我们希望 watch 能首先自动执行一次, 那么可通过向第二个参数传一个 true 声明这个 watch 要自动执行一次
上边的 test 方法, 将会在组件挂载之后自动执行, 之后在 model.name 发生变化时也将自动重新执行
数据绑定
基本用法
不要惊诧, 就是双向绑定 mota 主张面向对象, 同样也不排斥双向绑定, 使用 mota 能够实现类似 ng 或 vue 的绑定效果还是前边小节中的模型, 我们来稍微改动一下组件的代码
其中的关键就是 @binding, 使用 @binding 后, 组件便具备了双向绑定的能力, 在 jsx 中便可以通过名为 data-bind 的自定义 attribute 进行绑定了, data-bind 的值是一个绑定表达式字符串, 绑定表达式执行的 scope 是 model 而不是 this, 也就是只能与 模型的成员 进行绑定
会有一种情况是当要绑定的数据是一个循环变量时, 绑定表达式写起会较麻烦也稍显长, 比如
因为绑定表达式的执行 scope 默认是 this.model, 以及表达式是个字符串, 看一下 userList[${index}].selected 这并不友好, 为此 mota 还提供了一个名为 data-scope 的 attribute, 通过它能改变要绑定的 scope, 参考如下示例
通过 data-scope 将 input 的绑定上下文对象声明为当前循环变量 user, 这样就可以用 data-bind 直接绑定到对应 user 的属性上了
原生表单控件
所有的原生表单控件, 比如普通 inputcheckboxradiotextareaselect 都可以直接进行绑定其中, 普通 input 和 textrea 比较简单, 将一个字符类型的模型数据与控件绑定就行了, 而对于 checkbox 和 radio 有多种不同的绑定形式
将 checkbox 或 radio 绑定到一个 boolean 值, 此时会将 checkbox 或 radio 的 checked 属性和模型数据建立绑定, checked 反应了 boolean 变量的值, 参考如下示例
如上示例通过 this.model.selected 就能拿到当前 checkbox 或 radio 的选中状态
将 checkbox 绑定到一个数组, 通常是多个 checkbox 绑定同一个数组变量上, 此时和数据建立绑定的是 checkbox 的 value, 数据中会包含当前选中的 checkbox 的 value, 如下
如上示例, 通过 this.selected 就能知道当前有哪些 checkbox 被选中了, 并拿到所有选中的 value
将多个 radio 绑定我到一个字符类型的变量, 此时和数据建立绑定的是 raido 的 value, 因为 radio 是单选的, 所以对应的数据是当前选中的 radio 的 value, 如下
通过 this.model.selected 就能拿到当前选中的 radio 的 value
自定义组件
但是对于一些组件库中的部分表单组件不能直接绑定, 因为 mota 并没有什么依据可以判断这是一个什么组件所以 mota 提供了一个名为 bindable 的函数, 用将任意组件包装成可绑定组件
bindable 有两种个参数, 用于分别指定原始组件和包装选项
关建是 bindable 需要的 opts, 通过 opts 我们可以造诉 mota 如何绑定这个组件, opts 中有两个重要的成员, 它的结构如下
所以, 我们可以这样包装一个自定义文本输入框
对这种 value 不需要转换, change 能通过 event 或 event.target.value 拿到值的组件, 通过如上的代码就能完成包装了
对于有 onChange 和 value 的这类文本输入组件, 因为 opts 的默认值就是
所以, 可以更简单, 这样就行,
而对于 checkbox 和 radio 来讲, 如上边讲到的它根据不同的数据型有不同的绑定形式, 这就需要指定处理函数了, 如下
通过 prop 的第二个值, 能指定属性处理函数, event 的第二个值能指取事件处理函数, 处理函数的 ctx 是个特殊的对象
1.ctx.getValue 能获取当前绑定的模型数据
2.ctx.setValue 能设置当前绑定的模型数据
上边是 radio 的配置, 首先, 在属性处理函数中通过绑定的模型数据的类型决定 checked 最终的状态是什么, 并在函数中返回再次, 在事件处理函数中通过绑定的模型数据的类型决定将什么值回写到模型中
通过属性处理函数和事件处理函数几乎就能将任意的自定义组件转换为可绑定组件了
另外, 对于常见的 CheckBox 和 Radio 类型的组件 mota 也提供了内建的 opts 配置支持, 如果一个自定义组件拥有和原生 checkbox 一致的属性和事件模型, 那边可以直接用简单的方式去包装, 如下
来源: http://www.jianshu.com/p/61f62ab08320