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.pswp.cn/news/251720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251720.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

輕量社交APP系統ThinkSNS 簡 權威發布 限時惠購

2019獨角獸企業重金招聘Python工程師標準>>> 伴隨國內外創業風潮、AI、區塊鏈等互聯網軟件科技領域的高速發展&#xff0c;2019年&#xff0c;ThinkSNS軟件品牌迎來十周年后的新紀元。作為下一個階段的產品元年&#xff0c;官方于2019年5月正式發售輕量核心社交APP系…

linux下安裝oracle sqlplus以及imp、exp工具

一、下載oracle 11g sqlplus軟件 linux 64位操作系統&#xff0c;oracle安裝包地址 http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html oracle-instantclient11.2-sqlplus-11.2.0.3.0-1.x86_64.rpm  oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_6…

在operator =中要處理“自我賦值”

防止自我賦值很有必要 Widget w; w w; a[i] a[j]; //a[i]和a[j]實際上指向同一個元素 *pi *pj; //pi和pj實際上指向同一個元素 自我賦值的危害&#xff1a; Widget { private:Test *p; }; Widget &Widget::operator(const Widget &w) {delete p;p new int (*w.p);r…

新添加磁盤分區后,找不到新分區

問題&#xff1a;在Vcent中擴容磁盤容量&#xff0c;登錄虛擬機fdisk /dev/sda分區后&#xff0c;找不到新分區。 lsblk或者 df -TH fdisk /dev/sda p 嘗試解決辦法&#xff1a; cd /sys/class/scsi_host/ ls echo "- - -" > /sys/class/scsi_host/host0/scan (中…

Linux一些指令

備忘。。 ~/.bashrc 環境變量文件 xshell5 與本機文件傳輸 rz接受 sz filename 傳輸 watch -n 2 nvidia-smi 監視gpu 狀態wget 下載單個文件wget http://images.cocodataset.org/zips/train2014.zip給.sh文件添加x執行權限 比如以hello.sh文件為例&#xff0c;chmod ux hello…

C# 通過反射獲取方法/類上的自定義特性

1.所有自定義屬性都必須繼承System.Attribute 2.自定義屬性的類名稱必須為 XXXXAttribute 即是已Attribute結尾 自定義屬性QuickWebApi [AttributeUsage(AttributeTargets.Method, Inherited false, AllowMultiple true)]public class QuickWebApiAttribute: Attribute{publ…

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…

前端安全之token

前端可以通過cookie以js的方式存取token&#xff0c;并且實現用戶的登錄登出以及token的超時操作&#xff0c;但這樣做并不安全&#xff0c;無法避免跨站腳本的攻擊&#xff0c;如果對項目的安全性要求比較高&#xff0c;應該在服務端開啟http only為true&#xff0c;通過服務端…

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 對傳文件…

Mybatis中輸入輸出映射和動態Sql

一、輸入映射我們通過配置parameterType的值來指定輸入參數的類型&#xff0c;這些類型可以是簡單數據類型、POJO、HashMap等數據類型1、簡單類型2、POJO包裝類型①這是單表查詢的時候傳入的POJO包裝類型&#xff0c;即可以直接傳入實體類&#xff0c;但是當多表查詢的時候&…

css純字母或者字母換行顯示

white-space:normal; word-break:break-all;轉載于:https://www.cnblogs.com/mmykdbc/p/7661009.html

javascript使用btoa和atob來進行Base64轉碼和解碼

javascript中如何使用Base64轉碼 let str javascript;let btoaStr window.btoa(str); //轉碼結果 amF2YXNjcmlwdAconsole.log(btoaStr);console.log(window.atob(btoaStr)); //解碼結果 javascriptBase64轉碼的對象只能是字符串, var str "China&#xff0c;中國"…

珠寶條碼打印掃描解決方案

隨著人們生活水平的逐步提高&#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兩個函數都可以用來復制…

Android Activity標簽屬性

Android Activity標簽屬性 Activity 是 Android 系統四大應用組件之一&#xff0c;用戶可與 Activity 提供的屏幕進行交互&#xff0c;以執行撥打電話、拍攝照片、發送電子郵件等操作開發者必須在清單文件中聲明要使用的 Activity&#xff0c;這樣系統才能訪問它。聲明方式是在…

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驗…