这个版本的JQuery是对上一个版本的JQuery,使用了require.js进行了二次封装,基本上把前面的每一个框架封装成为一个单独的模块,最终的目录结构如下:
由于代码量和目录比较多,这个封装好的代码和目录已经全部上传到GitHub上面,需要的同学可以前往下载哈。
https://github.com/xiugangzhang/JavaScript-Xframe
【main.js】这个是模块文件的主入口函数
/**
* @Desc : 主要的功能模块展示
* @Author : xiugang
* @Time : 20180722
*/
//配置项,在主入口js文件配置即可,其他模块都可调用paths模块
require.config({
//所有的require依赖根路径都是baseUrl
baseUrl: './js',
//路径可以是数组,如果第一个加载成功则结束,否则加载后面的文件
paths:{
'xframe' : 'xframe', // 主框架模块
'basis': 'basisModule', // 基础模块
'string': 'stringModule', // 字符串方法扩展模块
'array' : 'arrModule', // 数组方法扩展模块
'func' : 'funcModule', // AOP模块
'domReady' : 'domReadyModule', // 异步加载模块
'dom' : 'domModule', // DOM元素操作模块
'css' : 'cssModule', // CSS样式模块
'attr' : 'attrModule', // 属性模块
'content' : 'contentModule', // 内容模块
'event' : 'eventModule', // 事件模块
'select' : 'selectModule', // 选择模块
'animate' : 'animateModule', // 动画模块
'cache' : 'cacheModule' // 缓存模块
}
});
【index.html】这个是自己封装完毕之后对每一个框架进行的功能测试文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#map{
width: 250px;
height: 250px;
background: #0da357;
position: absolute;
}
#game{
position: absolute;
width: 350px;
height: 350px;
top: 280px;
background: blue;
}
</style>
</head>
<body>
<div id="map">123456789</div>
<div id="game">789456123</div>
<script data-main="main" src="require.min.js"></script>
<script>
/**
* 在这里导入需要使用的模块,以供下面调用的时候来使用
*/
require([
'js/domReadyModule',
'js/xframe',
'js/stringModule',
'js/arrModule',
'js/funcModule',
'js/basisModule',
'js/eventModule',
'js/cssModule',
'js/selectModule',
'js/attrModule',
'js/contentModule',
'js/domModule',
'js/animateModule',
'js/cacheModule'
], function (domReadyModule,
xframe,
stringModule,
arrModule,
funcModule,
basisModule,
eventModule,
cssModule,
selectModule,
attrModule,
contentModule,
domModule,
animateModule,
cacheModule
) {
console.log(xframe);
console.log('1234560@{name}'.formateString({name: 'xiuxiu'}), 'redcolor'.camelCase());
var arr = new Array(1, 2, 5);
console.log(arr.random(3));
console.log(funcModule);
console.log($.isArray(new Array()));
console.log(domReadyModule);
// 直接获取一个类似于JQuery的对象
console.log($('#map'));
$('#map').on('click', function () {
this.style.background = 'red';
console.log($.getEvent());
});
//console.log($('#map').getEvent());
domReadyModule.onReady(function (mes) {
console.log('load ok', mes); // ok
});
console.log(eventModule);
console.log(cssModule);
$(function (mes) {
console.log(mes); //ok
})
// 事件框架测试
var fun = function () {
console.log('DOM load 完毕!');
}
$(fun);
console.log(selectModule);
// 选择框架测试
var res = $.$id('map');
console.log(res);
// CSS样式框架测试
console.log($('#map').css('width'));
console.log($('#map').css('background', 'pink'));
// 属性框架测试[20180721测试-----------------------------]
console.log(attrModule);
res = $('#map');
console.log($('#map').addClass('name'));
$('#map').addClass('age');
$('#map').attr('name', 18);
// 内容框架测试
console.log($('#map').html('<a href="main.js">7892121212</a>>'));
console.log(contentModule);
// DOM框架测试
console.log(domModule);
var dom = $.create('div', {name: "xiuxiu"}, '<a>456789</a>');
dom.appendTo(('#map'));
console.log(dom);
var dom1 = $.create('span', {age: "22"}, '<a href="require.min.js">456789</a>');
dom.append(dom1);
// 动画框架测试
console.log(animateModule.Animate);
$('#map').on('click', function () {
// $$.animate('#sun', {left: width}, 7000);
$.animate('#map', {left: 550, top: 550}, 7000)
});
//$('#game').css('left', '800px');
document.getElementById('game').style.left = '800px';
// backgroundColor
console.log('background-color'.camelize());
// 缓存框架的测试
// 本地临时存储的实现测试
// set
// 使用方式,需要先指定需要使用的功能模块名称,然后再指定相应的函数功能
// 1. 添加数据
cacheModule.cache.add('name', '52tech');
// 2.获取数据
var res = cacheModule.cache.get('name');
// 3. 修改数据
res = cacheModule.cache.update('name', 'xiuxiu');
res = cacheModule.cache.get('name');
// 3. 删除数据
res = cacheModule.cache.delete('name');
// 4. 判断本地是否存在某一个数据
res = cacheModule.cache.isExist('name');
// cookie框架测试
// 1. 添加Cookie信息 name, value, days, path
// 主要问题: 如果直接添加内容的话,出现的问题是,存储的是这个内容,但是存储进cookie本地存储的就不是了
// 注意当前的这种方式是不支持在字符串中有分号的情形
cacheModule.cookie.setCookie('script5', '<script>alert(2)<\/script>', 10, '/');
// 2. 获取本地存储的cookie信息
res = cacheModule.cookie.getCookie('script3');
document.body.innerHTML = '<script>alert("ok")<\/script>';
// 3. 修改本地的Cookie信息
res = cacheModule.cookie.deleteCookie('script5', '/');
// 清空所有的COOkie信息
// "name&=xiuxiu& name=xiuxiu; script=<script>alert(2); script2=<script>alert(2); script3=<script>alert(2); script3&=<script>alert(2); script4&=<script>alert(2); a&=<a>alert(2)</a>&"
cacheModule.cookie.clearAllCookies();
// 设置Cookie信息
cacheModule.cookie.setCookie('json', '<a href="www.52tech.tech" onclick="javascript:void 0"></a>>', 10, '/');
res = cacheModule.cookie.getCookie('json');
console.log(res);
// localstorage本地存储功能的测试
// 1. 设置storage信息
$.storage.set('name', 'xiuxiu');
// 2. 获取信息
res = $.storage.get('name');
// 3. 修改信息
$.storage.remove('name');
// 4. 清空所有的本地存储信息
$.storage.clear();
});
</script>
</body>
</html>
【JS文件夹】:这个文件夹就是自己抽象出来的一些功能模块,这也是第一次进行的模块封装,封装的也比较粗糙,但是基本的功能还是实现了,大家可以一起交流哈。
下面的这个就是主框架Xframe模块:
/**
* 自定义一个基本的模块:类似于JQuery的基础模块,主要用于实现一个链式访问的功能
*/
define(function () {
// 返回的必须是一个对象
// 主框架: 只做一件事,就是用于获取所有的元素集合
// 定义一个Xframe对象,后面就是他的构造函数
var xframe = function (selector, context) {
// 为了使得后面的函数this始终指向的是xframe框架,这里需要修改函数内部this的指向
return this.init.apply(this, [selector, context]);
};
// 定义一个初始化函数,用于初始化获取所有的元素集合
// 只要用户使用了类似于JQuery中的选择元素的方法,就开始选择一个元素集合
// 这里的核心功能:实际上是为了使用一个伪数组实现一个类似于JQuery中的链式访问的功能
xframe.prototype.init = function (selector, context) {
// 开始构建一个伪数组:{1 : list[0], 2 : list[1], , , , length : list.length}
this.length = 0;
// 针对没有参数的处理方式
if (typeof selector === 'undefined') {
return this;
}
if (typeof selector === 'string') {
var nodeList = (context || document).querySelectorAll(selector);
this.length = nodeList.length;
for (var i = 0, len = this.length; i < len; i++) {
this[i] = nodeList[i];
}
} else if (selector.nodeType) {
// 如果获取的是一个元素节点,文本节点,或者属性节点的话
this[0] = selector;
this.length++;
}
// 为了可以支持链式访问必须把这个this对象返回出去
return this;
};
// 使用双对象法则继续暴露出去一个对象,进行对象的二次封装
// 【双对象法则的使用】
var $$ = function (selector, context) {
var self = this;
// 这里使用一个简单的异步加载机制,等待所有的DOM元素执行完毕之后再开始继续向下执行
if (typeof selector === 'function') {
// selector就是DOM元素加载完毕之后的继续向下执行的回调函数
//w.onload = selector;
// 使用自己定义的函数来实现一个domReady(ele, fn)的功能, 默认就是整个document加载完毕之后才会继续向下执行
// 使用call的时候第一个参数不能少哈, 否则传过去的参数就是空的
//$$.onDOMReady.call(this, selector);
// 使用apply传参的时候必须传递的是一个数组类型
//$$.onDOMReady.apply(this, [selector]);
// 如果使用bind的话(只是会修改调用函数内部的指向, 但是不会调用)
// bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。【只是会返回一个函数, 但还是不会立即调用】
require(['js/domReadyModule'], function (domReadyModule) {
var func = domReadyModule.onReady.bind(self, selector);
// 调用使用bind()方法返回的函数
func();
});
} else {
// 如果不是一个函数的话
return new xframe(selector, context);
}
}
// 添加一个extend方法, 用于扩充一个对象的方法, 扩展向一个类中拷贝方法
$$.extend = function () {
// 这里需要分为两种情况:
// 1. 如果传过来的是一个参数的话,就相当于是给xframe对象添加方法
// 2. 如果是两个参数的话,就相当于是给一个类扩充方法(把一个函数的方法拷贝到另一个类中去)
var len = arguments.length,
target = null, // target 用来存储需要把方法拷贝进去的目标函数
i = 1, // 初始化变量i, 表示需要开始遍历的起始位置标记
key; // 为了防止定义太多的局部变量,可以把后面需要用到的所有局部变量事先在前面定义好
if (len === 0) {
return;
} else if (len === 1) {
// 给xrame对象添加方法
target = xframe.prototype;
i--;
} else {
// 两个参数的话,那么第一个参数就是我需要拷贝新的方法进去的目标对象
// 如果是两个参数的话:就不需要修改变量i的值了, 直接从第一个位置开始,拿到第一个参数后, 把第二个参数的方法全部拷贝给第一个对象
// 注意: 这里有可能也是三个参数或者是多个参数, 因此也可以吧后面的好几个对象的属性或者方法添加给第一个对象
target = arguments[0];
}
// 确定好了target 这个目标对象以后,开始遍历原始对象那个source,把source里面的方法全部都拷贝到这个target对象里面
for (; i < len; i++) {
// 这里实际上在遍历一个json对象,json对象的每一项实际上就是一个属性或者方法
// 遍历每一个arguments, 获取每一个参数的属性, 然后把这个属性拷贝到原始的对象
for (key in arguments[i]) {
target[key] = arguments[i][key];
}
}
return target;
}
var w = window;
// 为了把主框架里面的局部变量暴露出去供其他模块使用
w.xframe = w.$ = $$;
// 把当前的这个对象返回出去即可
return $$;
});
basisModule.js
/**
* @Desc : 主要的功能模块展示
* @Author : xiugang
* @Time : 20180722
*/
/**
* 定义一个基础框架,这里的模块名字必须和文件的名字一样
*/
define(['js/xframe'], function (xframe) {
// 数据类型检验模块
var api = {};
// 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。
// 只关注对象的行为,不关注对象本身面向接口编型 ,而不是面向实现编程,是设计模式中最重要的思想。
// 【理解】:一个对象有效的语义,不是由集成自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定的!!!
api.isNeedChainedAccess = function(){
}
api.isNotNeedChainedAccess = function(){
/*数据类型检验*/
xframe.extend(xframe, {
// 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。
// 只关注对象的行为,不关注对象本身面向接口编型 ,而不是面向实现编程,是设计模式中最重要的思想。
// 【理解】:一个对象有效的语义,不是由集成自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定的!!!
isNumber: function (val) {
// 如果这个数字是有限的话, 而且是数字类型
return (typeof val === 'number' && isFinite(val)) && (Object.prototype.toString.call(val) === '[object Number]');
},
/***
* 判断一个变量是不是Boolean类型
* @param val
* @returns {boolean}
*/
isBoolean: function (val) {
return (typeof val === 'boolean') && (Object.prototype.toString.call(val) === '[object Boolean]');
},
/**
* 判断一个变量是不是字符串类型
* @param val
* @returns {boolean}
*/
isString: function (val) {
return (typeof val === 'string') && (Object.prototype.toString.call(val) === '[object String]');
},
/**
* 判断一个变量是不是undefined
* @param val
* @returns {boolean}
*/
isUndefined: function (val) {
// oid 0 is a correct and standard way to produce undefined.
return (val === void 0) || (typeof val === 'undefined') && (Object.prototype.toString.call(val) === '[object Undefined]');
},
/**
* 判断一个变量是不是为空
* @param val
* @returns {boolean}
*/
isNull: function (val) {
return (val === null) && (Object.prototype.toString.call(val) === '[object Null]');
},
/**
* 检测
* @param obj
* @returns {*}
*/
isNaN: function (val) {
// 只要这个数字通过判断是不是和他自身相同或者使用typef的方式去检测
return val !== val;
},
/**
* 判断一个变量是不是一个对象类型
* @param val
* @returns {boolean}
*/
isObject: function (val) {
if (val !== null && val !== undefined) {
if ((typeof val === 'object') && (Object.prototype.toString.call(val))) {
return true;
}
}
return false;
},
/**
* 判断一个对象是不是数组对象
* @param val
* @returns {boolean|void|string}
*/
isArray: function (val) {
// 判断上不是一个数组的先判断这个数组对象是不是为空, 因为如果val为空的话,就是val.constructor这个属性实际上是没有的,error
if (val !== null || typeof val !== "undefined") {
// 注意在使用constructor判断数据类型的时候比较的实际上是他的原型对象的constructor属性, 这个属性指向的实际上是这个变量的原型对象
return (val.constructor === Array) && (Object.prototype.toString.call(val) === '[object Array]');
}
return false;
}
});
}
// 调用函数,实现生效
api.isNeedChainedAccess();
api.isNotNeedChainedAccess();
return api;
});
stringModule.js
/**
* @Desc : 主要的功能模块展示
* @Author : xiugang
* @Time : 20180722
*/
/**
* 这个模块是用来出来原型对象的方法扩展的,主要用于实现一个String,Array,Function等内置函数方法的扩展
*/
define(function () {
// 定义一个关于字符串处理的API接口
var api = {
}
api.isNeedChainedAccess = function(){
}
api.isNotNeedChainedAccess = function(){
// str = 'name: @(name), age:@(age)'
// data = {name : 'xiugang', age : 18}
/**
* 实现一个简单的数据绑定
* @param str
* @param data
* @return {*}
*/
String.prototype.formateString = function (data) {
return this.replace(/@\((\w+)\)/g, function (match, key) {
// 注意这里找到的值必须返回出去(如果是undefined,就是没有数据)
// 注意:判断一个值的类型是不是undefined,可以通过typeof判断
console.log(typeof data[key] === 'undefined');
return data[key] === 'undefined' ? '' : data[key];
});
}
/**
* 去掉坐标的空格
* @param str
* @return {*}
*/
String.prototype.ltrim = function () {
return this.replace(/^\s*/g, '');
}
/**
* 去掉右边的空格
* @param str
* @return {*}
*/
String.prototype.rtrim = function () {
return this.replace(/\s*$/g, '');
}
/**
* 去掉两边的空格
* @param str
* @return {*}
*/
String.prototype.trim = function () {
return this.replace(/(^\s*)|(\s*$)/g, '');
}
// red===>Red
/**
* 将第一个字母小写,其他字母大写
* @param str
* @return {*}
*/
String.prototype.camelCase = function () {
// .*?是非贪婪的匹配,点可以匹配任意字符,星号是前边的字符有0-n个均匹配,问号是则是0-1;
// (^\w{1}): 用于匹配第一个首字母
// (.*):用于匹配任意个的前面的字符
// - param 1: 匹配到的字符串
// - param 2: 匹配的的子字符串
// - param 3: 匹配的子字符串
// - param 4: 匹配到的字符串在字符串中的位置
// - param 5: 原始字符串
return this.replace(/(^\w{1})(.*)/g, function (match, g1, g2) {
return g1.toUpperCase() + g2.toLowerCase();
});
}
/**
* @param 作用是将连字符类的css属性值,转换成驼峰写法。
* 将background-color转换为backgroundColor
*/
String.prototype.camelize = function(){
// \w 表示 匹配包括下划线的任何单词字符
return this.replace(/-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
}
/**
* 将一个字符串的下划线转换为中划线
* @param str
* @return {*}
*/
String.prototype.dashString = function () {
// 这里面的this实际上指向的就是我们自己定义的一个变量字符串
return this.replace(/\_/g, '-');
}
/**
* 检测一个字符串是不是为空
* @return {boolean}
*/
String.prototype.isEmpty = function () {
return this.length === 0;
}
/**
* 判断字符串是不是包含一个字符串
* @param target
* @return {boolean}
*/
String.prototype.contains = function (target) {
// 只要这个indexOf的下标不是-1的话,就说明包含这个目标字符串,否则的话就是不包含
// indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置,如果没找到的话,就返回-1
return this.indexOf(target) !== -1;
}
/**
* 对一个字符串中的特殊字符进行转义
* @return {string}
*/
String.prototype.escapeHTML = function () {
/*显示结果 描述 实体名称 实体编号
空格  
< 小于号 < <
> 大于号 > >
& 和号 & &
" 引号 " "
' 撇号 ' (IE不支持) '
¢ 分 ¢ ¢
�0�5 镑 £ £
�0�6 日圆 ¥ ¥
€ 欧元 &euro
* **/
// 先进行字符串分割, 得到一个数组
var strArr = this.split('');
for (var pos = 0, l = strArr.length, tmp; pos < l; pos++) {
// 拿到数组中的每一个元素
tmp = strArr[pos];
// 对字符串中的每一个元素进行判断, 如果是特殊字符的话就进行处理
switch (tmp) {
// pos始终为1, 表示要替换的项是1项
case '<':
replaceArr(strArr, pos, '<');
break;
case '>':
replaceArr(strArr, pos, '>');
break;
case '\'':
replaceArr(strArr, pos, ''');
break;
case '\"':
replaceArr(strArr, pos, '"');
break;
case '&':
replaceArr(strArr, pos, '&');
break;
default:
;
}
}
// join() 方法用于把数组中的所有元素放入一个字符串。
return strArr.join('');
// 专门用于替换掉数组中的元素
/**
* 替换数组中指定的项
* @param arr
* @param pos
* @param item
* @return {*}
*/
function replaceArr(arr, pos, item) {
// Splice: splice主要用来对JS中的数组进行操作,包括删除,添加,替换等,原来的数组会被改变
// 删除数据:array.splice(index,num),返回值为删除内容,array为结果值。index为起始项,num为删除元素的的个数。
// 插入数据:array.splice(index,0,insertValue),index要插入的位置,insertValue要插入的项
// 替换数据:array.splice(index,num,insertValue),index起始位置,num要被替换的项数,insertValue要替换的值
return arr.splice(pos, 1, item);
}
}
/**
* 忽略HTML中的一些内置的特殊字符
* @return {string}
*/
String.prototype.escapeHTML = function () {
return Array.prototype.slice.call(this).join('').replace(/$/g, '&')
.