在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 相关文章推荐
多引号嵌套的变量命名的问题
May 09 Javascript
基于javascript、ajax、memcache和PHP实现的简易在线聊天室
Feb 03 Javascript
基于jQuery实现的美观星级评论打分组件代码
Oct 30 Javascript
javascript实现的网站访问量统计代码
Dec 20 Javascript
javascript汉字拼音互转的简单实例
Oct 09 Javascript
预防网页挂马的方法总结
Nov 03 Javascript
Bootstrap缩略图与警告框学习使用
Feb 08 Javascript
浅谈react+es6+webpack的基础配置
Aug 09 Javascript
JS实现从对象获取对象中单个键值的方法示例
Jun 05 Javascript
解决LayUI数据表格复选框不居中显示的问题
Sep 25 Javascript
vue项目中监听手机物理返回键的实现
Jan 18 Javascript
微信jssdk踩坑之签名错误invalid signature
May 19 Javascript
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
PHP中通过加号合并数组的一个简单方法分享
2011/01/27 PHP
在php中判断一个请求是ajax请求还是普通请求的方法
2011/06/28 PHP
编译PHP报错configure error Cannot find libmysqlclient under usr的解决方法
2014/06/27 PHP
PHP中多线程的两个实现方法
2016/10/14 PHP
Laravel构建即时应用的一种实现方法详解
2017/08/31 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
2020/02/15 PHP
jquery 得到当前页面高度和宽度的两个函数
2010/02/21 Javascript
判断javascript的数据类型(示例代码)
2013/12/11 Javascript
javascript计算当月剩余天数(天数计算器)示例代码
2014/01/09 Javascript
JavaScript通过function定义对象并给对象添加toString()方法实例分析
2015/03/23 Javascript
JavaScript中浅讲ajax图文详解
2016/11/11 Javascript
Angular4的输入属性与输出属性实例详解
2017/11/29 Javascript
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
Koa项目搭建过程详细记录
2018/04/12 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
python list语法学习(带例子)
2013/11/01 Python
python使用webbrowser浏览指定url的方法
2015/04/04 Python
python实现多进程代码示例
2018/10/31 Python
python Django的web开发实例(入门)
2019/07/31 Python
用Python爬取QQ音乐评论并制成词云图的实例
2019/08/24 Python
Python 70行代码实现简单算式计算器解析
2019/08/30 Python
用python-webdriver实现自动填表的示例代码
2021/01/13 Python
python实现代码审查自动回复消息
2021/02/01 Python
js实现移动端H5页面手指滑动刻度尺功能
2017/11/16 HTML / CSS
HTML5 本地存储实现购物车功能
2017/09/07 HTML / CSS
墨尔本最受欢迎的复古风格品牌:Princess Highway
2018/12/21 全球购物
美国相机和电子产品零售商:Beach Camera
2020/11/26 全球购物
护理专业毕业生自荐信范文
2014/01/05 职场文书
英语专业学生个人求职信
2014/01/28 职场文书
《只有一个地球》教学反思
2014/02/14 职场文书
意向书范文
2014/03/31 职场文书
2016年小学“我们的节日·中秋节”活动总结
2016/04/05 职场文书
golang 如何用反射reflect操作结构体
2021/04/28 Golang
使用python向MongoDB插入时间字段的操作
2021/05/18 Python
【海涛教你打DOTA】虚空假面第一视角骨弓3房29杀
2022/04/01 DOTA
速龙x4-860k处理器相当于i几
2022/04/20 数码科技