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

一、其实简单

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

从上图,中以看出数据的改变是单向循环的。我想这就是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。

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"));

其实很简单,首先创建rVM(也就是根状态器),然后再调用根状态器上的register方法注册一个子状态器(也就是域)。ko.$store === rVM,也就是说ko.$store就是根状态器。

五、其他

  1. 当然模块化的引用,也是支持。具体实例细节可参考test中的测试示例。
  2. 项目的git地址:https://gitee.com/ko-plugins/flux.git欢迎大家指正和提出宝贵的意见

knockoutjs 上自己实现的flux的更多相关文章

  1. 第3章 从Flux到Redux

    第3章 从Flux到Redux 3.1 Flux 单向数据流,React是用来替换Jquery的,Flux是以替换Backbone.js.Ember.js等MVC框架为主的. actionTypes. ...

  2. 安全增强 Linux (SELinux) 剖析

    架构和实现 Linux® 一直被认为是最安全的操作系统之一,但是通过引入安全增强 Linux(Security-Enhanced Linux,SELinux),National Security Ag ...

  3. Reactor 3 学习笔记(2)

    接上篇继续学习各种方法: 4.9.reduce/reduceWith @Test public void reduceTest() { Flux.range(1, 10).reduce((x, y) ...

  4. Redux/Mobx/Akita/Vuex对比 - 选择更适合低代码场景的状态管理方案

    近期准备开发一个数据分析 SDK,定位是作为数据中台向外输出数据分析能力的载体,前端的功能表现类似低代码平台的各种拖拉拽.作为中台能力的载体,SDK 未来很大概率会需要支持多种视图层框架,比如Vue2 ...

  5. Reactor3 中文文档(用户手册)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  6. knockoutJs在移动设备上有时无法更新控件值

    最近在用cordova(phonegap)写一个移动app,表单比较复杂,用了knockoutJs作为前端的MVVM框架进行数据绑定. 但是发现有时候(其实是每次)如果最后在input中编辑一个值,然 ...

  7. 理顺react,flux,redux这些概念的关系

    作者:北溟小鱼hk链接:https://www.zhihu.com/question/47686258/answer/107209140来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

  8. Flux 普及读本

    话说当时做 APP 时,三月不知肉味,再次将眼光投放前端,有种天上一天,地下一年的感觉. Flux 是一种思想 了解的最好方式当然是看Flux官方文档了.React 中文站点也能找到对应的翻译版本,但 ...

  9. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 3

    原文地址:http://ddmvc4.codeplex.com/ 原文名称:Design and Develop a website using ASP.NET MVC 4, EF, Knockout ...

随机推荐

  1. 升级android studio 3.4需要注意n事项

    1.在AS版本升级前建议关闭AS代理,以及关闭本地的一些代理工具,不然点击更新的时候会提示Connection failed (Read timed out). Please check networ ...

  2. 手写数字识别 ----卷积神经网络模型官方案例注释(基于Tensorflow,Python)

    # 手写数字识别 ----卷积神经网络模型 import os import tensorflow as tf #部分注释来源于 # http://www.cnblogs.com/rgvb178/p/ ...

  3. python基础其他

    目录: 一.Python为什么受欢迎的本质,知道的人寥寥无几? 二.PyCharm的模板设置 三.pycharm的一些快捷键 四.PyCharm最新2018激活 五.python虚拟环境--virtu ...

  4. 动态规划——Palindrome Partitioning II

    Palindrome Partitioning II 这个题意思挺好理解,提供一个字符串s,将s分割成多个子串,这些字串都是回文,要求输出分割的最小次数. Example:Input: "a ...

  5. [转]C# 使用Conditional特性而不是#if条件编译

    转自: http://www.cnblogs.com/xibei666/p/5495561.html 概述 #if/#endif 语句常用来基于同一份源码生成不同的编译结果,其中最常见的就是debug ...

  6. Java EE 导图

  7. 2018-2019-20175324实验一《Java开发环境的熟悉》实验报告

    2018-2019-20175324实验一<Java开发环境的熟悉>实验报告   实验内容与结果 一.Java开发环境的熟悉-1 1.实验要求: 0 参考实验要求 1 建立“自己学号exp ...

  8. idea破解失效:cant obtain ticket from http://idea.iteblog.com/key.php

    破解idea错误描述:cant obtain ticket from http://idea.iteblog.com/key.php   idea破解失效 解决方案: 打开链接: http://ide ...

  9. ipset和iptables配合来自动封闭和解封有问题的IP

    iptables封掉少量ip处理是没什么问题的,但是当有大量ip攻击的时候性能就跟不上了,iptables是O(N)的性能.而ipset就像一个集合,把需要封闭的ip地址放入这个集合中,ipset 是 ...

  10. layui layer弹框中表格的显示

    场景描述:点击iframe里面的一个按钮,需要在父级弹出一个弹框表格. 问题描述:这个弹框的分页不能正常显示,如果把layer.open前面的parent去掉,就可以正常显示. 代码展示: paren ...