两年前写的,现在发出来,也当是一个记录。

我知道贴代码有些人会反对,觉得应该用文字讲细致,但是我觉得用文字我没发用简单的文字来表达,看代码反而更直接,这个是见仁见智的。

很早之前一直用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框架的更多相关文章

  1. 微信js框架第二篇(创建完整界面布局)

    接着昨天的继续谈关于微信新出的这个js框架,今天主要谈一个页面的创建到布局的详细步骤. 一.创建一个完整页面       页面你可以创建在项目的任何节点,只要你在入口文件正确引入创建该页面的路径就可使 ...

  2. JS框架

    s框架就是将常用的方法进行封装,方便调取使用.一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计.协作构件之间的依赖关系.责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方 ...

  3. 前端Js框架汇总

    概述: 有些日子没有正襟危坐写博客了,互联网飞速发展的时代,技术更新迭代的速度也在加快.看着Java.Js.Swift在各领域心花路放,也是煞是羡慕.寻了寻.net的消息,也是振奋人心,.net co ...

  4. Node.js 框架

    Node.js的是一个JavaScript平台,它允许你建立大型的Web应用程序.  Node.js的框架平台使用JavaScript作为它的脚本语言来构建可伸缩的应用. 当涉及到Web应用程序的开发 ...

  5. js框架设计1.1命名空间笔记

    借到了司徒正美的写的js框架设计一书,司徒大神所著有些看不太懂,果然尚需循序渐进,稳扎js基础之中. 第一张开篇司徒阐述了种子模块的概念 种子模块亦为核心模块,框架最先执行模块,司徒见解应包含:对象扩 ...

  6. 自己的JS框架--Amy框架。

    这是我根据司徒正美<JavaScript框架设计>一书然后百度了很多东西之后自己写的一个JS框架,满足了司徒正美文中的种子模块部分,包含了命名空间.对象扩展.数组化.类型判断.选择器.多库 ...

  7. Aurelia – 模块化,简单,可测试的 JS 框架

    Aurelia 是下一代 JavaScript 客户端框架,利用简单的约定来激发你的创造力.凭借其强大的专注于开发经验, Aurelia 可以使您不仅创造惊人的应用程序,同时也享受这个过程.它经过精心 ...

  8. JavaScriptOO.com – 快速找到你需要的 JS 框架

    JavaScriptOO.com 集合了目前 Web 开发中最常用的422(截至目前)款 JavaScript 框架,你可以根据功能类别(Ajax,动画,图表,游戏等)进行过滤和排序,快速找到你需要的 ...

  9. KnockoutJS---一个极其优秀的MVVM模型的js框架

    相信对于DotNet平台的开发人员来讲,MVVM模式已经不再是个陌生的词汇了吧.而我们今天介绍的Knockout JS, 则是一个MVVM模式的JS框架,官方网址:http://knockoutjs. ...

  10. js框架简明

    jquery 主要战场还是在dom这块.其它经典怀旧的2个需要了解一下,mootools, prototype.是他们启发了js向工程化,团队化,协作化发展的转变,yui虽然听说停止开发了,但他的代码 ...

随机推荐

  1. SublimeText3 生成html标签快捷键

    mmet Documentation Syntax Child: > nav>ul>li <nav> <ul> <li></li> & ...

  2. kettle使用log4j管理输出日志

    在使用kettle进行数据分析和清洗时日志非常多而且杂乱,使用原有的日志有时找不到异常的位置,有时日志不够详细,说简单一点就是日志不是我们想要的.因而对kettle日志进行相应的管理就想得尤为重要了. ...

  3. Java for LeetCode 168 Excel Sheet Column Title

    Given a positive integer, return its corresponding column title as appear in an Excel sheet. For exa ...

  4. codeforces B.Fence 解题报告

    题目链接:http://codeforces.com/problemset/problem/363/B 题目意思:给定整数n和k,需要从n个数中找出连续的k个数之和最小,输出这连续的k个数中的第一个数 ...

  5. python 的类变量和对象变量

    python是一种解释性的语言,任何变量可以在使用的时候才声明以及定义,也可以在程序运行的任何位置进行声明和定义新的变量. class Man(object): #直接定义的类的变量,属于类 #其中 ...

  6. CodeForces - 404A(模拟题)

    Valera and X Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Submit ...

  7. iOS 手势操作:拖动、捏合、旋转、点按、长按、轻扫、自定义

    1.UIGestureRecognizer 介绍 手势识别在 iOS 中非常重要,他极大地提高了移动设备的使用便捷性. iOS 系统在 3.2 以后,他提供了一些常用的手势(UIGestureReco ...

  8. Update startup files更新安装文件

    The service request did not complete because access to the service configuration manager was not gra ...

  9. NSOperation基本使用

     NSOperation简单介绍 a. 是OC语言中基于GCD的面向对象的封装 b. 使用起来比GCD更加简单(面向对象) c. 提供了一些用GCD不好实现的功能 d. 苹果推荐使用,使用NSOper ...

  10. vim 多窗口

    打开多个文件: 1.vim还没有启动的时候: 在终端里输入 vim file1 file2 ... filen便可以打开所有想要打开的文件 2.vim已经启动 输入 :open file 可以再打开一 ...