实现自己的js框架
两年前写的,现在发出来,也当是一个记录。
我知道贴代码有些人会反对,觉得应该用文字讲细致,但是我觉得用文字我没发用简单的文字来表达,看代码反而更直接,这个是见仁见智的。
很早之前一直用extjs,这个确实非常强大,但是在IE下一直都有一个性能的问题,搞得要让客户换chrome,firefox浏览器才行。
之所以要写自己js框架,原因是觉得自己实现也简单,维护也方便,一些管理应用的项目可以用,网站这些我还是推荐直接使用jquery,毕竟更加简单直接没有那么多可给你重复应用的地方。
可能你要问为什么不用jquery插件,一样可以。但是这些插件代码质量不能保证,风格也是奇形怪状,出了问题还要去看代码,改了之后又跟原作者的有出入,以后同步更加麻烦。
不用jquery插件,但是jquery却是个好东西,解决了浏览器兼容的大问题,所以我这个就是基于jquery来实现的,因为一直喜欢extjs的代码风格,所以如果你使用过extjs的话,使用起来会轻车熟路。
js的继承是原型继承的方式,最开始的时候我确实也用原型的方式来实现,但是后面我发现有些问题,而且理解起来不是太清晰,所以我采用一种简单清晰的方法,写起来是继承但是实际上它只是一个对象。
它同样有着抽象方法,有父类,有重载,有重写等等。
先看一下大概结构如下图:
现在说下几个重要的地方
首先就是如何定义一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | define: function (className, defaultConfig) { if (!wyl.isString(className) || className.isEmpty()) { throw new Error( "[wyl.define] Invalid class name '" + className + "' specified, must be a non-empty string" ); } var namespace_arr = className.split( '.' ); var namespace = window; var class_Name = namespace_arr.last(); wyl.each(namespace_arr, function (ns) { if (ns == class_Name) { return ; } if (!namespace[ns]) { namespace[ns] = {}; } namespace = namespace[ns]; }); if (namespace[class_Name]) { throw new Error( '重复定义了' + className); } defaultConfig.className = className; for ( var p in defaultConfig) { if (wyl.isFunction(defaultConfig[p])) { defaultConfig[p].fnName = p; } } namespace[class_Name] = defaultConfig; } |
接着就是如何创建一个类的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | getDefineConfig: function (namespaces, i, context) { if (context == null ) { return null ; } if (namespaces.length == i) { return context; } var ns = namespaces[i]; return wyl.getDefineConfig(namespaces, i + 1, context[ns]); } create: function (className, config) { if (!wyl.isString(className) || className.isEmpty()) { throw new Error( "[wyl.create] Invalid class name '" + nsclassName + "' specified, must be a non-empty string" ); } var namespaces = className.split( '.' ); var defineConfig = wyl.getDefineConfig(namespaces, 0, window); if (!defineConfig) { throw '{0}类型未定义。' .format(className); } config = config || {}; if (!config.id) { config.id = wyl.newId(); } var instance = {}; wyl.apply(instance, config, defineConfig); //继承的关键代码如下 if (instance.extend) { var base = wyl.create(instance.extend); for ( var p in base) { if (instance.hasOwnProperty(p)) { //把父类的方法重新命名赋值到这个实例上 if (wyl.isFunction(instance[p]) && wyl.isFunction(base[p])) { var baseFnName = instance.extend + '_' + p; instance[p][ 'baseFnName' ] = instance.extend + '_' + p; instance[baseFnName] = base[p]; } } else { instance[p] = base[p]; } } } instance.initConfig = config; if ( typeof (instance.init) == 'function' ) { instance.init.apply(instance); } if (wyl.isFunction(instance.initComponent)) { instance.initComponent.apply(instance); } wyl.each(instance.abstractMethods, function (methodName) { this [methodName] = function () { throw this .className + ' has not implement ' + methodName; } }, this ); this .intanceMgr[instance.id] = instance; return instance; } |
对于所有的类型我定义了一个基类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | wyl.define( 'wyl.object' , { initConfig: null , abstractMethods: [], //ext4.0中调用父类的方法就是这个 callParent: function () { var me = this ; //调用的时候根据之前create里面加入的隐藏信息baseFnName来找到父类的方法并调用它 var fnname = me.callParent.caller[ 'baseFnName' ]; var fn = me[fnname]; if (wyl.isFunction(fn)) { fn.call(me); } }, addEvents: function () { var me = this ; if (!wyl.eventMgr[me.id]) { wyl.eventMgr[me.id] = {}; } var myEventMgr = wyl.eventMgr[me.id]; wyl.each(arguments, function (eventName) { if (!myEventMgr[eventName]) { myEventMgr[eventName] = []; } }); }, fireEvent: function (eventName, prams) { var me = this ; var myEventMgr = wyl.eventMgr[me.id]; var listeners = myEventMgr[eventName]; if (wyl.isArray(listeners)) { wyl.each(listeners, function (listener) { var scope = listener.scope ? listener.scope : this ; if (listener.callback && typeof (listener.callback) == 'function' ) { listener.callback.call(scope, prams); } }); } }, on: function (eventName, options) { var me = this ; if (!wyl.eventMgr[me.id]) { wyl.eventMgr[me.id] = {}; } var myEventMgr = wyl.eventMgr[me.id]; if (!myEventMgr[eventName]) { myEventMgr[eventName] = []; } var removeIndex = null ; wyl.each(myEventMgr[eventName], function (item, i) { var b = options.callback == item.callback; if (b) { removeIndex = i; } return !b; }); if (removeIndex && removeIndex > -1) { myEventMgr[eventName].removeAt(removeIndex); } myEventMgr[eventName].push(options); }, destroy: function () { delete wyl.eventMgr[ this .id]; delete wyl.intanceMgr[ this .id]; }, init: function () { wyl.apply( this , this .initConfig); } }); |
界面的控件,我也定义了一个基类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | wyl.define( 'wyl.Component' , { extend: 'wyl.object' , containerSelector: null , container: null , abstractMethods: [ 'render' ], getContainer: function () { if ( this .container === null ) { this .container = $( this .containerSelector).first(); if ( this .container == null ) { throw '控件必须要设置containerSelector或不存在.' ; } } return this .container; }, setContainer: function (selector) { if ( typeof (selector) != 'string' ) { throw '设置container必须是string类型.' ; } this .containerSelector = selector; }, getWidth: function () { return this .getContainer().width() - 2; }, getHeight: function () { return this .getContainer().height() - 2; } }); |
大概的思路就是容器会负责分配给下面子控件的容器setContainer,子控件得到自己的容器getContainer,一个控件不需要关系其他控件,只需要控制好自己内部的控件元素就行了。
里面定义了一个抽象方法render,每个控件都必须实现这个方法。容器render的时候,同时如果自己内部有子控件,也render自己内部的子控件。
posted on 2013-11-22 08:46 bmrxntfj 阅读(4406) 评论(11) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探