【长文】JQuery碎碎念
by 毛三胖 on 2018年03月10日
阅:529赞:16

简言

JQuery碎碎念好多条,整理自以前写的文章,包括JQuery最佳实践,常见的错误,性能提升等方面的内容 。有的条目反复出现,更说明其重要性。文中还收录了常用的代码片段,包括表单处理及其它方面的代码。文中所列都是JQuery在WEB开发中经常用到并需要熟练掌握的内容。

JQuery-ssn

注:阅读时间大于10分钟

1 JQuery最佳实践

1.1 使用JQuery的ready处理器

如果你的代码操作DOM,则需要DOM加载完成后再运行代码。推荐使用如下的第一种写法,第二种写法在JQuery3.x中已经不推荐使用了。

$(function () { 
    /* 你的代码 */ 
});

//或者
$(document).ready(function () { 
    /* 你的代码 */ 
});

1.2 用noConflict()避免冲突并定义别名

如果你的jQuery代码与其它使用$符号作为别名的类库冲突,则使用noConflict()方法定义别名。

$jq = jQuery.noConflict();
$jq(function () {
    /* 你的代码 */ 
}

1.3 缓存JQuery对象及链式调用

调用jQuery选择器函数$()代价较大,反复调用效率更低。

1.3.1 错误的方式

//错误
$('#list li').addClass('strong');
$('#list li').css('color', 'red');

1.3.2 缓存JQuery对象

//正确
var $li = $('#list li');
$li.addClass('strong');
$li.css('color', 'red');

1.3.3 链式调用

//正确
$('#list li').addClass('strong').css('color', 'red');

1.4 JQuery变量命名习惯

jQuery包装变量通常以$开头,以区别于标准JavaScript对象。

//良好的命名习惯
var $li = $('#list li');

1.5 利用DOM原生的属性和函数

虽然jQuery的目标之一是对DOM进行抽象,但利用DOM原生的属性和函数效率更高。在不了解DOM的情况下学习jQuery的人中最常犯的错误之一就是利用jQuery访问元素的属性。

1.5.1 冗长而缓慢

$('img').click(function () {
    $(this).attr('src');  
});

1.5.2 简洁而快速

$('img').click(function () {
    this.src;  
});

1.6 创建元素的通用语法

1.6.1 创建元素通用语法方式

$('<p>', {
    text: p_text, 
    "class": 'red', 
    title: p_title, 
    id:  p_id
}).appendTo("#myDiv");

1.6.2 字符串拼接方式

$('<p class="red" id="'+p_id+'" title="'+p_title+'">'+p_text+'</p>').appendTo(#myDiv);

虽然上述两种方式语法正确,功能相同,但是第一种方式更好。第二种字符串拼接的方式可读性差,也更脆弱。

第一种方式对特殊字符的输入是十分强大的。但第二种方式效率较第一种方式更好一些。

2 JQuery常见坑

2.1 乱用选择器

坑人指数:200

JQuery选择器调用代价很大,反复调用效率更低。应采用缓存对象的方法或采用链式调用的方式。

//错误的写法
$("#button").click(function(){
    $('#list li').addClass('strong');
    $('#list li').css('color', 'red');
});
//正确的写法
$("#button").click(function(){
    $lis = $('#list li');
    $lis.addClass('strong');
    $lis.css('color', 'red');
});
//更好的写法
$("#button").click(function(){
    $('#list li').addClass('strong').css('color', 'red');
});

2.2 全局选择效率低

坑人指数:100

尽量使用上下文(context)查找,避免全局选择的使用。全局选择器会进行整个Doc的查找,效率很低。

//错误的写法
$(".active").method();
//正确的写法
var ul = $("#myList");
$(".active",ul).method();

2.3 复制匿名函数

坑人指数:50

避免多次复制匿名函数的写法,将匿名函数分离出来,供其它对象多次调用。

//错误的写法
$('#myDiv').click( function(){
   //一些操作
});
//正确的写法
function divClickFn(){
   //一些操作   
}
$('#myDiv').click(function(){
    divClickFn();
});

2.4 误用ajax的complete

坑人指数:30

当用ajax进行数据请求时,避免使用complete回调方法,而应该使用success方法。complete回调在请求成功或失败都会触发。

//错误的写法
$.ajax({
  url: "http://tools.42du.cn/jsonp/student/all",
}).complete(function( data ) {
    //一些操作  
});
//正确的写法
$.ajax({
  url: "http://tools.42du.cn/jsonp/student/all",
}).success(function( data ) {
    //一些操作  
});

2.5 链式调用的误用

坑人指数:20

采用链式调用的方式会使对象在渐变未完成之前就被移除,即remove方法会在fadeOut方法完成之前调用。当需要第一方法完成之后,再执行第二个方法,请使用回调,即第二种方式。

//错误的写法
$("#myDiv").click(function(e) {
  $(this).fadeOut("slow").remove();
});
//正确的写法
$("myDiv").click(function(e){
  $(this).fadeOut("slow", function(){
    $(this).remove();
  });
});

2.6 事件多次绑定

坑人指数:20

如果你绑定(bind)同一事件多次,响应就会被执行多次。为避免多次执行,请先做事件解绑再重新绑定。

//避免响应多次执行
$("myDiv").unbind("click").bind("click");

2.7 错误使用this指示符

坑人指数:10

this指示符存在于一定的上下文中的,当上下文变化时this指向不同的对象。如果还想调用原上下文中的this,则需要在原上下文中缓存原this对象($that = $(this))。

//错误的写法
$( "#myList").click( function() {
   $(this).method(); 
   $("#myList li").each( function() {
      //this并不指向myList
      $(this).method2(); 
   })
});

3 JQuery性能提升

3.1 优先使用ID选择器和以ID开头的选择器

//ID选择器性能最佳
$("#myDiv")
//以ID开头,提高效率
$("#myDiv .red")

3.2 类选择之前加元素选择提高效率

//元素(tag)选择器效率仅次于ID选择器,优于类(class)选择器
$("#myList li.active")

3.3 缓存JQuery对象

//错误,做了两次选择
$("#myList li").css('border','3px');
$("#myList li").css('color','red');
//缓存对象,提高效率
var $li = $("#myList li")
$li.css('border','3px');
$li.css('color','red');

3.4 利用链式命令,减少代码量

//链式命令,减少代码量
$("#myList li").css('border','3px').css('color','red');

3.5 使用子查询

//一次全局查找加两次子查询优于两次全局查找
var $list = $("#myList");
var $actives = $list.find('li.active');
var $in_actives = $list.find('li.in_active');

3.6 减少DOM的操作次数(DOM操作很慢)

//操作一次DOM,而不要操作100次
var lis = ""; 
for (var i=0, i<100; i++) {
 lis += '<li>' + i + '</li>';
}
$('#myList').html(lis);

3.7 许多节点调用相同的函数时,利用事件委托

//效率较低
$('#myList li').bind('click', function(){
});
//效率较高
$('#myList').bind('click', function(e){
 if ($(e.target).nodeName === 'LI') {
 }
});

3.8 把不重要的功能(如拖放,效果等)放在$(window).load执行

//不要把所有都放在$(document).ready中
$(window).load(function(){
 // 在页面所有对象加载完执行
});

3.9 较长的字符串拼接不要使用concat(),要使用join()

//join()比concat()效率更好
var list_items = [];
for (var i=0; i<=10; i++) { 
    list_items[i] = '<li>Item '+i+'</li>';
}
$('#myList').html(list_items.join(''));

3.10 使用for循环,不要使用$.each循环

//js原生方法效率更好
var js_array = new Array ();
for (var i=0; i<10000; i++) {
    js_array[i] = i;
}

3.11使用元素前,先检查其是否存在

//检查id为myDiv的元素是否存在
if($("#myDiv").length) {
}

3.12 函数总是返回false

$('#myDiv').click (function () {
    return false;
});

3.13 使用html5的data属性

//<div id="myDiv" data-value="111"></div>
$("#myDiv").data("value");

3.14 使用最新的版本及CDN

3.15 压缩你的JS代码

3.16 保持代码规范整洁

4 JQuery表单处理

4.1 只接受数字输入

$("#uAge").keydown(function(event) {
    // 允许退格和删除键
    if ( event.keyCode == 46 || event.keyCode == 8 ) {
    }
    else {
        // 保证输入的是数字键
        if (event.keyCode < 48 || event.keyCode > 57 ) {
            event.preventDefault();
        }
    }
});

4.2 全选

$("#checkall").click(function() {
   //固有属性使用prop,切记 
   $("#myForm input:checkbox").prop("checked",true);
});

4.3 反选

$("#inverse").click(function() {
    $("#myForm input:checkbox").each(function () {
        $(this).prop("checked",!$(this).prop("checked"))
    })
});

4.4 单选框标签表示

//css,隐藏radio圆形,用label表示
//实际使用中,样式写的好看一些
.sex input {  display: none; }
.selected {  background: red;  }
//javascript
$("input:radio").click(function () {
    $("input:radio").parent("label").removeClass("selected");
    $(this).parent("label").addClass("selected");
})

4.5 还可输入多少字符提示

//第一个参数:总字符数
//第二个参数:还可输入多少显示区对象
$.fn.limiter = function (limit, elem) {
    $(this).on("keyup focus", function () {
        setCount(this, elem);
    });
    function setCount(src, elem) {
        var chars = src.value.length;
        if (chars > limit) {
            src.value = src.value.substr(0, limit);
            chars = limit;
        }
        elem.html(limit - chars);
    }
    setCount($(this)[0], elem);
}
$("#title").limiter(3,$("#limit"));

4.6 输入域显示缺省值

$('.default').each(function() {
    var $this = $(this);
    var defaultVal = $this.attr('title');
    if($this.val().length ==0) {
        $this.val(defaultVal);
    }
    $this.focus(function() {
        if ($this.val() === defaultVal) {
            $this.val('');
        }
    });
    $this.blur(function() {
        if ($this.val().length === 0) {
            $this.val(defaultVal);
        }
    });
});

4.7 Email验证

$.fn.validateEmail = function () {
    var $this = $(this);
    $this.change(function () {
        var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
        if ($this.val() == "") {
            $this.removeClass("badEmail").removeClass("goodEmail")
        } else if (reg.test($this.val()) == false) {
            $this.removeClass("goodEmail");
            $this.addClass("badEmail");
        } else {
            $this.removeClass("badEmail");
            $this.addClass("goodEmail");
        }
    });
};

4.8 避免重复提交

$('form').submit(function() {
    if(typeof jQuery.data(this, "disabledOnSubmit") == 'undefined') {
        jQuery.data(this, "disabledOnSubmit", { submited: true });
        $('input[type=submit], input[type=button]', this).each(function() {
            $(this).attr("disabled", "disabled");
        });
        return true;
    }
    else
    {
        return false;
    }
});

5 实用代码

5.1 元素屏幕居中

jQuery.fn.center = function () {
    this.css("position","absolute");
    this.css("top",($(window).height()-this.height())/2+$(window).scrollTop()+"px");
    this.css("left",($(window).width()-this.width())/2+$(window).scrollLeft()+"px");
    return this;
}
$("#myDiv").center();

5.2 获取页面路径相关参数

//值:http://42du.cn/list#jq
var url = document.URL;
//值:http:
var protocol = location.protocol;
//值:42du.cn
var host = location.host;
//值:jq
var hashP = document.URL.split('#')[1];

5.3 删除内联样式

$("*[style]").attr("style", "");

5.4 长度限制并截取

var $elem = $("#title");
if($elem.text().length > 30) {
    $elem.text($elem.text().substr(0, 27)+"...");
}

5.5 外链新窗口打开

$("a[@href^='http']").attr('target','_blank');

5.6 测试JQuery与其它库冲突情况

//测试冲突代码
$("#jqtest").click( function() {
   alert("jQuery is working!");
});
//避免冲突
var $jq = jQuery.noConflict();
$jq("#jqtest").click( function() {
   alert("jQuery is working!");
});

5.7 加载JQuery即使CDN掉线

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="/media/js/jquery.js"><\/script>')</script>

5.8 加载遮罩层,点击移除

$('<div id="overlay"></div>')
.css({
    position    : 'fixed',
    top         : 0,
    left        : 0,
    right       : 0,
    bottom      : 0,
    opacity     : 0.6,
    background  : 'black',
    display     : 'none'
})
.appendTo('body')
.fadeIn('normal')
.click(function () {
    $(this).fadeOut('normal', function () {
        $(this).remove();
    })
});

5.9 元素固顶

//注意调整边界值
$(window).scroll(function() {
    if ($(window).scrollTop() > 100) {
        $('#navbar').css({'position' : 'fixed', 'top' : 0});
    } else {
        $('#navbar').css({'position' : 'relative', 'top' : 'none'});
    }
});

5.10 禁止右键菜单

$(document).bind('contextmenu', function () {
    return false;
})

5.11 对象插件模版代码

(function($){
   var MyPlugin = function(element, options) {
       var elem = $(element);
       var obj = this;
       var settings = $.extend({param: 'defaultValue'}, options || {});
       // 公有方法
       this.publicMethod = function(){
           console.log('public method called!');
       };
       // 私有方法
       var privateMethod = function() {
           console.log('private method called!');
       };
   };
   $.fn.myplugin = function(options) {
       return this.each(function(){
           var element = $(this);
           // Return early if this element already has a plugin instance
           if (element.data('myplugin')) return;
           // pass options to plugin constructor
           var myplugin = new MyPlugin(this, options);
           // Store plugin object in this element's data
           element.data('myplugin', myplugin);
       });
   };
})(jQuery);
$ 热门标签
$ 贴士
简单是稳定的前提。 -Edsger Dijkstra
$ 声明
本站所有代码及文字都是作者精心汇编整理而成,转载代码及文字请明确注明出处和作者名称。