模擬jQuery框架,利用原生的js技術,封裝一個js框架,以加深對jQuery的經常使用api的使用和麪向對象原理的理解;
一:結構部分
首先利用閉包,構造一個自執行函數,而後利用選擇器函數Sizzle,獲取dom元素;其後設置入口函數jQuery,返回一個F的實例;
而後對jQuery.prototype進行設置;其後修改F的原型指向jQuery的原型,最後暴露出去兩個接口$和jQuery;
二:jQuery.fn.extend = jQuery.extend = function(){}
經過向jQuery的原型和jQuery上添加一個extend方法(詳見下面代碼extend部分);
能夠實現擴展工具類方法和dom操做、css操做類的方法;
jQuery.fn.extend(object); 對jQuery.fn即jQuery.prototype
得擴展,就是爲jQuery類添加「成員函數」。jQuery類的實例能夠使用這個「成員函數」。
代碼以下,歡迎指正
(function (window) { //僞數組借用數組的push和splice方法 var arr = [];//Array.prototype; var push = arr.push; var splice = arr.splice; //jQuery.extend()工具類方法中的type部分代碼預處理 var toString = Object.prototype.toString; var types = "Number,String,Boolean,Null,Undefined,Array,Object,Function,Math,Date,RegExp".split(","); var class2type = {}; for (var i = 0; i < types; i++) { var type = types[i]; class2type["[object " + type + "]"] = type.toLowerCase(); } /** * 獲取dom元素的僞數組nodelist 不考慮兼容性問題; * @param selector * @returns {NodeList} * @constructor */ var Sizzle = function (selector) { return document.querySelectorAll(selector); } /** * 設置入口函數,返回F的實例對象 * @param selector * @returns {*} */ function jQuery(selector) { return jQuery.fn.F(selector); } /** * jQuery.prototype設置 * @type {{constructor: jQuery, F: Function}} */ jQuery.fn = jQuery.prototype = { constructor: jQuery, version: "0.0.1", F: function (selector) { if (jQuery.isString(selector)) { if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) { //eg:$("<input>"); var div = document.createElement("div"); div.innerHTML = selector; //for(var i =0;i<div.childNodes.length;i++){ // var child = div.childNodes[i]; // push.call(this.child); //} push.apply(this, div.childNodes); } else { //eg:$("div") splice.call(this, 0, this.length); var elements = Sizzle(selector); push.apply(this, elements); } } else if (selector.nodeType) { //鴨式辨型思想 //this[0] = selector; //this.length = 1; push.call(this, selector); } else if (selector.version === this.version) { return selector; } return this;//實現鏈式編程 } } /** * extend方法 * @type {Function} */ jQuery.fn.extend = jQuery.extend = function () { var argLen = arguments.length; var arg0 = arguments[0]; var sources = []; var target; if (argLen === 0) return this; if (argLen === 1) { sources.push(arg0); target = this; } else { //for(var i=1;i<argLen;i++){ // sources.push(arguments[i]); //} push.apply(sources, arguments); target = arg0; } for (var i = 0; i < sources.length; i++) { var source = sources[i]; for (var key in source) { target[key] = source[key]; } } return target; } /** * 工具類方法,添加到jQuery中,使用$.方法名()調用 */ jQuery.extend({ //判斷數據類型 type: function (data) { return class2type[toString.call(data)]; }, //判斷是否是字符串 isString: function (str) { return jQuery.type(str) === "string"; }, //判斷是否是函數 isFunction: function (fn) { return jQuery.type(fn) === "function"; }, //拋出異常 error: function (msg) { throw new Error(msg); }, //去除字符串兩邊的空格 trim: function (str) { return str.replace(/^\s+|\s+$/g, ""); }, //遍歷(數組的遍歷或者對象的遍歷) each: function (array, callback) { var len = array.length; var i; if (typeof len === "number" && len >= 0) { for (i = 0; i < len;) { if (callback.call(array[i], i, array[i++]) === false) { break; } } } else { for (i in array) { if (callback.call(array[i], i, array[i]) === false) { break; } } } } }) //jQuery.fn中的each方法:這樣F的實例,即jQuery的對象擁有的each方法 jQuery.fn.extend({ each: function (callback) { jQuery.each(this, callback); return this; } }) //css模塊 jQuery.fn.extend({ css: function () { var argLen = arguments.length; var arg0 = arguments[0]; var arg1 = arguments[1]; if (argLen === 0) return this; if (argLen === 1) { if (jQuery.isString(arg0)) { //表示獲取第一個dom元素的css樣式 var firstDom = this[0]; return window.getComputedStyle(firstDom, null)[arg0]; } else { //是一個對象的時候表示設置多個樣式 //return this.each(function(){ // var dom = this; // jQuery.each(arg0,function(styleName,styleValue){ // dom.style[styleName] = styleValue; // }) //}) return this.each(function () { jQuery.extend(this.style, arg0); }); } } else { //傳遞兩個參數;設置單個css樣式 return this.each(function () { this.style[arg0] = arg1; }) } }, //顯示 show: function () { return this.css("display", "block"); }, //隱藏 hide: function () { return this, css("display", "none"); }, //切換顯示和隱藏 toggle: function () { return this.each(function () { var $this = $(this); $this.css("display") === "none" ? $this.show() : $this.hide(); }) } }) //屬性模塊 jQuery.fn.extend({ attr: function (arg0, arg1) { var argLen = arguments.length; if (argLen === 0) return this; if (argLen === 1) { if (jQuery.isString(arg0)) { //獲取第一個dom元素的屬性值 var firstDom = this[0]; return firstDom.getAttribute(arg0); } else { //設置一個對象的屬性 return this.each(function () { var dom = this; jQuery.each(function (className, classValue) { dom.setAttribute(className, classValue); }) }) } } else { //兩個參數;設置屬性 return this.each(function () { this.setAttribute(arg0, arg1); }) } }, hasClass: function (className) { //遍歷,只要有一個dom元素含有className這個類名就返回true var isExist = false; this.each(function () { if ((" " + this.className + " ").indexOf(" " + className + " ") > -1) { isExist = true; return false; } }) return isExist; }, addClass: function (className) { var classNames = className.split(" "); return this.each(function () { for (var i = 0; i < classNames.length; i++) { var singleClassName = className[i]; if (!$(this).hasClass(singleClassName)) { this.className += " " + singleClassName; } } }) }, removeClass: function (className) { if (!className) { //刪除所有類名 return this.each(function () { this.className = ""; }) } else { //刪除一個或者多個類名 var classNames = className.split(" "); return this.each(function () { var domClassName = " " + this.className + " "; for (var i = 0; i < classNames.length; i++) { var singleClassName = " " + classNames[i] + " "; domClassName = domClassName.replace(singleClassName, " "); } this.className = $.trim(domClassName); }) } } }) //dom操做方法模塊 jQuery.fn.extend({ appendTo: function () { var $parent = $(arguments[0]); return this.each(function () { var child = this; $parent.each(function () { var parent = this; parent.appendChild(child.cloneNode(true)); }) }) }, prependTo: function () { var $parent = $(arguments[0]); return this.each(function () { var child = this; $parent.each(function () { var parent = this; parent.insertBefore(child.cloneNode(true), parent.firstChild); }) }) }, append: function () { var $parent = $this; var $child = $(arguments[0]); $child.appendTo($parent); return this; }, prepend: function () { var $parent = $this; var $child = $(arguments[0]); $child.prependTo($parent); return this; }, remove: function () { return this.each(function(){ this.parentNode.removeChild(this); }) }, html: function (html) { if (html === undefined) { //返回第一個dom元素的html var firstDom = this[0]; return firstDom.innerHTML; } //若是爲null或者其餘參數時候 return this.each(function () { this.innerHTML = html; //this.innerHTML = html===null?"":html; }) }, text: function (text) { if (html === undefined) { var str = ""; this.each(function () { str += this.innerText; }) return str; } return this.each(function () { this.innerText = text; }) } }) //事件模塊 jQuery.fn.extend({ on:function(type,callback){ return this.each(function(){ this.addEventListener(type,callback); }) } }) var eventTypes = "click dblclivk keydown keyup mousedown mouseup mouseout mouseenter mouseleave load".split(" "); for(var i =0;i<eventTypes.length;i++){ var eventType = eventTypes[i]; $.fn[eventType] = (function(){ var type = eventType; return function(callback){ return this.on(type,callback); } })() } //F的實例 = jQuery的實例 jQuery.fn.F.prototype = jQuery.fn; //暴露出去兩個接口 window.$ = window.jQuery = jQuery;})(window)