实现自己的js框架
两年前写的,现在发出来,也当是一个记录。
我知道贴代码有些人会反对,觉得应该用文字讲细致,但是我觉得用文字我没发用简单的文字来表达,看代码反而更直接,这个是见仁见智的。
很早之前一直用extjs,这个确实非常强大,但是在IE下一直都有一个性能的问题,搞得要让客户换chrome,firefox浏览器才行。
之所以要写自己js框架,原因是觉得自己实现也简单,维护也方便,一些管理应用的项目可以用,网站这些我还是推荐直接使用jquery,毕竟更加简单直接没有那么多可给你重复应用的地方。
可能你要问为什么不用jquery插件,一样可以。但是这些插件代码质量不能保证,风格也是奇形怪状,出了问题还要去看代码,改了之后又跟原作者的有出入,以后同步更加麻烦。
不用jquery插件,但是jquery却是个好东西,解决了浏览器兼容的大问题,所以我这个就是基于jquery来实现的,因为一直喜欢extjs的代码风格,所以如果你使用过extjs的话,使用起来会轻车熟路。
js的继承是原型继承的方式,最开始的时候我确实也用原型的方式来实现,但是后面我发现有些问题,而且理解起来不是太清晰,所以我采用一种简单清晰的方法,写起来是继承但是实际上它只是一个对象。
它同样有着抽象方法,有父类,有重载,有重写等等。
先看一下大概结构如下图:
现在说下几个重要的地方
首先就是如何定义一个类
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;
}
接着就是如何创建一个类的实例:
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;
}
对于所有的类型我定义了一个基类
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);
}
});
界面的控件,我也定义了一个基类:
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自己内部的子控件。
实现自己的js框架的更多相关文章
- 微信js框架第二篇(创建完整界面布局)
接着昨天的继续谈关于微信新出的这个js框架,今天主要谈一个页面的创建到布局的详细步骤. 一.创建一个完整页面 页面你可以创建在项目的任何节点,只要你在入口文件正确引入创建该页面的路径就可使 ...
- JS框架
s框架就是将常用的方法进行封装,方便调取使用.一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计.协作构件之间的依赖关系.责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方 ...
- 前端Js框架汇总
概述: 有些日子没有正襟危坐写博客了,互联网飞速发展的时代,技术更新迭代的速度也在加快.看着Java.Js.Swift在各领域心花路放,也是煞是羡慕.寻了寻.net的消息,也是振奋人心,.net co ...
- Node.js 框架
Node.js的是一个JavaScript平台,它允许你建立大型的Web应用程序. Node.js的框架平台使用JavaScript作为它的脚本语言来构建可伸缩的应用. 当涉及到Web应用程序的开发 ...
- js框架设计1.1命名空间笔记
借到了司徒正美的写的js框架设计一书,司徒大神所著有些看不太懂,果然尚需循序渐进,稳扎js基础之中. 第一张开篇司徒阐述了种子模块的概念 种子模块亦为核心模块,框架最先执行模块,司徒见解应包含:对象扩 ...
- 自己的JS框架--Amy框架。
这是我根据司徒正美<JavaScript框架设计>一书然后百度了很多东西之后自己写的一个JS框架,满足了司徒正美文中的种子模块部分,包含了命名空间.对象扩展.数组化.类型判断.选择器.多库 ...
- Aurelia – 模块化,简单,可测试的 JS 框架
Aurelia 是下一代 JavaScript 客户端框架,利用简单的约定来激发你的创造力.凭借其强大的专注于开发经验, Aurelia 可以使您不仅创造惊人的应用程序,同时也享受这个过程.它经过精心 ...
- JavaScriptOO.com – 快速找到你需要的 JS 框架
JavaScriptOO.com 集合了目前 Web 开发中最常用的422(截至目前)款 JavaScript 框架,你可以根据功能类别(Ajax,动画,图表,游戏等)进行过滤和排序,快速找到你需要的 ...
- KnockoutJS---一个极其优秀的MVVM模型的js框架
相信对于DotNet平台的开发人员来讲,MVVM模式已经不再是个陌生的词汇了吧.而我们今天介绍的Knockout JS, 则是一个MVVM模式的JS框架,官方网址:http://knockoutjs. ...
- js框架简明
jquery 主要战场还是在dom这块.其它经典怀旧的2个需要了解一下,mootools, prototype.是他们启发了js向工程化,团队化,协作化发展的转变,yui虽然听说停止开发了,但他的代码 ...
随机推荐
- Thinkphp中eq,neq,gt,lt等表达式缩写
eq 等于 equalneq 不等于gt 大于 greater thanegt 大于等于lt 小于 less thanelt 小于等于like LIKEbetween BETWEENno ...
- linux安装setup工具
如果你的Linux系统是最小化安装的,可能会没有setup命令工具,环境是centos 5.8 安装setup命令工具的步骤. 安装setuptool #yum install setuptool 系 ...
- 交换排序—冒泡排序(Bubble Sort)
基本思想: 在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒. 即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就 ...
- 简单方便地扩充Python的系统路径
参考: http://www.elias.cn/Python/PythonPath?from=Develop.PythonPath http://v2in.com/pth-file-usage-in- ...
- 22.整数二进制表示中1的个数[Get1BitCount]
[题目] 输入一个整数,求该整数的二进制表达中有多少个1.例如输入10,由于其二进制表示为1010,有两个1,因此输出2. [分析] 如果一个整数不为0,那么这个整数至少有一位是1.如果我们把这个整数 ...
- kettle作业中的js如何写日志文件
在kettle作业中JavaScript脚本有时候也扮演非常重要的角色,此时我们希望有一些日志记录.下面是job中JavaScript记录日志的方式. job的js写日志的方法. 得到日志输出实例 o ...
- Java for LeetCode 054 Spiral Matrix
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...
- 虚拟机下安装ubuntu后root密码设置
ctrl+alt+t:调出命令行. 问题描述: 在虚拟机下安装了ubuntu中要输入用户名,一般情况下大家都会输入一个自己的网名或绰号之类的,密码也在这时设置过了. 但是当安装成功之后,使用命令#su ...
- linux下文件压缩与解压操作
对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名给搞晕.别个不说,单单就压缩文件为例,我们知道在Windows下最常见的压缩文件就只有两种,一是,zip,另一个是.rap.可 ...
- Buy Tickets(poj 2828)
题意:排队买票,但是 中途 出现插队情况,比如 0 123,代表值为123的人 插入到 0 的位置,如果后面 出现 0 456,那么新的 0的位置就是 456,123就变成是 1的位置了 分析:这道题 ...