jQuery封装心得

闭包


// 立刻执行函数
(function($){
    
    

    // code

})(jQuery);

形参: $
实参: jQuery
1、jQuery借助了沙箱模式,其实整个jQuery包中的代码就是一个自执行函数,并且把window对象作为参数传递了过去。
2、.jQuery函数只是一个工厂,真正的构造函数时jQuery.fn.init( )
3、把init的原型对象替换为jQuery.fn,其实也就是替换为了jQuery这个函数自己的原型对象,也就是jQuery.prototype,这么做的目的是为了实现插件机制,让外界可以通过jQuery方便的进行扩展。

 //工厂
    function jQuery(selector){
    
    
        return new jQuery.fn.init(selector);
    }

jQuery原型替换和给原型提供一个简写方式

 jQuery.fn = jQuery.prototype = {
    
    
        constructor : jQuery,
        version : '1.0.0',
        toArray : function(){
    
    
            return [].slice.call(this);
        },
        each : function(fun){
    
    
            return jQuery.each(this, fun);
        },
        get : function(index){
    
    
            if(index == undefined || index == null){
    
    
                return this.toArray();
            }
            if(index >=0 && index < this.length){
    
    
                return this[index];
            }
            if(index >= -(this.length - 1) && index < 0){
    
    
                return this[this.length + index];
            }else{
    
    
                return undefined;
            }
        }
    };

给jQuery的构造函数和原型对象,都添加一个extend方法,该方法用来拓展对象功能

jQuery.extend = jQuery.fn.extend = function(obj){
    
    
        for(var key in obj){
    
    
            this[key] = obj[key];
        }
    };

给jQuery添加静态方法

	;(function($){
    
    
	$.fn.extend({
    
    	
 	"loading":function(msgObj){
    
    		
	ui_loading = this; 
	ui_loading.show().html('<span class="ui-loading-text">'+(msgObj&&msgObj.msg1)? msgObj.msg1:'加载中...'+'</span>').before('<div class="ui-loading-cover"></div>');		 	 
	longTip = self.setTimeout(LongTip, 5000);
	function LongTip(){
    
    
		ui_loading.find("span.ui-loading-text").html((msgObj&&msgObj.msg2)? msgObj.msg2:'仍在加载中...');
	}		
     },
     "close":function () {
    
    
           // 关闭插件的代码
     }	 
	});
	})(jQuery);

  jQuery.extend({
    
    
    //去除首尾空格
    trim: function (str) {
    
    
      if (!str) {
    
    
        return str;
      } else if (str.trim) {
    
    
        return str.trim();
      }
      return str.replace(/^\s+|\s+$/, "");
    },
    //判断是不是HTML标签片段
    isHTML: function (str) {
    
    
      //null、undefined、0、NaN、false、''
      if (!str) {
    
    
        return false;
      }
      //<p>   <span>
      //如果字符串的第一个字母是<,最后一个字母是>,并且length >= 3,就可以认为是html片段。
      if (
        str.charAt(0) == "<" &&
        str.charAt(str.length - 1) == ">" &&
        str.length >= 3
      ) {
    
    
        return true;
      }
      return false;
    },
    isString: function (str) {
    
    
      return typeof str === "string";
    },
    isNumber: function (num) {
    
    
      // return typeof num === 'number' && isFinite(num); //isFinite(4/0) : false
      return Object.prototype.toString.call(num) === "[object Number]";
    },
    isBool: function (arg) {
    
    
      // return typeof num === 'number' && isFinite(num); //isFinite(4/0) : false
      return Object.prototype.toString.call(arg) === "[object Boolean]";
    },
    isObj: function (obj) {
    
    
      return Object.prototype.toString.call(obj) === "[object Object]";
    },
    isArray: function (arr) {
    
    
      return Object.prototype.toString.call(arr) === "[object Array]";
    },
    //判断是不是伪数组
    isLikeArray: function (likeArr) {
    
    
      //1.具有length属性
      //2.要么没成员 arr.length === 0,要么一定存在key为arr.length - 1 的成员(没办法对所有的key都做判断)
      //3.对象的__proto__  != Array.prototype
      return (
        "length" in likeArr &&
        (likeArr.length === 0 || likeArr.length - 1 in likeArr) &&
        likeArr.__proto__ != Array.prototype
      );
    },
    isFunction: function (fun) {
    
    
      return Object.prototype.toString.call(fun) === "[object Function]";
    },
    //each(index, element)迭代函数
    each: function (obj, fun) {
    
    
      if (jQuery.isFunction(fun)) {
    
    
        if (jQuery.isArray(obj) || jQuery.isLikeArray(obj)) {
    
    
          for (var i = 0; i < obj.length; i++) {
    
    
            fun.call(obj[i], i, obj[i]);
          }
        } else {
    
    
          for (var key in obj) {
    
    
            fun.call(obj[key], key, obj[key]);
          }
        }
      }
      return obj;
    },
  });

AJAX模块

jQuery.extend({
    
    
    ajax: function (jsonData) {
    
    
      var xhr = null;
      if (window.XMLHttpRequest) {
    
    
        //标准的浏览器
        xhr = new XMLHttpRequest();
      } else {
    
    
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
      }
      //配置参数
      var type = jsonData.type == "get" ? "get" : "post";
      var url = "";
      if (jsonData.url) {
    
    
        url = jsonData.url;
        if (type == "get") {
    
    
          url += "?" + jsonData.data;
        }
      }
      var flag = jsonData.asyn == "true" ? "true" : "false";
      xhr.open(type, url, flag); //指定回调函数
      xhr.onreadystatechange = function () {
    
    
        if (this.readyState == 4 && this.status == 200) {
    
    
          //请求成功
          if (typeof jsonData.success == "function") {
    
    
            var d =
              jsonData.dataType == "xml" ? xhr.responseXML : xhr.responseText;
            jsonData.success(d);
          }
        } else {
    
    
          //请求失败
          if (typeof jsonData.failure == "function") {
    
    
            jsonData.failure();
          }
        }
      }; //发送请求
      if (type == "get") {
    
    
        xhr.setRequestHeader("If-Modified-Since", "0");
        xhr.send(null);
      } else if (type == "post") {
    
    
        xhr.setRequestHeader(
          "Content-Type",
          "application/x-www-form-urlencoded"
        );
        xhr.send(jsonData.data);
      }
    },
  });

获取样式

jQuery.extend({
    
    
    getStyle: function (dom, style) {
    
    
      //判断浏览器是否支持主流浏览器获取样式的api
      if (window.getComputedStyle) {
    
    
        return window.getComputedStyle(dom)[style];
      } else {
    
    
        //IE8浏览器兼容处理
        return dom.currentStyle[style];
      }
    },
  });

事件注册模块

jQuery.fn.extend({
    
    
    on: function (type, fun) {
    
    
      if (jQuery.isString(type) && jQuery.isFunction(fun)) {
    
    
        this.each(function (i, e) {
    
    
          if (e.addEventListener) {
    
    
            //主流浏览器支持的方式
            e.addEventListener(type, fun);
          } else {
    
    
            e.attachEvent("on" + type, fun); //IE浏览器支持的方式
          }
        });
      }
      return this;
    },
    click: function (fun) {
    
    
      this.on("click", fun);
      return this;
    },
  });

属性操作模块

 jQuery.fn.extend({
    
    
    attr: function (attr, val) {
    
    
      /*
       * 实现思路:
       * 1、判断attr是不是字符串或者对象,不是直接return this。
       * 2、如果是字符串,那么继续判断arguments的length
       * 3、length为1,则获取第一个元素指定的属性节点值返回
       * 4、length>=2,则遍历所有元素,分别给他们设置新的属性节点值( setAttribute )
       * 5、如果不是字符串(是对象),那么遍历这个对象,得到所有的属性节点值,
       * 然后遍历所有的元素,把所有的属性节点分别添加到这些元素中。
       * 6、return this。
       * */
      // 不是字符串也不是对象,直接返回this
      if (!jQuery.isString(attr) && !jQuery.isObject(attr)) {
    
    
        return this;
      }
      // 如果是字符串
      if (jQuery.isString(attr)) {
    
    
        // 如果length为1,则直接返回第一个元素的属性节点值
        if (arguments.length === 1) {
    
    
          return this.get(0).getAttribute(attr);
        }
        // 如果length为多个(2和及2个以上)
        // 则遍历所有的元素,分别设置属性节点值
        else {
    
    
          for (var i = 0, len = this.length; i < len; i++) {
    
    
            this[i].setAttribute(attr, val);
          }
        }
      }
      // 如果是对象
      // 遍历这个对象,和所有的元素,分别添加遍历到的属性节点值
      else {
    
    
        // 遍历得到所有的属性节点和属性节点值
        for (var key in attr) {
    
    
          // 遍历得到所有的元素
          for (var i = 0, len = this.length; i < len; i++) {
    
    
            this[i].setAttribute(key, attr[key]);
          }
        }
      }
      // 链式编程
      return this;
    },
  });

样式操作模块css()

 jQuery.fn.extend({
    
    
    css: function (name, val) {
    
    
      if (arguments.length === 1) {
    
    
        //只有1个参数,并且参数是字符串,就是要读取元素的样式值
        if (jQuery.isString(name)) {
    
    
          return jQuery.getStyle(this[0], name);
        } else if (jQuery.isObj(name)) {
    
    
          //赋值的操作,比如传递的参数是{color: red, width:'400px'}
          for (var key in name) {
    
    
            this.each(function (i, e) {
    
    
              //注意:这里一定不能写成:this[i]['style'][key] = name[key];
              //因为在each中,已经把fun执行时的this替换成了this[i]
              this["style"][key] = name[key];
            });
          }
        }
      } else if (arguments.length >= 2) {
    
    
        this.each(function (i, e) {
    
    
          this["style"][name] = val;
        });
      }
      //链式编程
      return this;
    },
  });

css类操作模块

 jQuery.fn.extend({
    
    
    addClass: function (clsName) {
    
    
      //思路:
      //1.先判断dom元素是否有该class
      //2.如果没有就添加,如果有就不能再添加了
      this.each(function () {
    
    
        if ((" " + this.className + " ").indexOf(" " + clsName + " ") == -1) {
    
    
          this.className += " " + clsName;
        }
      });
      return this; //链式编程
    },
    removeClass: function (clsName) {
    
    
      //1.如果没传参数,就把所有DOM对象的class属性清空
      //2.如果传递参数了,就遍历所有DOM对象,把class属性值的对应字符串,用‘ ’替换
      if (arguments.length == 0) {
    
    
        this.each(function () {
    
    
          this.className = "";
        });
      } else {
    
    
        this.each(function () {
    
    
          this.className = jQuery.trim(
            (" " + this.className + " ").replace(" " + clsName + " ", " ")
          );
        });
      }
      return this; //链式编程
    },
  });

init才是jQuery真正的构造函数

var init = (jQuery.fn.init = function (selector) {
    
    
    if (!selector) {
    
    
      return this;
    }
    //如果是字符串
    if (jQuery.isString(selector)) {
    
    
      selector = jQuery.trim(selector);
      //如果是HTML标签片段,则创建对应的DOM,
      //然后添加到实例(this)身上,这里的this是由工厂jQuery调用init构造函数new出来的对象
      if (jQuery.isHTML(selector)) {
    
    
        /**
         * 由于存在标签嵌套<div><span></span></div>的可能,所以不能简单的通过字符串切割,找到标签名,去createElement.
         * 创建的思路:
         * 1.先创建一个临时的容器div
         * 2.设置这个div的innerHTML为这个selector字符串。这些标签就成为了div的子元素
         * 3.然后遍历这个div容器的子元素,依次添加到this身上
         * 4.最后追加length属性
         */
        var tempDiv = document.createElement("div");
        tempDiv.innerHTML = selector;
        [].push.apply(this, tempDiv.childNodes);
        // Array.prototype.push.apply(this, tempDiv.childNodes);
        this.length = 1;
        return this;
      } else {
    
    
        //selector是选择器
        try {
    
    
          var firtChar = selector.charAt(0);
          var lastChars = selector.substr(1);
          if (firtChar == "#") {
    
    
            //id选择器
            var obj = document.getElementById(lastChars);
            if (obj == null) {
    
    
              return this;
            }
            [].push.call(this, obj);
          } else {
    
    
            if (firtChar == ".") {
    
    
              //类选择器
              var objs = document.getElementsByClassName(lastChars);
              [].push.apply(this, objs);
            } else {
    
    
              //标签选择器
              var objs = document.getElementsByTagName(selector);
              [].push.apply(this, objs);
            }
          }
          return this;
        } catch {
    
    
          this.length = 0;
          return this;
        }
      }
    }
  });

把构造函数的原型,替换为jQuery工厂的原型
这么做的目的是为了实现jQuery的插件机制,让外界可以通过jQuery方便的进行扩展

 init.prototype = jQuery.fn;
  w.jQuery = w.$ = jQuery;

猜你喜欢

转载自blog.csdn.net/ck2018182068/article/details/128007983