在knockoutjs 上自己实现的flux(实例讲解)


Posted in Javascript onDecember 18, 2017

在knockoutjs 上实现 Flux 单向数据流 状态机,主要解决多个组件之间对数据的耦合问题。

一、其实简单

flux的设计理念和实现方案,很大程度上人借鉴和参考了Vuex的实现,只是简化了某些过程,数据流向图如下:

在knockoutjs 上自己实现的flux(实例讲解)

从上图,中以看出数据的改变是单向循环的。我想这就是Flux理念的核心所在吧。Vuex中对Action规范为Action和Mutation,由action去触发Mutation,action是可以异步的,而Mutation则是同步更新。而我在设计ko的Flux时,去掉了Mutation这个环节,是因为我理解为,异步的请求一般情况下都是与api接口有关系,这块内容存在极大的变化性,应该从业务或项目构架上做一层区分。

二、如果使用

当然,flux只是针对knockoutjs的,所以你使用之前必须引入knockoutjs。flux主要的方法和对象

2.1 静态方法

方法 说明
flux.use 在require模式下,将flux与ko做关联的方法,当然他必须先与createStore方法调用。
flux.createStore 创建一个store(状态器)实例,当然此方法是有返回值,他的返回值可以调用register方法注册到指定的域上,但第一次调用此方法时是创建rootStore(根状态器),他不允许被注册到域的。

2.1.1 flux.createStore参数格式

参数名称 说明
state 状态器相关状态数据
actions 更改state上的状态方法,方法的第一个参数为state,第二参数开始则为传入的相关内容
getters 获取state上的相关状态数据,当然返回是一个ko监控对象。

2.2 实例方法

createStore方法的执行,会在ko实例上增加$store属性,此属性是状态器的实例对象,在任何位置都可以调用他的dispatch来触发事件。

方法 说明
register 创建和注册一个状态域,域与域之间是相互独立存储的,域之间action或get名称是可以重复的
unRegister 移除一个状态域
dispatch 根据actionName调用指定的action,无返回值
get 根据getName调用指定的get,有返回值

三、简单的使用

本示例定义了四个ko绑定区域,分别是:app1, app2, app3, app4。实现app4中对name的改变自动影响到app1,而app3对列表的改变自动影响到app2。

在knockoutjs 上自己实现的flux(实例讲解)

3.1 定义vm并初始化store

function ViewModel(){
 this.list = ko.observableArray();
 this.name = ko.observable('无名氏');
 this.count = ko.computed(function(){
  //必须用this,这个时候ko.$store还没创建完成,应该ko.computed创建时会执行一次此处
  //如果是子vm依赖主vm,还是可以用ko.$store的
  return this.list().length + '个数'; //需要对监控对象求值,否则computed不能有效
 },this);
}
var fullVm = new ViewModel(); 
var index = 1;
fullVm.vf={
 add: function(){
  ko.$store.dispatch('addClass',{title: 'title' + (index++)});
 }
}
var opt = {
 state: {
  class: fullVm
 },
 actions:{
  "setName":function(state, name){
   state.class.name(name);
  },
  "addClass":function(state, classInfo){
   state.class.list.push(classInfo);
  }
 },
 getters:{
  "getName":function(state){
   return state.class.name;
  }
 }
}
flux.createStore(opt);

根据上述代码,首先定义了ViewModel的一个类,并创建了一个fullVm的一个实例,然后直接在fullVm实例上增加了add方法。

opt的state引用的是fullVm,其中还配置了actions和getters相关对象,然后调用flux.createStore(opt)方法。创建一个store,并关联到ko.$store对象上。

3.2 与视图绑定

html代码:

<div id="app1">
 app1:
 <span data-bind="text:ko.$store.get('getName')"></span>
</div>
<div id="app4">
 app4:
 <input type="text" data-bind="value:name" />
 <button type="text" data-bind="click:changeName" >改变名字</button>
 <span data-bind="text:ko.$store.state.class.name"></span>
</div>
<hr>
<div id="app2">
 app2:
 <ul data-bind="foreach:list" >
  <li data-bind="text:title" ></li>
 </ul>
</div>
<div id="app3">
 app3: 
 <button type="button" data-bind="click:vf.add" >添加</button>
 <span data-bind="text:count"></span>
</div>

js代码:

var app1 = ko.applyBindings(fullVm, document.getElementById("app1"));
var app2 = ko.applyBindings(fullVm, document.getElementById("app2"));
var app3 = ko.applyBindings(fullVm, document.getElementById("app3"));
//测试两个vm之间的依赖 解藕
var app4 = ko.applyBindings({
 name: ko.observable(),
 changeName:function(data,event){
  ko.$store.dispatch('setName', this.name());
 }
}, document.getElementById("app4"));

四、域的实例

html代码:

<div id="app1">
 <span data-bind="text:name" ></span>
</div>
<div id="app2">
 <span data-bind="text:name"></span>
 <span data-bind="text:full"></span>
 <button type="button" data-bind="click:changeName" >换名</button>
</div>

js代码:

function rootViewModel(){
 this.name = ko.observable('root'); 
}
var rVM = new rootViewModel();
flux.createStore({ state: rVM}); //创建root状态器

var treeNode={
 name: ko.observable('node'),
 changeName:function(){
  ko.$store.areas.treeNode.state.name('新名字');
 },
 full: ko.computed(function(){
  //computed的职责:1. 监控其他对象属性的变化,而影响自身对象(flux解决);2. 合并自身对象的几个属性(在function下,有this可解)
  //不能通过ko.$store访问对象本身,因为首次对象本身还没初始化好
  var store = ko.$store;
  //(store.areas.treeNode? store.areas.treeNode.state.name() : '') 这样也是不行,因为解决第一次通不过,后面肯定不行
  return store.state.name();
 })
}

ko.$store.register('treeNode', flux.createStore({ state: treeNode})); //创建子状态机
var app1 = ko.applyBindings(rVM, document.getElementById("app1"));
var app2 = ko.applyBindings(treeNode, document.getElementById("app2"));

五、其他

当然模块化的引用,也是支持。具体实例细节可参考test中的测试示例。

项目的git地址:https://gitee.com/ko-plugins/flux.git,欢迎大家指正和提出宝贵的意见。

以上这篇在knockoutjs 上自己实现的flux(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js操作select控件的几种方法
Jun 02 Javascript
利用js正则表达式验证手机号,email地址,邮政编码
Jan 23 Javascript
JS取request值以及自动执行使用示例
Feb 24 Javascript
js获取当前页面的url网址信息
Jun 12 Javascript
2014年最火的Node.JS后端框架推荐
Oct 27 Javascript
javascript模块化简单解析
Apr 07 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
Mar 09 Javascript
Javascript继承机制详解
May 30 Javascript
详解vue模拟加载更多功能(数据追加)
Jun 23 Javascript
Easyui ueditor 整合解决不能编辑的问题(推荐)
Jun 25 Javascript
浅谈jquery中ajax跨域提交的时候会有2次请求的问题
Nov 10 jQuery
vue中 this.$set的使用详解
Nov 17 Vue.js
vue的无缝滚动组件vue-seamless-scroll实例
Dec 18 #Javascript
分析JavaScript数组操作难点
Dec 18 #Javascript
微信小程序基于本地缓存实现点赞功能的方法
Dec 18 #Javascript
JavaScript模块详解
Dec 18 #Javascript
webpack打包js文件及部署的实现方法
Dec 18 #Javascript
react+redux的升级版todoList的实现
Dec 18 #Javascript
总结js中的一些兼容性易错的问题
Dec 18 #Javascript
You might like
收音机怀古---春雷3P7图片欣赏
2021/03/02 无线电
php disk_free_space 返回目录可用空间
2010/05/10 PHP
PHP中几种常见的超时处理全面总结
2012/09/11 PHP
php笔记之:文章中图片处理的使用
2013/04/26 PHP
PHP基于方差和标准差计算学生成绩的稳定性示例
2017/07/04 PHP
纯js实现的论坛常用的运行代码的效果
2008/07/15 Javascript
javascript 写类方式之六
2009/07/05 Javascript
事件绑定之小测试  onclick &amp;&amp; addEventListener
2011/07/31 Javascript
关于Javascript加载执行优化的研究报告
2014/12/16 Javascript
jQuery的promise与deferred对象在异步回调中的作用
2016/05/03 Javascript
jQuery flip插件实现的翻牌效果示例【附demo源码下载】
2016/09/20 Javascript
jquery实现图片平滑滚动详解
2017/03/22 jQuery
Javascript ES6中数据类型Symbol的使用详解
2017/05/02 Javascript
Angular中管道操作符(|)的使用方法
2017/12/15 Javascript
通过seajs实现JavaScript的模块开发及按模块加载
2019/06/06 Javascript
js如何实现元素曝光上报
2019/08/07 Javascript
微信小程序中的video视频实现 自定义播放按钮、封面图、视频封面上文案
2020/01/02 Javascript
Node使用Nodemailer发送邮件的方法实现
2020/02/24 Javascript
[01:11]辉夜杯战队访谈宣传片—CDEC.Y
2015/12/26 DOTA
[00:10]DOTA2全国高校联赛 以DOTA2会友
2018/05/30 DOTA
Python urlopen()函数 示例分享
2014/06/12 Python
Python找出9个连续的空闲端口
2016/02/01 Python
Python的净值数据接口调用示例分享
2016/03/15 Python
深入浅析python中的多进程、多线程、协程
2016/06/22 Python
python实现关键词提取的示例讲解
2018/04/28 Python
python数据结构之线性表的顺序存储结构
2018/09/28 Python
Python实现元素等待代码实例
2019/11/11 Python
python 视频逐帧保存为图片的完整实例
2019/12/10 Python
pytorch数据预处理错误的解决
2020/02/20 Python
Python调用接口合并Excel表代码实例
2020/03/31 Python
解决python Jupyter不能导入外部包问题
2020/04/15 Python
澳洲在线厨具商店:Kitchen Style
2018/05/05 全球购物
遗产继承公证书
2014/04/09 职场文书
合同纠纷调解书
2015/05/20 职场文书
python接口测试返回数据为字典取值方式
2022/02/12 Python
Redis分布式锁的7种实现
2022/04/01 Redis