做前端的,谁没写过几万行jQuery?
从$(document).ready()开始,到$('.btn').click(),到$.ajax(),到各种链式调用和动画,jQuery曾经是每个前端开发者的标配。那时候找工作,不会jQuery都不好意思说自己是做前端的。
我也是写着jQuery长大的一代。从2010年开始用jQuery,写了五六年,自认为对jQuery了如指掌,各种插件、各种技巧、各种hack,玩得很溜。
但是2016年,我在一个项目中尝试用了Vue.js,然后……就再也回不去了。
今天就来聊聊,为什么用了Vue.js之后,我再也不想写jQuery了。
一、jQuery的那些痛
在用Vue之前,我其实没觉得jQuery有什么不好。毕竟用了这么多年,已经形成了肌肉记忆。但是回头看,jQuery的痛点其实很多,只是我们习惯了而已。
1. DOM操作太繁琐
jQuery的核心是DOM操作。要更新页面内容,你需要先选中元素,然后设置内容:
$('#username').text(user.name);
$('#user-avatar').attr('src', user.avatar);
$('#user-bio').html(user.bio);
$('.user-followers').text(user.followers + ' followers');一个用户信息展示,就要写这么多行。如果数据变了,还要再写一遍更新逻辑。数据和视图是分离的,你需要手动把数据同步到DOM上。
而且,DOM操作多了,性能就成了问题。频繁的DOM操作会导致页面重排重绘,卡顿、闪烁都是常事。
2. 事件绑定和销毁麻烦
jQuery绑定事件很简单:$('.btn').click(handler)。但是在复杂的页面中,事件绑定和销毁就成了噩梦。
动态添加的元素,需要用事件委托:$(document).on('click', '.btn', handler)。页面切换时,需要手动解绑事件,否则会内存泄漏、事件重复绑定。
我曾经维护过一个项目,页面切换后按钮点击一次触发三次,查了半天才发现是之前的页面没有解绑事件,三次绑定叠加了。
3. 代码组织混乱
jQuery没有强制的代码组织方式,全靠开发者自觉。小项目还好,大项目中,代码很容易变成"面条代码"——HTML里混着JS,JS里拼着HTML字符串,逻辑和视图搅在一起,维护起来非常痛苦。
// 典型的jQuery代码:JS里拼HTML
var html = '<div class="user-card">' +
'<img src="' + user.avatar + '">' +
'<h3>' + user.name + '</h3>' +
'<p>' + user.bio + '</p>' +
'</div>';
$('#user-list').append(html);拼字符串拼到怀疑人生,引号嵌套、转义、拼写错误,都是家常便饭。
4. 状态管理缺失
jQuery没有状态管理的概念。页面的状态(哪些数据加载了、哪些按钮被点击了、当前是哪个tab)都散落在各个地方,可能存在DOM的data属性里,可能存在全局变量里,可能存在隐藏域里。
状态多了之后,你根本不知道哪个状态是最新的,修改一个状态要改好几个地方,bug层出不穷。
5. 双向绑定要自己写
表单输入和数据同步,在jQuery里需要自己写:
$('#input-name').on('input', function() {
user.name = $(this).val();
$('#display-name').text($(this).val());
});一个输入框就要写这么多,表单字段多了简直是灾难。
二、Vue.js的初体验
2016年初,我听说了Vue.js。那时候Vue还不算火,AngularJS和React是主流,Vue算是后起之秀。但是看了Vue的文档和demo之后,我被吸引了——它太简单、太优雅了。
我在一个小项目中尝试用了Vue,然后就被惊艳到了。
1. 数据驱动,告别DOM操作
Vue的核心理念是"数据驱动视图"。你只需要关心数据,视图会自动更新。
<div id="app">
<div class="user-card">
<img :src="user.avatar">
<h3>{{ user.name }}</h3>
<p>{{ user.bio }}</p>
<p>{{ user.followers }} followers</p>
</div>
</div>new Vue({
el: '#app',
data: {
user: {
name: '张三',
avatar: 'avatar.jpg',
bio: '一个程序员',
followers: 100
}
}
});就这么简单!数据变了,视图自动更新。你不需要手动操作DOM,不需要选中元素、设置内容。你只需要修改this.user.name = '李四',页面上的名字就自动变了。
这种感觉太爽了,就像从"手动挡"换到了"自动挡"。
2. 组件化,代码组织清晰
Vue的组件化让代码组织变得非常清晰。每个组件都是一个独立的单元,有自己的模板、逻辑、样式,互不干扰。
<!-- user-card.vue -->
<template>
<div class="user-card">
<img :src="user.avatar">
<h3>{{ user.name }}</h3>
<p>{{ user.bio }}</p>
</div>
</template>
<script>
export default {
props: ['user']
}
</script>
<style scoped>
.user-card {
padding: 20px;
border: 1px solid #eee;
}
</style>组件可以复用,可以嵌套,可以传参。一个复杂的页面,拆分成若干个组件,每个组件负责自己的部分,维护起来非常清晰。
而且,scoped样式让CSS只在当前组件内生效,再也不用担心样式冲突、类名冲突了。
3. 双向绑定,表单so easy
Vue的v-model让表单双向绑定变得异常简单:
<input v-model="user.name" type="text">
<p>你好,{{ user.name }}</p>就这一行,输入框和数据就双向绑定了。输入框内容变了,数据自动更新;数据变了,输入框内容也自动更新。不需要写任何事件监听和同步逻辑。
表单字段多了之后,这个优势更加明显。一个复杂的表单,在jQuery里可能要写几百行DOM操作和事件绑定,在Vue里可能只需要一个v-model就搞定了。
4. 指令系统,声明式操作
Vue的指令系统让DOM操作变得声明式、直观:
v-if/v-show:条件渲染v-for:列表渲染v-on(简写@):事件绑定v-bind(简写:):属性绑定v-model:双向绑定
<ul>
<li v-for="item in list" :key="item.id">
{{ item.name }}
<button @click="removeItem(item.id)">删除</button>
</li>
</ul>
<p v-if="list.length === 0">暂无数据</p>列表渲染、条件渲染、事件绑定,都在模板里声明式地写,一目了然。不需要在JS里循环拼HTML字符串,不需要手动绑定事件。
5. 生命周期钩子,逻辑清晰
Vue的生命周期钩子让组件的初始化、更新、销毁逻辑变得清晰:
export default {
data() {
return { list: [] }
},
created() {
// 组件创建后,加载数据
this.fetchData();
},
mounted() {
// DOM挂载后,可以操作DOM
},
beforeDestroy() {
// 组件销毁前,清理定时器、解绑事件
},
methods: {
fetchData() {
// 加载数据
}
}
}什么时候加载数据、什么时候操作DOM、什么时候清理资源,都有对应的钩子,逻辑非常清晰。再也不用担心事件没解绑、定时器没清理导致的内存泄漏了。
三、实际项目中的对比
说了这么多概念,来看看实际项目中,jQuery和Vue的代码量对比。
场景:一个用户列表页面
功能:加载用户列表、展示用户卡片、点击删除按钮删除用户、搜索过滤。
jQuery版本(简化版):
$(function() {
var list = [];
var keyword = '';
// 加载数据
function loadData() {
$.getJSON('/api/users', function(data) {
list = data;
renderList();
});
}
// 渲染列表
function renderList() {
var $list = $('#user-list');
$list.empty();
var filtered = list.filter(function(user) {
return user.name.indexOf(keyword) > -1;
});
if (filtered.length === 0) {
$list.append('<p class="empty">暂无数据</p>');
return;
}
filtered.forEach(function(user) {
var html = '<div class="user-card" data-id="' + user.id + '">' +
'<img src="' + user.avatar + '">' +
'<h3>' + user.name + '</h3>' +
'<p>' + user.bio + '</p>' +
'<button class="btn-delete">删除</button>' +
'</div>';
$list.append(html);
});
}
// 搜索
$('#search').on('input', function() {
keyword = $(this).val();
renderList();
});
// 删除(事件委托)
$('#user-list').on('click', '.btn-delete', function() {
var id = $(this).closest('.user-card').data('id');
if (confirm('确定删除吗?')) {
$.ajax({
url: '/api/users/' + id,
type: 'DELETE',
success: function() {
list = list.filter(function(user) {
return user.id !== id;
});
renderList();
}
});
}
});
loadData();
});Vue版本(简化版):
<template>
<div>
<input v-model="keyword" type="text" placeholder="搜索">
<div class="user-list">
<div v-for="user in filteredList" :key="user.id" class="user-card">
<img :src="user.avatar">
<h3>{{ user.name }}</h3>
<p>{{ user.bio }}</p>
<button @click="removeUser(user.id)">删除</button>
</div>
<p v-if="filteredList.length === 0" class="empty">暂无数据</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
keyword: ''
}
},
computed: {
filteredList() {
return this.list.filter(user => user.name.includes(this.keyword));
}
},
created() {
this.fetchData();
},
methods: {
fetchData() {
fetch('/api/users')
.then(res => res.json())
.then(data => { this.list = data; });
},
removeUser(id) {
if (confirm('确定删除吗?')) {
fetch('/api/users/' + id, { method: 'DELETE' })
.then(() => {
this.list = this.list.filter(user => user.id !== id);
});
}
}
}
}
</script>对比一下:
- jQuery版本:JS里拼HTML字符串,事件委托,手动渲染,数据和视图分离
- Vue版本:模板声明式渲染,计算属性自动过滤,数据驱动视图,逻辑清晰
而且,Vue版本的可读性和可维护性远高于jQuery版本。如果要加功能(比如分页、排序),Vue版本只需要加几个属性和方法,jQuery版本可能要大改。
四、Vue的坑和注意事项
当然,Vue也不是完美的,用的过程中也踩了一些坑。
1. 响应式的限制
Vue 2.x的响应式是基于Object.defineProperty的,有一些限制:
- 不能检测对象属性的添加和删除(需要用
Vue.set) - 不能检测数组的直接修改(如
arr[0] = newValue,需要用Vue.set或splice)
这些限制在Vue 3.x中用Proxy解决了,但是2016年用的是Vue 1.x/2.x,需要注意。
2. 组件通信
组件之间的通信,在简单场景下用props和事件就够了,但是复杂场景下(如跨层级通信、兄弟组件通信)会比较麻烦。2016年的时候,Vuex还不算成熟,大型应用的状态管理需要自己摸索。
3. 学习曲线
Vue虽然比Angular简单,但是比jQuery还是有学习曲线的。需要理解数据驱动、组件化、生命周期、计算属性、指令等概念。对于习惯了jQuery命令式编程的开发者,需要转变思维方式。
4. 生态还不够成熟
2016年的时候,Vue的生态还不如React和Angular成熟。第三方组件库、插件、工具链都还在发展中。很多东西需要自己造轮子。
但是这些坑,相比Vue带来的便利,都是可以接受的。而且Vue的文档非常好,社区也很活跃,遇到问题基本都能找到解决方案。
五、为什么回不去jQuery了
用了Vue之后,再回去写jQuery,感觉就像从现代社会回到了原始社会。
- 写一个列表渲染,第一反应是
v-for,而不是for循环拼HTML - 写一个表单输入,第一反应是
v-model,而不是on('input')手动同步 - 写一个条件显示,第一反应是
v-if,而不是show()/hide() - 写一个组件,第一反应是拆分成
.vue文件,而不是在一个大JS文件里写一堆函数
jQuery的命令式编程,需要你告诉浏览器"做什么"和"怎么做";Vue的声明式编程,你只需要告诉浏览器"我要什么",剩下的交给框架。
这种思维方式的转变,一旦习惯了,就再也回不去了。就像用惯了自动挡的车,再开手动挡会觉得累;用惯了智能手机,再用功能机会觉得不方便。
当然,jQuery也不是一无是处。在一些简单的页面(如营销页、活动页)中,jQuery还是很方便的,引入一个JS文件就能用,不需要构建工具、不需要模块化。但是在中大型项目中,Vue(或React、Angular)的优势是碾压级的。
六、2016年的前端框架选择
2016年,前端框架三足鼎立:AngularJS(Angular 1.x)、React、Vue.js。
- AngularJS:老牌框架,功能强大,但是学习曲线陡,性能有问题,而且Angular 2即将发布(不兼容1.x),很多人在观望。
- React:Facebook出品,组件化+虚拟DOM,生态强大,但是需要学习JSX、Flux/Redux等概念,入门门槛不低。
- Vue.js:尤雨溪出品,简单易学,文档友好,渐进式框架(可以只用到一部分功能),性能优秀,但是生态还在发展中。
我选择Vue的原因:
- 简单:看了一遍文档就能上手,不需要学习太多新概念
- 灵活:可以从简单的用法开始,逐步深入,不需要一上来就用全套工具链
- 文档好:Vue的中文文档非常友好,例子丰富,遇到问题查文档基本能解决
- 性能好:虚拟DOM+异步更新,性能不输React
- 中国人开发:尤雨溪是中国人,社区氛围好,中文资料多
当然,这只是我个人的选择。React和Angular也各有优势,选择哪个框架要看项目需求、团队情况、个人偏好。但是无论选哪个,都比纯jQuery开发效率高得多。
总结
用了Vue.js之后,我再也不想写jQuery了。原因很简单:
- 数据驱动视图:告别繁琐的DOM操作,只关心数据
- 组件化:代码组织清晰,可复用,易维护
- 双向绑定:表单处理so easy
- 声明式模板:直观、易读、易维护
- 生命周期钩子:逻辑清晰,资源管理方便
- 开发效率高:同样的功能,代码量更少,bug更少
jQuery的痛点:DOM操作繁琐、事件绑定/销毁麻烦、代码组织混乱、状态管理缺失、双向绑定要自己写。
Vue的坑:响应式限制、组件通信、学习曲线、生态不够成熟(2016年)。但是这些坑相比Vue带来的便利,都是可以接受的。
2016年,前端框架三足鼎立(AngularJS、React、Vue),我选择Vue是因为它简单、灵活、文档好、性能好、中国人开发。当然,选择哪个框架要看具体情况,但是无论选哪个,都比纯jQuery强。
最后,如果你还在用jQuery写中大型项目,我强烈建议你试试Vue(或React、Angular)。一开始可能不习惯,但是用了之后,你会发现前端开发原来可以这么优雅。然后,你也会和我一样,再也回不去jQuery了。
技术在进步,我们也要跟着进步。不要让"习惯"成为你学习新技术的障碍。走出舒适区,你会发现更大的世界。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录