AngularJS 多字段混合排序

在小溪里最近做的 “加入我们” 碰到了多字段中英文排序,需要把多个字段按照先英文后中文的方式进行排序。

##初始字段

  • 职位名称:中英文,如“Web 前端开发工程师”
  • 是否热门:new
  • 工作职能:中英文,如“软件研发”
  • 工作地点:中英文,如“北京 - 望京”或“北京 - 亦庄”
  • 职位详情:HTML 文档

Link to this heading
排序具体规则

产品说需要将职位是否热门、职位名称、工作职能、工作地点按照汉语拼音/English 进行排序,相同拼音(字母)开头开头时,按照英文在前面来排,如“Android 工程师”在 “安全工程师”之前。

产品经理制定的排序具体规则:(减号表示降序)

  • PC
    • 默认升序: 职能 > 热门 > 职位 > 地点
    • 职位升序: 热门 > 职位 > 职能 > 地点
    • 职位降序: 热门 > -职位 > 职能 > 地点
    • 职能升序: 职能 > 热门 > 职位 > 地点
    • 职能降序:-职能 > 热门 > 职位 > 地点
    • 地点升序: 地点 > 热门 > 职能 > 职位
    • 地点降序:-地点 > 热门 > 职能 > 职位
  • 移动端
    • 默认升序: 热门 > 职能 > 职位 > 地点

Link to this heading
使用 AngularJS orderBy 排序

因为在项目中使用 AngularJS,所以首先考虑使用 AngularJS 进行排序,这里用到了 $filter('orderBy') 进行排序。

文档:https://docs.angularjs.org/api/ng/filter/orderBy

但排序中文时,并没有完全按照拼音排序,好像是按照 中文对应的 Unicode 编码

来自 w3cschool 的解释 把 < 和 > 运算符应用到字符串时,它们只用字符的 Unicode 编码比较字符串,而不考虑当地的排序规则。以这种方法生成的顺序不一定是正确的。例如,在西班牙语中,其中字符 “ch” 通常作为出现在字母 “c” 和 “d” 之间的字符来排序。

PS:至于说,$filter('orderBy')(array, expression, reverse)中的 expression 可以使用 callback,但在网上寻找了很久都没有找到合适的方式写这个function。

Link to this heading
基于 JavaScript localCompare() 的排序

localCompare() 存在的固有问题

来自 w3cschool 的解释 用本地特定的顺序来比较两个字符串。 说明 localeCompare() 方法提供的比较字符串的方法,考虑了默认的本地排序规则。ECMAscript 标准并没有规定如何进行本地特定的比较操作,它只规定该函数采用底层操作系统提供的排序规则。

那么,localeCompare() 存在的问题在于它的排序依据是当前电脑系统设置的语言来进行本地字符串的比较。

  • 当电脑系统语言为中文时,localeCompare() 能返回中英文混合排序的预期结果,只是出现了所有的中文在前,英文都排在后面,此时,想让英文在前,中文在后面就有点难了。
  • 当电脑系统语言为英文或者其他语言时,localeCompare() 并不能返回预期的中英文混合排序结果。

多字段排序的方法

另外,就算使用 localCompare() 进行中英文混合排序能达到预期效果,在多字段排序上,也得需要用递归的方式进行深入的排序,在定制相应的方法方面,需要自行写 JS 逻辑。

以下代码来自于我学弟,他的前端博客是 http://thunf.me/。

Link to this heading
按照中文拼音排序

先将中文转换成拼音,然后按照字母排序。 这种排序直接碰到的一个问题是,中文的可能跟英文的混在一起。如安全工程师(an-quan-gong-cheng-shi)和 Android 工程师(Android-gong-cheng-shi),就没法很好的区分了。此时,我判断了第一个字是否是拼音,因为职位名称基本上是多种多样的,在第二个字或者字母出现相同的几率不是那么大,用户也不会那么在意。

排序的不完美地方 排序时只考虑了首位是中文(拼音)或者是英文的情况,并没有考虑后几位字符的情况。