jqfree core

var $ = function(selector, context) {

return new $.fn.init(selector, context);

};

$.fn = $.prototype;

$.fn.init = function(selector, context) {

if (selector.nodeType === 1) {

this[0] = selector;

this.length = 1;

return this;

}

var parent = context || document;

var nodeList = parent.querySelectorAll(selector);

this.length = nodeList.length;

for (var i=0; i<this.length; i+=1) {

this[i] = nodeList[i];

}

return this;

};

$.fn.init.prototype = $.fn;

我们需要一个包装着DOM Elements的伪数组,此伪数组对象使用原型链去挂载共享的DOM处理方法,原理如下图。

//选择器

$('body'); //返回$.fn.init {0: body, length: 1, selector: "body"}

$('.class');

$('#id');

$('#id .class');

extend

jqfree中的extend函数参照了prototype.js的实现方式,$.extend和$.fn.extend功能相同,也都是通过浅拷贝的方式,把第二个参数上的对象扩展添加到第二个参数的对象上,如果没有指定第二个参数,则会把第一个参数添加到this上。需要给DOM元素添加方法的话,使用$.fn.extend如$.fn.append,而需要给全局$对象添加扩展的话,使用$.extend,如$.ajax。

$.extend = $.fn.extend = function (destination, source) {

//if source is not exist,copy the destination to this。

if (typeof source === 'undefined') {

source = destination;

destination = this;

}

for (var property in source) {

if (source.hasOwnProperty(property)) {

destination[property] = source[property];

}

}

return destination;

};

traverse

遍历jqfree对象中的DOM Elements。实际上是遍历了$.fn.init {0: body, length: 1, selector: "body"}这样的一个伪数组中的类似数组的那一部分。

$.fn.extend({

each: function (func) {

var i=0,

length = this.length;

for (; i<length; i+=1) {

func.call(this[i], this[i], i);

}

return this;

},

});

接受一个回调函数,其第一个参数为dom元素,第二个参数为序号,调用代码如

$('body').each(function(val, index){

console.log(val, index)

});

DOM processor。

文档操作。添加了append,prepend,remove,empty的方法,功用同原版jquery。因为生成的$.fn.init是个包含DOM的伪数组,所以操作中就需要遍历这个数组做append操作,目的是为了让选中的所有DOM元素都append一遍。appendChild为DOM level2方法,从IE6开始就支持。

$.fn.extend({

append: function (child) {

if ($.isString(child)) {

child = $(child)[0];

}

this.each(function(v, k) {

v.appendChild(child);

});

child = null;

return this;

},

});

调用代码如

var element = document.createElement('div');

$('body').append(element);

css

添加了css的方法,功用同原版jquery。现将css规则转为驼峰式,然后利用style属性插入,如 padding: 0px; max-width: 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; font-size: 16px; line-height: 25.6px; box-sizing: border-box !important; word-wrap: break-word !important;">

$.fn.extend({

css: function (cssRules, value) {

//中划线转为驼峰式

var transformHump = function (name) {

return name.replace(/\-(\w)/g, function(all, letter){

return letter.toUpperCase();

});

};

if ($.isString(cssRules)) {

if ($.isUndefined(value)) {

return this[0].style[transformHump(cssRules)];

} else {

this[0].style[transformHump(cssRules)] = value;

}

} else {

for (var i in cssRules) {

this[0].style[transformHump(i)] = cssRules[i];

}

}

return this;

},

});

支持两种写法,参数1和参数2可以互为键值对,或者参数1为一个对象,另外这里只第一个dom元素的css规则生效。调用代码如

//设置第一个body元素的color值

$('body').css('color', '#FFF');

$('body').css({

color: '#FFF',

background: 'green'

});

DOM filter

添加了dom过滤的几个函数,如children、parent、siblings。返回出去的DOM对象会再次被$.fn.init对象包装。

$.fn.extend({

children: function (selector) {

return $(selector, this[0]);

}

});

只对第一个DOM元素生效,调用代码如下:

$('body').children('.class'); //获取第一个body元素下的所有class名为'.class'的元素

attributes

获取属性,实现了attr,removeAttr,addClass,hasClass,removeClass,data,html这几个api,功能和jq相似。 拿addClass举例来说,classList为H5的API,不支持IE9及以下。所有被匹配的dom元素都会被addClass处理。

$.fn.extend({

addClass: function (className) {

this.each(function(v, k) {

//please use 'v.className += className' if you need support IE9.

v.classList.add(className);

});

return this;

},

});

调用方式如下:

$('body').addClass('someClass');

event

事件操作。绑定事件使用on,取消绑定事件使用off,触发事件使用trigger。拿on举例,直接使用了addEventListener监听,不支持IE8及以下。需要支持IE8级以下的话,请使用attachEvent兼容。

$.fn.extend({

on: function (event, func) {

this.each(function(v, k) {

//dom level 2,IE8 not support。

v.addEventListener(event, func, false);

});

return this;

},

});

第一个参数为事件名,第二个参数为回调,调用代码如下:

$('body').on('click', function(e){

console.log('click');

})

effect

其他效果,鉴于动画用css3会更直观,所以这里只实现了show和hide两个方法。所有匹配的DOM元素都会被影响,这里只是简单设置了display属性为block或者none,有待改进。

$.fn.extend({

show: function() {

this.each(function() {

this.style.display = 'block';

});

return this;

},

});

调用代码如下:

$('body').hide();

ajax

抽离jsonp,$.jsonp独立于$.ajax,毕竟jsonp的原理和ajax完全没有关系,如果使用$.ajax的话有些误导别人。 $.ajax和$.jsonp方法最后都会返回一个Promise对象,此Promise参照了这里的方案。

$.ajax只接受一个对象作为参数,并且支持使用promise的写法,调用如下

$.ajax({

url: '/test.json'

})

.then(function (d) {

console.log(d);

return $.ajax({

url: '/test.json'

})

}, function (d) {

console.log(d);

})

.then(function (d) {

console.log(d);

}, function (d) {

console.log(d);

});

$.jsonp({

url: '/test.json',

})

.then(function (d) {

console.log(d);

return $.jsonp({

url: '/test.json'

})

}, function (d) {

console.log(d);

})

.then(function (d) {

console.log(d);

}, function (d) {

console.log(d);

});

注意,本地没法测试ajax函数,如果有需要请在此项目目录下运行node server.js,接着去打开test.html文件的关于ajax的注释,再去localhost:3000/test.html就能看到测试ajax的内容。

cookie

将增删改查cookie操作都用一个函数搞定

$.extend({

cookie: function (cookieName, cookieValue, day) {

var readCookie = function (name) {

var arr,

reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'),

matched = document.cookie.match(reg);

if(arr = matched) {

return unescape(arr[2]);

} else {

return null;

}

};

var setCookie = function (name, value, time) {

var Days = time || 30;

var exp = new Date();

exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);

document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();

};

if (cookieName && cookieValue) {

//set cookie

setCookie(cookieName, cookieValue, day);

} else if (cookieName && $.isNull(cookieValue)) {

//delete cookie

setCookie(cookieName, '', -1);

} else if (cookieName) {

//read cookie

return readCookie(cookieName);

}

}

});

调用代码如下:

//添加cookie,前两个参数为cookie名和值,必填。第三个参数设置cookie有效时常,单位为天,可选。

$.cookie('test', 'content');

//读取cookie,只填第一个参数

$.cookie('test'); //"content"

//删除cookie, 第二个参数填null

$.cookie('test', null);

utils

添加了变量类型判断、时间解析函数、url解析函数、浮点数四舍五入小数位和获取随机位数字符串的辅助函数。

$.extend({

isUndefined: function(obj) {

return obj === void 0;

},

isNull: function(obj) {

return obj === null;

},

isBoolean: function(obj) {

return Object.prototype.toString.call(obj) === '[object Boolean]';

},

isNumber: function(obj) {

return Object.prototype.toString.call(obj) === '[object Number]';

},

isString: function(obj) {

return Object.prototype.toString.call(obj) === '[object String]';

},

isNaN: function(obj) {

return obj !== obj;

},

isFunction: function(obj) {

return typeof obj === 'function';

},

......

});

$.extend({

//$.parseTime(new Date().getTime(), 'YYYY-MM-DD hh:mm:ss')

//result: "2016-08-03 16:14:12"

parseTime: function (timeStamp, format) {

var date = new Date(timeStamp);

var o = {

'M+' : date.getMonth() + 1, //month

'D+' : date.getDate(), //day

'h+' : date.getHours(), //hour

'm+' : date.getMinutes(), //minute

's+' : date.getSeconds(), //second

'S' : date.getMilliseconds() //millisecond

}

if(/(Y+)/.test(format)) {

format = format.replace(RegExp.$1,

(date.getFullYear() + '').substr(4 - RegExp.$1.length));

}

for(var k in o) {

if (new RegExp('('+ k +')').test(format)) {

format = format.replace(RegExp.$1,

RegExp.$1.length == 1 ? o[k] : ('00'+ o[k]).substr((''+ o[k]).length));

}

}

return format;

},

//$.parseUrl(location.href)

//return an object contains the folling info.

parseUrl: function (url) {

var a =  document.createElement('a');

a.href = url;

return {

source: url,

protocol: a.protocol.replace(':',''),

host: a.hostname,

port: a.port,

query: a.search,

params: (function(){

var ret = {},

seg = a.search.replace(/^\?/,'').split('&'),

len = seg.length, i = 0, s;

for (;i<len;i++) {

if (!seg[i]) { continue; }

s = seg[i].split('=');

ret[s[0]] = s[1];

}

return ret;

})(),

file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],

hash: a.hash.replace('#',''),

path: a.pathname.replace(/^([^\/])/,'/$1'),

relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],

segments: a.pathname.replace(/^\//,'').split('/')

};

},

//$.toFixedFloat(15.658, 2)

//result: 15.66

toFixedFloat: function (value, precision) {

var power = Math.pow(10, precision || 0);

return String(Math.round(value * power) / power);

},

//for generate random string

//$.generateRandomAlphaNum(5)

//random result: like "rc3sr".

generateRandomAlphaNum: function (len) {

var rdmString = '';

for (; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));

return rdmString.substr(0, len);

}

});

调用如下:

//参数1是时间戳,参数2是格式,年为Y,月为M,日为D,时h,分m,秒s,毫秒S,注意大小写,多余的位数补0

$.parseTime(new Date().getTime(), 'YYYY-MM-DD hh:mm:ss'); //"2016-08-03 16:14:12"。

//参数为url链接

$.parseUrl(location.href); //返回一个带诸多url信息的对象。

//参数1是目标浮点数,参数2是保留到第几位小数

$.toFixedFloat(15.658, 2); //四舍五入到两位小数:15.66

//参数为生成随机的字符串长度

$.generateRandomAlphaNum(5); //如"rc3sr"

构建一个类jq的函数库的更多相关文章

  1. 一个类似于jq的小型库

    本人写了一个类似于jq的小型库,不过只是写了部分方法而已.并没有jq那么全面,下面就介绍下有哪些方法可以使用 第一个是选择器, 选择器比较简单 只支持ID选择器 $(‘#id_name’) Class ...

  2. 从零开始构建一个Reactor模式的网络库(二)线程类Thread

    线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的. 首先是CurrentThread命名空间,主要是获取以及缓存线程id: #if ...

  3. 从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition

    最近在学习陈硕大神的muduo库,感觉写的很专业,以及有一些比较“高级”的技巧和设计方式,自己写会比较困难. 于是打算自己写一个简化版本的Reactor模式网络库,就取名叫mini吧,同样只基于Lin ...

  4. [转]使用 Angular CLI 和 ng-packagr 构建一个标准的 Angular 组件库

    使用 Angular CLI 构建 Angular 应用程序是最方便的方式之一. 项目目标 现在,我们一起创建一个简单的组件库. 首先,我们需要创建一个 header 组件.这没什么特别的,当然接下来 ...

  5. 自己实现一个类似 jQuery 的函数库

    假如我们有一个需求,需要给元素添加样式类,使用原生的JS很容易搞定. 1 抽取函数 function addClass(node, className){ node.classList.add(cla ...

  6. underscore.js 一个强大的js函数库

    Underscore提供的100多个函数,主要涉及对Collection.Object.Array.Function的操作: Collections(集合) each, map, reduce, re ...

  7. 为开发者准备的 Android 函数库(2016 年版)

    转载:http://www.androidchina.net/5922.html第三方函数库(译者注:包括第三方提供的 SDK,开源函数库)以惊人的方式助力着 Android 开发,借助这些其他开发人 ...

  8. [转载]能不能同时用static和const修饰类的成员函数?

    题目(一):我们可以用static修饰一个类的成员函数,也可以用const修饰类的成员函数(写在函数的最后表示不能修改成员变量,不是指写在前面表示返回值为常量).请问:能不能同时用static和con ...

  9. C++类的成员函数使用的一些小总结

    From: http://blog.csdn.net/xiayefanxing/article/details/7607506 这一阵做项目代码开发的时候,用到了在一个C++文件中使用另一个类的成员函 ...

随机推荐

  1. Shoot the Bullet(ZOJ3229)(有源汇上下界最大流)

    描述 ensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utop ...

  2. The Road to learn React书籍学习笔记(第三章)

    The Road to learn React书籍学习笔记(第三章) 代码详情 声明周期方法 通过之前的学习,可以了解到ES6 类组件中的生命周期方法 constructor() 和 render() ...

  3. 局域网访问不到linux下的tomcat

    问题描述: CentOS安装完成Tomcat后,访问本地:http://localhost:8080/正确.但局域网内无法访问,而且服务器可ping通 经查原因为防火墙开启: [root@localh ...

  4. 2 socket UDP通信

    1 socket套接字  class 对象 In [1]: import socket In [2]: help(socket.socket) class socket(_socket.socket) ...

  5. P1016 旅行家的预算

    P1016 旅行家的预算 题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2 ...

  6. Koa基本使用

    简介 koa 是由 Express 原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的 Web 框架. 使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的 ...

  7. OrCAD创建原理图符号图

    1. 首先创建一个库 2. 右键新创建的库,添加新的器件New Part 3. 修改器件属性 4. 添加引脚 添加完引脚之后如图,其中双击引脚,即可修改引脚名字和序号 5. 添加符号的外形 添加完外形 ...

  8. mcrouter facebook 开源的企业级memcached代理

    原文地址:https://code.facebook.com/posts/296442737213493/introducing-mcrouter-a-memcached-protocol-route ...

  9. APP功能性测试-3

    定义:兼容测试就是指软件在特定的硬件平台,不同的应用软件之间,不同的操作系统平台上,不同的网络等环境中是否能够正常的运行的测试  (会不会产生不兼容) 兼容性测试的作用 进一步提高产品质量 和其他软件 ...

  10. 牛客 小a与星际探索

    链接:https://ac.nowcoder.com/acm/contest/317/C来源:牛客网 小a正在玩一款星际探索游戏,小a需要驾驶着飞船从1号星球出发前往n号星球.其中每个星球有一个能量指 ...