热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

jQuery简单小结

前言之前一段时间一直在进行旧项目的重构,发现了很多问题,系统用的库是jQuery,主要是用着方便,其他同事,包括一些外包同事,对这个库也比较熟悉。这里就对一些常见的问题,结合查到的

前言

之前一段时间一直在进行旧项目的重构,发现了很多问题,系统用的库是jQuery, 主要是用着方便,其他同事,包括一些外包同事,对这个库也比较熟悉 。这里就对一些常见的问题,结合查到的资料,进行一些简单的总结。

为什么使用jQuery

这个问题,答案是显而易见的。还能因为啥,当然是方便呗。没错,它本身就是一个为dom而生的库。
jQuery的思想,实际上很简单,八个字可以概括: 选择元素,进行操作。

各类强大的选择器极大的简化了dom操作,我们最常使用的也是它的选择器。
下面就对经常使用的一些功能,给出一些建议。

使用最新版本

https://jsperf.com/jquery-1-4…
新版本会改进性能,还有很多新功能。

为了直观的看到版本对性能的影响,我们来看一些测试用例:

以三个常见的选择器为例:


$('.elem')
$('.elem', context)
context.find('.elem')

测试结果是相同时间内 选择器的执行次数:

《jQuery 简单小结》

《jQuery 简单小结》

可以很明显的看到,一般来说,新版本比旧版本有显著的性能提升。

用好选择器

首先列举几个常用的选择器:

$('#xxx') // ID选择器
$('.xxx') // 类选择器
$(input) // 标签选择器
$(':xxx') // 伪类选择器 比如 $(':hidden')
$('[attribute = value]') //属性选择器

使用上面几个选择器 来进行测试:







https://jsperf.com/dh-jquery-…
还是先看一下测试数据:

《jQuery 简单小结》

《jQuery 简单小结》

可以非常直观的看到,ID选择器的速度最快,远超其他选择器。

根据以上信息,简单的总结一下:


1. ID选择符应该是唯一的,不需要添加额外的选择符。
不推荐的: $('div#id'), $('#a #id'), $('div#id span.class')
正确的姿势: $('#id') ,$('#id .class')
2. 避免使用隐式通用选择符
不推荐的: $('.class :radio')
正确的姿势: $('.class input:radio')
3. 避免使用通用选择器`*` , 性能很差。
不推荐的: $('.container > *')
正确的姿势: $('.container').children()

遵循以上规则, 选择器的使用上基本就没什么问题了,之后,我们还可以继续优化。

利用缓存

频繁操作dom浪费性能,所以我们可以把重复使用的的元素缓存起来。


// 在变量前加$前缀,便于识别出jQuery对象
var $a = $('#a'),
$cOntainer= $('#container'),
$container_item = $container.find('li'),
// 利用缓存,比 $('#container li') 好一些
// ...
//如果你想更方便的管理,也可以使用对象字面量的方式:
var DOM = {
$a : $('#a'),
$container : $('#container'),
$container_item : $container.find('li'),
// ...

}
后面使用的时候,就直接可以使用我们定义的DOM对象了。

DOM.$a.on('click',function(){
//xxx
})

选择器也好了,下面我们看dom的操作。

链式操作

采用链式写法,jQuery自动缓存每一步的结果,因此比非链式写法要快。


$('div').find('span').eq(2).html('Hello World');

// 如果操作很多,会导致链很长,这时可以添加适当的换行来 增加可读性 :
$('div')
.find('span')
.eq(2)
.html('Hello World');

同样适用于一些样式的操作:
$target.on('click',function(){
$target.css({
'border':'1px solid #ddd',
'color':'#fff',
// ...
})})

非空判断

如果要进行非空判断 或者 未定义判断的时候 使用 === 而不要使用==.

如果你使用jsHint ,会有这样的提示:

// Use '===' to compare with 'null'
// Use '===' to compare with ''
// Use '===' to compare with 'undefined'

在分支判断的时候, 可以直接利用其本身的含义就可以了: if ( $something !== null) {
// xxx
} // 更好的方式:
if( something) {
// xxx
}

同样的,还有其他类似的判断,比如长度。

if(list.length > 0 ){

// xxx
}

就可以写成

if(list.length){
// xxx
}

事件的委托处理

Javascript的事件模型,采用”冒泡”模式,也就是说,子元素的事件会逐级向上”冒泡”,成为父元素的事件。利用这一点,可以大大简化事件的绑定。

比如,有一个表格(table元素),里面有100个格子(td元素),现在要求在每个格子上面绑定一个点击事件(click):


$("td").on("click", function(){
    $(this).toggleClass("active");
  });

这种做法是不推荐的,,因为td元素发生点击事件之后,这个事件会”冒泡”到父元素table上面,从而被监听到。所以,这个事件只需要在父元素绑定1次即可。

$("table").on("click", "td", function(){
    $(this).toggleClass("active");
  });
//更好的写法,则是把事件绑定在document对象上面。
$(document).on("click", "td", function(){
    $(this).toggleClass("active");
  });
如果要取消事件的绑定,就使用off()方法。
$(document).off("click", "td");

使用’on’

在新版jQuery中,更短的 on(“click”) 用来取代类似 click() 这样的函数。
在之前的版本中 on() 就是 bind()。
自从jQuery 1.7版本后,on() 附加事件处理程序的首选方法。
然而,出于一致性考虑,可以简单的全部使用 on()方法。


$('#id').click(function(){
//xxx
});
替换为:
$('#id').on('click', function(){
//xxx
})

使用短路求值

短路求值是一个从左到右求值的表达式,用 && 或 || 操作符。


if(!$value){
$value = $('#id').val();
}
可以写成:
$value = $value || $('#id').val();
//也可以用 || 来填充默认值
var age = myAge || 18 ;

避免过度使用jQuery

每当你使用一次选择器(比如$(‘#id’)),就会生成一个jQuery对象。jQuery对象是一个很庞大的对象,带有很多属性和方法,会占用不少资源。所以,尽量少生成jQuery对象。

以最简单的选择器为例:

document.getElementById("foo") 就要比 $('#foo') 快很多。

《jQuery 简单小结》

《jQuery 简单小结》

再来看一个例子:


$('a').on ('click' ,function(){
  alert($(this).attr('id'));
})
//点击a元素后,弹出该元素的id属性。
//为了获取这个属性,必须连续两次调用jQuery,第一次是$(this),第二次是attr('id')。
//事实上,这种处理完全不必要。更正确的写法是,直接采用Javascript原生方法,调用this.id:
$('a').on ('click' ,function(){
 alert(this.id);
})

上面简单说了一些简单的优化写法,我们再看看如何更好的组织你的逻辑

逻辑组织

如果遇到抄起键盘就开干的小伙伴,没有组织逻辑,那写的代码可能是这样的:


var a = xxx;
var b = xxx;
$('#id').on('click', function(){
// xxx
})
$('.class').on('click', function(){
// xxx
})
function xxx() {
// xxx
}
// 直到最后

如果整个页面页面的逻辑比较复杂,那到最后的代码,估计只有你自己清楚是怎么走的,别人要去看,要不断的查找你的写的各种方法,简直痛苦。

这里就说一种 或许是更好的方式。

下面就给个实际的例子吧:

/**
* Created by jf on 2015/9/11.
* Modified by bear on 2016/9/7.
*/
$(function () {
var pageManager = {
$container: $('#container'),
_pageStack: [],
_configs: [],
_pageAppend: function(){},
_defaultPage: null,
_pageIndex: 1,
setDefault: function (defaultPage) {
this._defaultPage = this._find('name', defaultPage);
return this;
},
setPageAppend: function (pageAppend) {
this._pageAppend = pageAppend;
return this;
},
init: function () {
var self = this;
$(window).on('hashchange', function () {
var state = history.state || {};
var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
var page = self._find('url', url) || self._defaultPage;
if (state._pageIndex <= self._pageIndex || self._findInStack(url)) {
self._back(page);
} else {
self._go(page);
}
});
if (history.state && history.state._pageIndex) {
this._pageIndex = history.state._pageIndex;
}
this._pageIndex--;
var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
var page = self._find('url', url) || self._defaultPage;
this._go(page);
return this;
},
push: function (config) {
this._configs.push(config);
return this;
},
go: function (to) {
var cOnfig= this._find('name', to);
if (!config) {
return;
}
location.hash = config.url;
},
_go: function (config) {
this._pageIndex ++;
history.replaceState && history.replaceState({_pageIndex: this._pageIndex}, '', location.href);
var html = $(config.template).html();
var $html = $(html).addClass('slideIn').addClass(config.name);
$html.on('animationend webkitAnimationEnd', function(){
$html.removeClass('slideIn').addClass('js_show');
});
this.$container.append($html);
this._pageAppend.call(this, $html);
this._pageStack.push({
config: config,
dom: $html
});
if (!config.isBind) {
this._bind(config);
}
return this;
},
back: function () {
history.back();
},
_back: function (config) {
this._pageIndex --;
var stack = this._pageStack.pop();
if (!stack) {
return;
}
var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
var found = this._findInStack(url);
if (!found) {
var html = $(config.template).html();
var $html = $(html).addClass('js_show').addClass(config.name);
$html.insertBefore(stack.dom);
if (!config.isBind) {
this._bind(config);
}
this._pageStack.push({
config: config,
dom: $html
});
}
stack.dom.addClass('slideOut').on('animationend webkitAnimationEnd', function () {
stack.dom.remove();
});
return this;
},
_findInStack: function (url) {
var found = null;
for(var i = 0, len = this._pageStack.length; i var stack = this._pageStack[i];
if (stack.config.url === url) {
found = stack;
break;
}
}
return found;
},
_find: function (key, value) {
var page = null;
for (var i = 0, len = this._configs.length; i if (this._configs[i][key] === value) {
page = this._configs[i];
break;
}
}
return page;
},
_bind: function (page) {
var events = page.events || {};
for (var t in events) {
for (var type in events[t]) {
this.$container.on(type, t, events[t][type]);
}
}
page.isBind = true;
}
};
function fastClick(){
var supportTouch = function(){
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}();
var _old$On = $.fn.on;
$.fn.on = function(){
if(/click/.test(arguments[0]) && typeof arguments[1] == 'function' && supportTouch){ // 只扩展支持touch的当前元素的click事件
var touchStartY, callback = arguments[1];
_old$On.apply(this, ['touchstart', function(e){
touchStartY = e.changedTouches[0].clientY;
}]);
_old$On.apply(this, ['touchend', function(e){
if (Math.abs(e.changedTouches[0].clientY - touchStartY) > 10) return;
e.preventDefault();
callback.apply(this, [e]);
}]);
}else{
_old$On.apply(this, arguments);
}
return this;
};
}
function preload(){
$(window).on("load", function(){
var imgList = [
"./images/layers/content.png",
"./images/layers/navigation.png",
"./images/layers/popout.png",
"./images/layers/transparent.gif"
];
for (var i = 0, len = imgList.length; i new Image().src = imgList[i];
}
});
}
function androidInputBugFix(){
// .container 设置了 overflow 属性, 导致 Android 手机下输入框获取焦点时, 输入法挡住输入框的 bug
// 相关 issue: https://github.com/weui/weui/issues/15
// 解决方法:
// 0. .container 去掉 overflow 属性, 但此 demo 下会引发别的问题
// 1. 参考 http://stackoverflow.com/questions/23757345/android-does-not-correctly-scroll-on-input-focus-if-not-body-element
// Android 手机下, input 或 textarea 元素聚焦时, 主动滚一把
if (/Android/gi.test(navigator.userAgent)) {
window.addEventListener('resize', function () {
if (document.activeElement.tagName == 'INPUT' || document.activeElement.tagName == 'TEXTAREA') {
window.setTimeout(function () {
document.activeElement.scrollIntoViewIfNeeded();
}, 0);
}
})
}
}
function init(){
preload();
fastClick();
androidInputBugFix(); window.pageManager = pageManager;
window.home = function(){
location.hash = '';
};
}
init();
});

如果想使用另一种更直观的方式,可以接着往下看。

另一种组织方式


var Module = function() {
this.init();
};
// 初始化
Module.prototype.init = function() {
this.fetchData(function() {
// do something
});
};
// 绑定事件
Module.prototype.bindEvent = function() {
// ...
};
// 获取数据
Module.prototype.fetchData = function(cb) {
var self = this;
ajax({}).then(function(data) {
self.renderData(data);
}).catch(function() {
self._fetchDataFailed();
}).fin(function() {
cb && cb();
});
};
// 渲染数据
Module.prototype.renderData = function(data) {
data = this._resolveData(data);
// ...
this.bindEvent();
};
// 处理数据
Module.prototype._resolveData = function() {
// ...
};
// 加载失败
Module.prototype._fetchDataFailed = function() {
// ...
};

当然,你也可以将这两种形式混合起来用,具体怎么用,就看个人习惯了。

这里仅仅介绍一些方法,抛砖引玉。如果你觉得这种方式不好,也可以提出来,以供大家参考学习。

结语

啰哩啰嗦 终于到头了..
类似的这种博文,简单搜一下就有很多,各种 指南 ,最佳实践。我这干脆就简单起个小结吧。

说到底,这篇文字就当是对前几天做的事情的一个简单总结,结合其他资料, 写出来的一点东西。

回头看看 其实也没什么。

查资料,写出来 的过程其实也是一个自我学习的过程,这大概就是写博客的意义所在吧。
不多说了,还有很多需求要做,都排到四月去了 (容我做个悲伤的表情)。就到这里吧。

如果想了解更多类似的内容,可以查看这两篇:

https://segmentfault.com/p/12&#8230;

http://www.ruanyifeng.com/blo&#8230;

以上 :-)


推荐阅读
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
author-avatar
mobiledu2502892183
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有