前言

近些年,随着 web 应用的蓬勃发展,前端所需要承载的业务需求与开发任务越来越多。一些曾经第一反应是 “调一下后端接口就完事儿” 的任务,随着 数据量 的提升以及对 用户体验 的追求的提高,问题变的没有那么简单了。今天我们来讨论一下 “如何在前端优雅的实现列表排序功能”。它会被应用在哪些场景呢?这里举几个例子:

  • 按照不同排序规则进行排序,例如:文章列表按更新时间升序或降序排列、按照浏览量升序或降序排列等等
  • 前端实现搜索功能,按匹配度进行排序
  • ……

面对这一问题,我们有几种方案备选,可以一起讨论一下

方案一:直接了当

直接绑定数据不就好啦。

我想很多前端从业者第一反应都会是这样思考的,当然我也不例外,这个方案的结构大致会是这个样子——

ViewModel View

bind
update
listDate
listView
updateSort

View层有一个listView与ViewModel层的listDate绑定,当需要重新排序的时候,对于listData重新sort一下,View层中的listView会自动更新。

没错,问题貌似解决了。但是当数据量达到一定程度或者列表中的结构比较复杂的时候,这个方案会很吃力。

拿我遇到的一个具体需求举个例子,我需要排序的是一系列化学反应方程式,比如:

2 N a H C O 3 + C a ( O H ) 2 = C a C O 3 ↓ + N a 2 C O 3 + 2 H 2 O 2NaHCO_3+Ca\left(OH\right)_2\xlongequal{ }{ }CaCO_3\downarrow +Na_2CO_3+2H_2O 2NaHCO3​+Ca(OH)2​ CaCO3​↓+Na2​CO3​+2H2​O

如果前端实现这样一个结构需要多少<span>或其他标签,可想而知(尽管他不是最复杂的例子)。如果按照此方案对几千几百条这样的数据进行重新排序时,对于DomTree产生的负担是极大的。如果我理解没错的话,当下主流的前端架构(React、Vue、Angular等)大致会这样处理:

  • listDate引用未发生变化(可能需要手动触发render)
  1. 逐一检查listDate[index] === lastListDate[index]
  2. 如果不一致则将原Dom节点移除掉并构造新的Dom节点
  • listDate引用发生了变化
  1. 将整个listView从DomTree上移除掉并进行重新构造

无论何种情况,都有大量的Dom结构的操作,这对于性能会带来一定的考验。

根据这个方案,完成了一个简单的Demo:

private invert() {this.listDate = [...this.listDate.reverse()];
}private render() {return (<div id="eq-list"><button id="invert-btn" onClick={() => {this.invert()}}>倒过来</button><ul class="equation-list">{this.getEqList()}</ul></div>);
}private getEqList() {return this.listDate.map(list => {return (<li class="equation-item"><equation eqlatex={list.latex}></equation></li>);});
}

这里我使用的是stenciljs框架,无需纠结语法。另外<equation>是我封装的一个Web Component,用来根据latex展示化学反应方程式。

实现的效果是这样的:

由于数据量较大,在翻转的时候会卡顿 4 - 5 秒钟,故而这种方案貌似不太能接受。可以尝试一下其他方案。

方案二:多来几份

方案一的一个重要问题在于频繁的修改Dom结构,方案二便主要针对这一点进行优化与完善 —— 在初始化的时候将各种排序结果都渲染好,再根据具体的用户操作控制显示与隐藏。

也就是说它将方案一的 “每次都卡” 优化为 “只卡一次” ,那就是初始化的时候。

看似在一定程度上解决了排序卡顿用户体验差的问题,但是治标不治本。还是有大量的算力浪费掉了。

以上文的例子为例,依此方案解决,会出现同一个item的解析与渲染会重复多遍的问题。

那么问题来了,有没有办法在不动Dom结构的情况下,完成Dom上的排序呢?

方案三:flex - order

这个方案就是用来解决上一个方案提出的问题的。可以在不修改Dom Tree的前提下完成节点排序。

它主要运用的是 flex 布局下的 order 属性,来修改item在布局时的顺序。

有了它,我们就可以将排序与内容分开管理了。不再局限于元素在数组中的 index 了,可以大概采用这样的结构:

ViewModel View listView

bind
bind
update
listDate
innerData
orderDate
itemOrder
updateSort

将每一个列表中的item分为两块:

  • innerData,表示元素的内部数据,与listData绑定;
  • itemOrder,表示元素的列表序,与orderDate绑定,当需要改排序方式时是需要维护好orderDate便可以了,由它去驱动列表的item的 order 属性发生变化便完成了排序任务。

还是上文那个例子,通过这一方案实现后,效果如下:

从实现效果上看,方案三明显优于方案一,几乎没有卡顿与延时的现象。

代码实现也很简单:

private updateInvert() {this.isInvert = !this.isInvert;
}private render() {return (<div id="eq-list"><button id="invert-btn" onClick={() => {this.updateInvert()}}>倒过来</button><ul class="equation-list">{this.getEqList()}</ul></div>)
}private getEqList() {return this.listDate.map((list, index) => {return (<li class="equation-item" style={{order: this.isInvert ? -index : index}}><nb-equation eqlatex={list.latex}></nb-equation></li>);});
}

关于 order 的补充

它作用于父容器display: flex的子元素。

仅对元素在视觉上的顺序产生作用,并不会影响其 parentchildren 上的顺序等逻辑顺序。

它作为一个Dom节点的一个属性,它接收一个整型的值,无论正整数、负整数、0都可以。如果传入浮点值则会视为未传入,取默认值0,并不会做任何取整操作。所以如果您是按匹配度排序的话,需要浮点数整型化后进行处理。

其视觉排序顺序是按照order由小到大排列的,即:小值在前,大值在后。同值则按照在Dom Tree上的顺序进行排列。

最后要说明的一点是:order的浏览器兼容性还是不错的 ——

浏览器 Chrome Edge Firefox Safari Opera
兼容性 29.0 + 11.0 + 28.0 + 9.0 + 17.0 +

上表数据来源 w3cschoo : https://www.w3cschool.cn/cssref/css3-pr-order.html

所以放心大胆的使用吧。

巧用order实现列表排序相关推荐

  1. Hive中使用sort_array函数解决collet_list列表排序混乱问题

    目录 0. 相关文章链接 1. 数据准备 2. 使用collect_list和concat_ws进行行转列 3. 使用sort_array函数解决collet_list列表排序混乱问题 0. 相关文章 ...

  2. python输入数字并排序_「每日一练」巧用Python实现数字排序

    原标题:「每日一练」巧用Python实现数字排序 数字排序在我们的生产和生活中占着非常大的比重,这种思维和技术可以让一组数据更快更明了的展现在我们的面前,极大的提高了我们的工作效率! 那么,你知道如何 ...

  3. Python学习教程实用技法:通过公共键对字典列表排序—itemgetter

    Python学习教程实用技法:通过公共键对字典列表排序-itemgetter 前言:我们有一个字典列表,想根据一个或多个字典中的值对列表进行排序. 利用operator模块中的itemgetter函数 ...

  4. 利用jQuery对无序列表排序 http://www.apkbus.com/android-80639-1-1.html

    利用jQuery对无序列表排序的原理是:获取到无序列表中的所有列表项,并转成数组形式,使用JavaScript函数对其进行排序后再次输出.其中使用到的jQuery函数有ready().get().te ...

  5. python 3 字典排序_Python学习教程实用技法:通过公共键对字典列表排序—itemgetter...

    Python学习教程实用技法:通过公共键对字典列表排序-itemgetter 前言:我们有一个字典列表,想根据一个或多个字典中的值对列表进行排序. 利用operator模块中的itemgetter函数 ...

  6. Python列表排序 reverse、sort、sorted 操作方法详解

    python语言中的列表排序方法有三个:reverse反转/倒序排序.sort正序排序.sorted可以获取排序后的列表.在更高级python list排序中,后两中方法还可以加入条件参数进行排序. ...

  7. Python 列表排序方法reverse、sort、sorted详解

    python语言中的列表排序方法有三个:reverse反转/倒序排序.sort正序排序.sorted可以获取排序后的列表.在更高级列表排序中,后两中方法还可以加入条件参数进行排序. reverse() ...

  8. mysql order by 中文 排序

    mysql order by 中文 排序 1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都 ...

  9. python 字符串比较忽略大小写的方法_python实现忽略大小写对字符串列表排序的方法...

    本文实例讲述了python实现忽略大小写对字符串列表排序的方法,是非常实用的技巧.分享给大家供大家参考.具体分析如下: 先来看看如下代码: string = ''' the stirng Has ma ...

最新文章

  1. valgrind——Cachegrind分析CPU的cache命中率、丢失率,用于进行代码优化。
  2. 卫星对地观测及任务调度中日照分析
  3. python绘制滑稽脸_用Python画滑稽
  4. 空格分隔输出(信息学奥赛一本通-T1026)
  5. android keyguard,Android8.1 SystemUI Keyguard之指纹解锁流程
  6. 5G 爆发前夕,这些科技巨头们聚在一起“密谋”了些什么?!
  7. Http请求返回结果报UnsupportedCharsetException
  8. 计算机aero背景黑,Win7中Aero下面的主题变为黑色
  9. POJ 334932742151184020022503
  10. PyQt5 实现类似海康的设备搜索工具
  11. buuctf————[NPUCTF2020]你好sao啊
  12. 2022-2028年中国饮用水行业市场专项调研及投资前景研究报告
  13. uniapp 下载视频到本地
  14. 关于ECharts中调整容器与图表的位置关系
  15. 如何使用Kotlin构建Android旋转旋钮以帮助儿子练习钢琴
  16. 淘宝被列入黑名单,确有其事还是另有原因
  17. 手机端网页尺寸html,手机端网页设计尺寸_html/css_WEB-ITnose
  18. 应用于流形的卷积网络
  19. 编程实用工具大全(前后端皆可用,不来瞅瞅?)
  20. STATA如何保留和删除变量或者观测值

热门文章

  1. 牛逼,《2020 年全球程序员收入报告》,字节跳动高居全球第七
  2. Linux非常牛逼的命令
  3. leetcode 1074. Number of Submatrices That Sum to Target(和为target的子矩阵个数)
  4. 【CTF WriteUp】2023数字中国创新大赛网络数据安全赛道决赛WP(1)
  5. linux中各种error意思
  6. AutoformR8 软件安装说明视频教程
  7. 在Ubuntu 上安装和配置Snort 3 NIDS
  8. 初学编程者必知的五个网站
  9. 【小沐学NLP】Python实现聊天机器人(ALICE)
  10. leaflet 矢量 经纬网格