knockout + easyui = koeasyui

     在做后台管理系统的同学们,是否有用easyui的经历。虽然现在都是vue、ng、react的时代。但easyui(也就是jquery为基础)还是占有一席之地的。因为他对后端开发者太友好了,太熟悉不过了。要让一个后端开发者来理解vue或者是react的VNode、状态器、组件等,都是有那么一点点的为难(反正我转型时,对这些都是很有困惑的)。今天我想试着解决这样一个问题,如:将knockout 与 大家熟悉的easyui结合在一起。让easyui具有MVVM的能力,也有不使用easyui的特性,看大家是否喜欢这一口。

一、项目介绍说明

项目语言:typescript

项目地址:https://gitee.com/ko-plugins/koeasyui

初级效果:

望大家给予评论和支持。

二、如何将easyui转换为ko的组件

     再前几年用ko的时候,由于他没有组件的支持(因为当时没有组件的概念)。至到react、vue提出和引用了组件的概念,以及将此概念深入到每个前端开发者的内心后。ko也提供了组件的支持。2017年看这个新特性的时候,就让我有改造easyui的冲突。当时苦于对ko和easyui的理解不深入,硬是没有找到突破口。今天终于让我找到。

2.1 easyui组件如何注册到为ko组件

     ko提供了components.register方法,用于注册一个组件。此方法接受一个字符串的名称,以及一个对象(至少包含一个template或viewModel属性),其中viewModel可以是一个对象,也就是一个function。本人就利用了可以为function这一点。根据easyui的组件名动态创建一个function,然后赋值给viewModel,代码片段如下:

let plugins = this.easyui.plugins;//动态生成一个function的类plugins.forEach(pluginName => {let defaults = this.jquery.fn[pluginName].defaults;let methods = this.jquery.fn[pluginName].methods;if(defaults){//options必须要是独立的,事件(放原型上),方法可以原型链上的let props = Object.getOwnPropertyNames(defaults);//方法let methodKeys = Object.getOwnPropertyNames(methods);this.option.ko.components.register(`ko-${pluginName}`,{template: '<div></div>',viewModel: EasyuiHelper.createEasyui(props, methodKeys)});}});

 

2.2 easyui组件的配置和方法怎么变成ko组件的参数和方法

上一步骤中的EasyuiHelper.createEasyui方法,就是实现对easyui组件的创建,以及参数的响应和方法的绑定,算是本插件的核心。

export  class EasyuiHelper{static createEasyui(props:Array<string>, methods):any{let tmpClass = class { public $dom:JQuery;public name:string;constructor(params, componentConfig){ this.name = componentConfig.element.nodeName.toLowerCase().replace('ko-', '');this.$dom = $(componentConfig.element).find('div');//绑定方法,方法还需要继承组件支持的方法的绑定Object.getOwnPropertyNames(methods).forEach(index=>{if(!$.isNumeric(index)) return true;let methodName = methods[index]; this[methodName] = ()=>{let args = Array.prototype.slice.call(arguments);args.unshift(methodName);return this.$dom[this.name].apply( this.$dom, args);}; });}            /*** 根据参数创建组件的配置对象* @param options 配置参数 */private createOptions(options){let opt = null;if(options){opt = Object.create({});Object.getOwnPropertyNames(options).forEach(optKey=>{let tmpOpt = options[optKey];if(props.indexOf(optKey) > 0 && ko.isObservable(tmpOpt) ){opt[optKey] = ko.unwrap(tmpOpt);}else{opt[optKey] = tmpOpt;}});}return opt;}/*** 绘制组件* @param options */public paint(options:any){let opt = this.createOptions(options);this.$dom[this.name](opt);}/*** 重组件* @param options 配置项* @param $dom dom元素对象*/public repaint(options:any){let $parent = this.$dom.parent();this.$dom[this.name]('destroy');let $dom = $('<div></div>');let opts = this.createOptions(options);$parent.append($dom);$dom[this.name](opts);this.$dom = $dom;}};return tmpClass;}/*** 根据dom获取上下文* @param dom dom节点 */static getContextFor(dom:HTMLElement){return ko.contextFor(dom);}
}

    代码量不多,其主要思路就是,动态创建一个类(其实js中的类就是function)。构造函数中获取到dom,以及组件名称。然后将easyui的方法绑定到类实例上。然后对外提供paint和repaint两个方法进行组件的绘制和重绘。但这个时候又出现了另一个问题,什么时候进行绘制重绘呢?

2.3 配置参数改变后,如何即使反馈给easyui

这一步就是解决绘制和重绘的问题。这里我们要了解一个ko的loader的概念,他相当于是组件渲染器向外提供的勾子,可以自定义一些内容。ko的loader提供了如下四个勾子:

getConfig:获取组件配置信息

loadComponent:加载组件时的勾子,这里我们可以使用利用require的异步组件加载什么

loadTemplate:加载模板,当然你的通过ajax向后端接口获取模板信息

loadViewModel:加载组件视图对象(这是我们要重写的方法),通过此处的重写,让组件渲染器创建我们指定的类。并执行执行的绘制或者是重绘方法。

export class EasyuiLoader{public factory:IGenerate;constructor(factory: IGenerate){ this.factory = factory;}getConfig(name:any, callback:any){callback(null);}loadComponent(name:any, componentConfig:any, callback:any){callback(null);}loadTemplate(name:any, templateConfig:any, callback:any){//这里做一些视图不显示的控制,在渲染数据后,进行视频的展示callback(null);}loadViewModel(name:any, viewModelConfig:any, callback:any){//到这里,视图都是已经呈现好的//这里要产生两个生命周期:渲染数据前、渲染数据后,以及一个视图重绘的事件var nViewModelConfig = (params, componentConfig) => {let vm = new viewModelConfig(params, componentConfig);let name;vm = this.factory.generate(name, params, vm);return vm;}callback(nViewModelConfig);}
}

以下是factory.generate的源码:

generate(componentName: string, params: any, viewModel: any):any {let first = true;viewModel.paint(params.options || {});//监听params的变化变化ko.computed(function(){let opts = params.options; let changeOpts = new Array<any>();let reflows = new Array<any>(); //可以通过方法来进行配置改变的参数Object.getOwnPropertyNames(opts).forEach(key => {let param = opts[key];let tmp = ko.unwrap(param);//探测监控对象有变化的属性,区分那些可以用方法进行改变,那些需要重绘if(ko.isObservable(param) && param.hasChanged()){changeOpts.push(param);if(relation[viewModel.name] && relation[viewModel.name][key]){reflows.push({val: tmp,methodName: relation[viewModel.name][key]});}}});if(first){ //如果是初始化执行,后面的业务不用重复执行了first = false;return;}if(changeOpts.length>0){if(changeOpts.length == reflows.length){//说明配置的改变,可能通过方法操作完成Object.getOwnPropertyNames(reflows).forEach(key=>{let item = reflows[key];viewModel.$dom[viewModel.name](item.methodName, item.val);});}else{//引起了组件重绘
                    viewModel.repaint(opts);}}});return viewModel;}

1. 进入此方法,首先我们进行组件的绘制(也就是创建)

2. 然后通过ko.computed方法监听params中的options(配置参数)的改变,然后进行组件重绘或者是部分改变(这里我叫他回流reflow)。

3. 由于ko.computed在初始化的时候会执行,所以通过first变量进行问题的回避。

三、还需要完善的点

1. 现在动态生成的koeasyui组件提供的方法只是easyui组件本身的,而没有对其继承的方法进行合并

2. repaint和reflow需要更细致的区分,让组件性能达到最优。

转载于:https://www.cnblogs.com/cqhaibin/p/9064803.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

轻量社交APP系统ThinkSNS 简 权威发布 限时惠购

2019独角兽企业重金招聘Python工程师标准>>> 伴随国内外创业风潮、AI、区块链等互联网软件科技领域的高速发展&#xff0c;2019年&#xff0c;ThinkSNS软件品牌迎来十周年后的新纪元。作为下一个阶段的产品元年&#xff0c;官方于2019年5月正式发售轻量核心社交APP系…

Spring Cloud Zuul网关(快速搭建)

zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。 在云平台上提供动态路由&#xff0c;监控&#xff0c;弹性&#xff0c;安全等边缘服务的框架。相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。主要功能是路由转发和过滤器。 Zuul可…

10.13 上午 考试

T1 直接二分就好了 #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std;ll n; in…

gbk 转 UTF-8

iconv命令 gbk 转 UTF-8 -----linux gbk 转 UTF-8-------- iconv 用法 iconv -f "gbk" -t "utf-8" < infile > outfile 或者 piconv -f "gbk" -t "utf-8" < infile > outfile iconv -f utf-8 -t GBK 123456.txt 对传文件…

珠宝条码打印扫描解决方案

随着人们生活水平的逐步提高&#xff0c;珠宝消费日益增长&#xff0c;据统计&#xff0c;我国珠宝首饰零售规模超过7000亿&#xff0c;过去5年复合增长为15%&#xff0c;是规模增长最为迅速的可选消费品类之一。面对千亿级的消费市场&#xff0c;珠宝行业竞争激烈&#xff0c;…

课程作业1

1使用组合数公式利用n!来计算 a.设计思想 定义n和k&#xff0c;用递归函数表示出N!的阶乘结果&#xff0c;c(n,k)n!/(k!(n-k)!);调用函数求出c(n,k)的结果 b.源代码 package kecheng1; import java.util.Scanner; public class Test {public static void main(String[] args) {…

新手学Python推荐的四本书籍+2个资源网站

2019独角兽企业重金招聘Python工程师标准>>> 很多伙伴初学Python&#xff0c;会问到&#xff1a;有没有好的学习书籍推荐&#xff1f;有没有好的学习网站推荐&#xff1f; 针对这类伙伴的问题&#xff0c;小优给大家整理了学习Python的四本书籍2个资源网站&#xff…

【转】Linux系统编程---dup和dup2详解

正常的文件描述符&#xff1a; 在linux下&#xff0c;通过open打开以文件后&#xff0c;会返回一个文件描述符&#xff0c;文件描述符会指向一个文件表&#xff0c;文件表中的节点指针会指向节点表。看下图&#xff1a; 打开文件的内核数据结构 dup和dup2两个函数都可以用来复制…

Java -----JVM运行时数据区

一、JVM体系结构 想要了解运行时数据区&#xff0c;先关注一下JVM的体系结构&#xff0c;知道数据区在JVM的整体位置和作用。 二、JVM运行时数据区 1.程序计数器 一块较小的内存空间&#xff0c;它是当前线程所执行的字节码的行号指示器&#xff0c;字节码解释器工作时通过改变…

20155235 《网络攻防》 实验八 Web基础

20155235 《网络攻防》 实验八 Web基础 实验内容 Web前端HTML(0.5分) 能正常安装、启停Apache。理解HTML&#xff0c;理解表单&#xff0c;理解GET与POST方法,编写一个含有表单的HTML。Web前端javascipt(0.5分) 理解JavaScript的基本功能&#xff0c;理解DOM。编写JavaScript验…

【每周一图】蜂鸟

摄影/祈澈姑娘小花园偶遇的一只蜂鸟转载于:https://www.cnblogs.com/wangting888/p/9702088.html

API网关如何实现对服务下线实时感知

上篇文章《Eureka 缓存机制》介绍了Eureka的缓存机制&#xff0c;相信大家对Eureka 有了进一步的了解&#xff0c;本文将详细介绍API网关如何实现服务下线的实时感知。 一、前言 在基于云的微服务应用中&#xff0c;服务实例的网络位置都是动态分配的。而且由于自动伸缩、故障和…

反射笔记-----------------------------

1.反射基本概念&#xff1a; 01.定义&#xff1a; 反射是指在程序运行期间&#xff0c;能够观察和修改类或者类的对象的属性和行为的特性&#xff01; 02.作用&#xff1a; 001.在运行期间获取类的修饰符&#xff0c;包名&#xff0c;类名&#xff0c;实现的接口&#xff0c;继…

kubernetes 集群部署

kubernetes 集群部署 环境JiaoJiao_Centos7-1(152.112) 192.168.152.112JiaoJiao_Centos7-2(152.113) 192.168.152.113JiaoJiao_Centos7-3(152.114) 192.168.152.114已开通 4C8G80G 集群规划 部署方式 环境准备&#xff1a;基于主机名称通信&#xff0c;时间同步&#xff0c;关…

wordpress 显示数学公式 (MathJax-LaTeX)

blog 不放一堆数学公式怎么能显得高大上&#xff0c;所以 MathJax-LaTeX 也是必装的插件之一了。 一、安装 MathJax-LaTex 插件 直接在 wordpress 插件中&#xff0c;搜索并安装 MathJax-LaTeX 二、安装本地 MathJax 服务 不过由默认的 MathJax cdn 服务经常被墙&#xff0c;所…

ConstraintLayout

ConstraintLayout使用笔记 具体使用参考&#xff1a;http://blog.csdn.net/guolin_blog/article/details/53122387 ConstraintLayout 好处还是很明显&#xff0c;确实可以减少嵌套。性能对比参阅&#xff1a;http://www.cnblogs.com/liujingg/p/7161319.html 简单嵌套Constrain…

python(5)- 基础数据类型

一 int 数字类型 #abs(x)      返回数字的绝对值&#xff0c;如abs(-10) 返回 10 # ceil(x)    返回数字的上入整数&#xff0c;如math.ceil(4.1) 返回 5 # cmp(x, y)    如果 x < y 返回 -1, 如果 x y 返回 0, 如果 x > y 返回 1 # exp(x)…

基于HTK的语音拨号系统

为什么80%的码农都做不了架构师&#xff1f;>>> 基于 HTK 的语音拨号系统 Veket NWPU 2011-6-22 目标&#xff1a; 该系统能够识别连续说出的数字串和若干组姓名。建模是针对子词&#xff08; sub-word,eg.. 音素&#xff09;&#xff0c;具有一定的…

MySQL无法重启问题解决Warning: World-writable config file '/etc/my.cnf' is ignored

为什么80%的码农都做不了架构师&#xff1f;>>> 今天帮朋友维护服务器&#xff0c;在关闭数据库的命令发现mysql关不了&#xff0c;提示Warning: World-writable config file /etc/my.cnf is ignored &#xff0c;大概意思是权限全局可写&#xff0c;任何一个用户都…

用户体验分析: 以 “南通大学教务管理系统微信公众号” 为例

基于实例分析&#xff0c;体会用户体验设计的 7 条准则&#xff0c;分析“南通大学教务管理系统微信公众号” 在用户体验设计方面让你觉得满意的地方&#xff08;不少于2点&#xff09;&#xff1b;&#xff08;20分&#xff09;&#xff0c;请陈述理由。 同样&#xff0c;分析…