在做后台管理系统的同学们,是否有用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

knockout + easyui = koeasyui相关推荐

  1. Knockout.js 整理

    上个月做项目需要用到easyui和Knockout.js ,所以简单的整理了下,以便学习 Knockout.js 是一个JavaScript库,它可以让HTML控件很容易与数据进行绑定.使用的是&qu ...

  2. Knockout中文开发指南(完整版API中文文档) 目录索引

    推荐阅读:https://www.cnblogs.com/smallprogram/p/5976954.html http://www.cnblogs.com/xqin/tag/easyui/ 一.下 ...

  3. JQuery EasyUI的常用组件

    jQuery EasyUI 是一个基于 jQuery 的框架,集成了各种用户界面插件,该框架提供了创建网页所需的一切,帮助您轻松建立站点. 注:本次介绍的JQuery EasyUI版本为1.5版. 一 ...

  4. java easyui tree例子_EasyUI Tree的简单使用

    此前写过zTree插件的demo,没有记录下来,这次记录一下EasyUI的Tree. 实现效果:获取数据库表的数据,以树结构的形式展示出来. 树结构数据分为同步加载和异步加载,同步加载就是初始化加载时 ...

  5. 雷林鹏分享:jQuery EasyUI 数据网格 - 创建属性网格

    jQuery EasyUI 数据网格 - 创建属性网格 属性网格(property grid)带有一个内置的 expand(展开)/collapse(合并) 按钮,可以简单地为行分组.您可以简单地创建 ...

  6. 第二百二十节,jQuery EasyUI,Slider(滑动条)组件

    jQuery EasyUI,Slider(滑动条)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Slider(滑动条)组件的使用方法,这个 ...

  7. easyui源码翻译1.32--Messager(消息窗口)

    前言 使用$.messager.defaults重写默认值对象.下载该插件翻译源码 消息窗口提供了不同的消息框风格,包含alert(警告框), confirm(确认框), prompt(提示框), p ...

  8. Easyui 让Window弹出居中与最大化后居中

    easyui1.3.2版本,window的弹出不会居中了.而dialog是会居中的,我们必须为为window的open事件做扩展 代码如下:只要加入以下代码即可.如果你是看了MVC项目系列的,把他放到 ...

  9. php easyui tree 结构,EasyUI Tree树组件无限循环的解决方法

    在学习jquery easyui的tree组件的时候,在url为链接地址的时,发现如果最后一个节点的state为closed时,未节点显示为文件夹,单击会重新加载动态(Url:链接地址)形成无限循环. ...

最新文章

  1. tensorflow随笔-随机数
  2. ajax如何给label赋值,如何让AjaxEditableLabel显示TextField?
  3. SAP标准培训课程C4C10学习笔记(一)第一单元
  4. [Silverlight]使用PagedCollectionView配合复选框实现动态筛选的解决方案
  5. 精选| 2020年8月R新包推荐(第45期)
  6. Mysql的数据库引擎 区别特点_mysql数据库存储引擎及区别
  7. perlin噪声函数
  8. Android Root原理初探
  9. Java:批量插入、修改数据到数据库中的用法
  10. 最近很热衷于研究相册效果:)
  11. html5中box-shadow,CSS阴影效果(Box-shadow)用法趣味讲解
  12. 大年初一连夜带娃改bug:CTO把代码写成这鬼样子,被害惨了!
  13. 十进制转化成八进制(一到十六进制)
  14. Java面向对象(一)20170517
  15. 架构师:成为架构师可能会面临的问题
  16. nmea怎么转wgs84坐标c语言源码,NMEA-0813数据格式说明
  17. 【AI视野·今日CV 计算机视觉论文速览 第192期】Thu, 6 May 2021
  18. WPS2005中实现多行合一(转)
  19. java银行排队系统_java--面向对象(一个简单的银行排队系统)原理版
  20. flask开发桌面应用程序_使用Microsoft Authenticatio将多个破折号应用程序嵌入Flask中...

热门文章

  1. SQL:find duplicate rows -- using group or having
  2. 投影仪投影粉色_DecisionTreeRegressor —停止用于将来的投影!
  3. 直击于丹软肋的作家——李悦
  4. 在辉腾锡勒我见到了狼
  5. UART 异步串行通信发送模块设计与实现
  6. 产品配件类目税目分类_我国消费税税目种类有哪些?
  7. 华为手机出现android啥意思,传华为正研发手机系统,如果脱离安卓系统,还有啥能阻止华为前进...
  8. 平板电脑办公软件_大屏平板互动软件-平板电脑触摸大屏控制软件
  9. c# mongodb or查询_C# MongoDB 查询方法
  10. python波峰波谷算法_波动均分算法