“没有jQuery的时代,前端工程师是用牙啃DOM的。”
墨尘的这句话让林小凡差点把嘴里的泡面喷出来。
他正对着一个古董级企业网站抓耳挠腮——这个用jQuery 1.3.2写的项目突然被甲方要求“现代化改造”,而文档里只有一行README:
“别动,能跑就行。”
“这代码……像用象形文字写的。”林小凡颤抖着点开main.js,映入眼帘的是:
javascript
$('#main-content')
.find('.widget:visible')
.not(':has(.hidden)')
.each(function() {
$(this).hover(
function() { $(this).addClass('active').siblings().fadeTo(200, 0.5); },
function() { $(this).removeClass('active').siblings().fadeTo(200, 1); }
);
});
他试着在控制台输入$('#main-content')
——
一个熟悉的蓝底白字错误跳出来:
$ is not defined
“哈!果然连jQuery都没引入!”他得意地准备加上<script src="jquery.js">
,却被墨尘的消息打断:
“先别急,看看Network面板。”
林小凡打开开发者工具,赫然发现页面底部藏着:
html
<script src="/libs/jquery-1.3.2.min.js" defer></script>
<script src="/js/legacy-polyfill.js"></script>
那个legacy-polyfill.js
里赫然写着:
javascript
// 防止$冲突
jQuery.noConflict();
var $jq = jQuery;
“所以……”林小凡声音发抖,“这个项目里$
不是jQuery?!”
**“欢迎来到2010年的前端地狱。”**墨尘回复道。
第一节:选择器之王
为了理解这段“考古发现”,林小凡决定系统学习jQuery。
他打开2006年的教程视频,画面里一个兴奋的程序员演示着:
javascript
// 原生JS获取所有.red元素
var redElements = document.querySelectorAll('.red'); // 2013年才普及
// jQuery方式
var $redElements = $('.red');
“就这?”林小凡不以为然,“现在用document.querySelectorAll
不就行了?”
直到他看到下一个例子:
javascript
// 原生JS切换类
var element = document.getElementById('menu');
if (element.classList.contains('active')) { // IE9+才支持classList
element.classList.remove('active');
} else {
element.classList.add('active');
}
// jQuery方式
$('#menu').toggleClass('active');
视频里的讲师激情解说:“jQuery让DOM操作像说话一样自然!”
林小凡突然理解了为什么这个库能统治前端十年——在IE6还是主流浏览器的年代,原生DOM API简直是刑具。
第二节:链式调用的魔法
随着深入学习,林小凡被jQuery的链式调用震撼了:
javascript
$('.item')
.filter(':odd')
.css('color', 'red')
.end()
.find('.icon')
.attr('title', 'Modified!');
这种流畅的操作让他想起自己用现代JS写的臃肿代码:
javascript
document.querySelectorAll('.item').forEach((el, index) => {
if (index % 2 === 1) {
el.style.color = 'red';
}
el.querySelectorAll('.icon').forEach(icon => {
icon.setAttribute('title', 'Modified!');
});
});
“难怪老程序员提起jQuery都眼含热泪……”他喃喃自语。
墨尘发来一个jQuery时代的经典段子:
“当年面试只考两件事:你能手写AJAX吗?你能不用jQuery操作DOM吗?”
第三节:动画帝国的崛起
最让林小凡惊叹的是jQuery的动画系统。
那个古董项目里有一段神奇的代码:
javascript
$('#banner')
.slideDown(300)
.delay(500)
.animate({
'margin-left': '+=200px',
'opacity': 0.7
}, {
duration: 800,
complete: function() {
$(this).html('Animation Complete!');
}
});
他试着用现代CSS重写:
css
#banner {
transition: all 0.3s ease;
/* 如何实现delay后的链式动画? */
}
“CSS动画没法这么精确控制流程啊!”他抓狂地发现需要嵌套setTimeout
才能模拟。
墨尘适时补刀:
“知道为什么当年jQuery UI能火了吧?那可是在CSS3诞生前的黑暗年代。”
第四节:插件生态的狂欢
林小凡在代码深处发现了一个神秘引用:
html
<script src="/libs/jquery.mousewheel.min.js"></script>
<script src="/libs/jquery.cookie.min.js"></script>
<script src="/libs/jquery.validate.min.js"></script>
这些插件让他窥见jQuery全盛时期的生态:
- 表单验证不用写正则表达式(jQuery Validation)
- 轮播图不用算偏移量(Slick Slider)
- 模态框不用调z-index(Magnific Popup)
“这不就是现代npm生态的雏形吗?!”林小凡恍然大悟。
直到他尝试升级jQuery版本……
第五节:版本升级的血泪
“我就想升级到jQuery 3.0……”林小凡委屈地看着满屏报错。
问题接踵而至:
$.browser
被移除(旧代码里全是IE6判断)animate()
的scrollTop
语法变了load()
事件被on('load')
取代
最致命的是某个插件报错:
javascript
// 某神秘插件内部
$.fn.hover = function(fn1, fn2) {
return this.on('mouseenter', fn1).on('mouseleave', fn2 || fn1);
};
而jQuery 3.0+已经内置了更科学的.hover()
方法。
“所以现在怎么办?”林小凡绝望地问。
墨尘发来一个链接:
“用这个过渡,或者……”
“重写整个项目。”
终节:王者的黄昏
深夜,林小凡终于让古董网站在jQuery 3.6.0下跑起来了。
他翻看着Git提交历史,最早的记录停在2009年:
bash
commit 3a1b5c8 (HEAD -> master)
Author: Unknown <old_dev@example.com>
Date: Mon Aug 3 14:22:38 2009 +0800
初次提交:基于jQuery 1.3.2的企业门户
十四年前的代码,至今仍在线上运行。
他突然理解了jQuery的伟大——它用简单的$()
统一了碎片化的浏览器世界,让Web开发从刀耕火种进入铁器时代。
关掉电脑前,他鬼使神差地在控制台输入:
javascript
$.fn.jquery // "3.6.0"
蓝色的版本号在黑暗中闪烁,像一座纪年碑。
(第七章 完)
下一章预告:
第八章:Angular的崛起——MVC的革新
“当jQuery开发者第一次看到ng-repeat
时,他们的表情就像看到火器的原始人。”——某前端历史学家