最近在做的新业务(PC端)里面,自己写了几个组件,既有简单的toast,也有稍微复杂一点的pagination(分页),在这里记录下自己的思考过程,希望对大家有帮助 ~

Toast

实现基本功能

toast大家已经很熟悉了,其应用场景是:完成某个操作后,给用户一个提示,一定时间后消失

基于这个思路,我们很快能实现出一个基于jQuery能用初版toast

其中关键的代码只有几行:

1
2
3
4
5
6
var elementContent = '<div class="toast-container" style="' + style + '"> <span class="toast-content"> ' + options.content + ' </span> </div>';
$('body').append(elementContent);
//一定时间后消失
var timeout = setTimeout(function() {
$('.toast-container').remove();
}, options.time*1000);
使用优化

上面的toast已经可以用了,但是我在用的时候,发现有一点不方便,因为我每次调用的时候都需要传入一个object对象,即便我就想用默认的样式,默认的消失时间。那我能不能就传入一个我想要给用户展示的字符串呢?

简单改造一下:

1
2
3
4
5
6
7
8
9
10
11
12
//参数为字符串时,将其作为content属性值
if(Object.prototype.toString.call(options) === '[object String]') {
options = $.extend(defaultParam, {
content: options
});
} else if(Object.prototype.toString.call(options) === '[object Object]') {
options = $.extend(defaultParam, options);
} else {
console.error('only support String or Object for param');
return;
}
...

没有花费太多心思,我们就能让使用方式变得更加简单,有了支持多参数形式的toast

去掉第三方依赖

我们在实现toast时使用了jQuery这个第三方库,不得不说,我有时候真心觉得jQuery让前端门槛降低了不少,但是,业务技术架构并不是一成不变的,有的项目里并不会使用jQuery。那么我们就需要提供一个不依赖第三方库toast

只需要将上面用到jQuery的地方使用原生JS实现就行了,其中有个深拷贝函数$.extend大家需要关注,在这里我们就不细说了。

完整代码:原生JavaScript实现的toast

到这里我们就实现了一个功能比较完整的toast,整个代码很简单,但我重点想说的是不断优化的过程:

  • 第一个版本,我们的要求是:能用
  • 第二个版本,我们的要求是:用起来方便
  • 第三个版本,我们的要求是:不依赖第三方库,能适应不同技术架构

Pagination

我们通过写toast组件的过程,已经了解了如何写好一个组件,现在我们将这个思路应用到一个稍微有点复杂的组件上:分页组件。

分页组件通常是和表格一起用的,使用场景是:将比较大的数据量分页,每页展示固定条数的数据,用户可以通过分页组件自由选择查看任何页码的数据,我们梳理下思路,分为这么几步:

  1. 通过当前页码总页数展示出页码选择器
  2. 给每一页绑定点击事件,点击时获取数据,并且更新页码选择器

其中有个词是:页码选择器,其实指的就是这个东西:

页码选项

如何展示出页码选择器?,我发现有篇博客讲解的思路非常好:如何写一个简单的分页,但是在代码细节上,对于不熟悉分页的人不太好理解,我沿用这个思路,具体细节上有修改。

总体思路就是以当前页码为分割点,分别得到之前和之后的页码。

现在我们用代码初版pagination组件实现这个效果(忽略CSS),得到上图中的页码选择器,其中关键代码如下,我做了详细注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* [getPage 获取页码展示]
* @param {[type]} currentPage [当前页码]
* @param {[type]} totalPage [页码总数]
* @return {[type]} [description]
*/
function getPage(currentPage, totalPage) {
//显示:第一页,当前页,当前页的前后两页,最后一页
//以当前页为分割点,分别得到当前页前面的页码和后面的页码
var pageStr = '<a class="active">' + currentPage + '</a>';
// 将当前页前后2页的页码展示出来
for(var i = 1; i<=2; i++) {
//得到当前页前两页的的页码
//其中的1指第一页
if(currentPage > i+1) {
pageStr = '<a>' + (currentPage - i) + '</a>' + pageStr;
}
//得到当前页后两页的页码
if(currentPage+i < totalPage) {
pageStr = pageStr + '<a>' + (currentPage + i) + '</a>';
}
}
//得到当前页前面用...表示的页码
//两个1分别表示第一页,和当前页
if( currentPage > 2+1+1 ) {
pageStr = ' ... ' + pageStr;
}

//得到上一页
if(currentPage > 1) {
pageStr = '<a class="prePage">上一页</a><a>1</a>' + pageStr;
}

//得到当前页后面用...表示的页码
//其中1表示最后一页,当前页已经在前面计算过,这里不再计算
if( currentPage+2+1 < totalPage ) {
pageStr = pageStr + ' ... ';
}

//得到下一页
if( currentPage < totalPage ) {
pageStr = pageStr + '<a>' + totalPage + '</a><a class="lastPage">下一页</a>';
}

return pageStr;
}

最终我们达到的效果是这样的:

分页效果图

其中.pagination-container这个元素是整个分页组件的容器,直接在html页面中定义就行。

在上面的效果图中,我们点击不同的页码只是【跳转到了不同的页面】,但在实际项目中,我们通常都是获取要获取数据,更新表格。

我们把bindEvent函数稍微更新一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var $this = $(this);
var pageNum;
var currentPage = +$('.pagination-list a.active').text();
if( $this.hasClass('prePage') ) {
//点击【上一页】
pageNum = currentPage - 1;
} else if( $this.hasClass('lastPage') ) {
//点击【下一页】
pageNum = currentPage + 1;
} else {
pageNum = +$this.text();
}
//获取表格数据
//执行ajax之前的回调函数,比如加个loading
options.beforeCallback && options.beforeCallback();
$.ajax({
url:options.url,
type: options.type,
data: options.data
}).done(function(res){
//执行ajax之后的回调函数,比如隐藏loading
options.afterCallback && options.afterCallback();
//请求成功后的回调函数
options.callback && options.callback(res);
// 更新页码
var pageHtml = getPage(pageNum, options.totalPage);
$('.pagination-list').html(pageHtml);
}).fail(function(error){
//执行ajax之后的回调函数,比如隐藏loading
options.afterCallback && options.afterCallback();
alert('请求出错,请重试');
});

这样我们就完成了一个比较完整的分页组件

去掉第三方依赖

在这个组件里去掉依赖就是去掉对jQuery的依赖,我们只需要把使用jquery方法的地方用原生JavaScript实现一遍就行。总结一下,我们需要自己实现深拷贝函数事件代理函数发送Ajax。完整代码:原生JavaScript实现的分页组件

大家可以对比一下,去掉了jQuery之后,我们多写了多少代码啊。其中有很多细节需要考量,所以我一直觉得写原生JavaScript才能真正考察一个前端的功底。

总结

ok, 到这里就差不多了,本文重点不在于告诉大家如何去实现某一个具体的组件(毕竟我们只涉及到两个组件),而在于阐述一种观点:我们写的组件即便只是用在我们自己的业务中,也不要满足于能用就行,一步步优化组件,优化功能,能适应不同技术场景,不仅能提升技术能力,还能让我们意识到并且实践如何把一件事从60分做到90分