Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS 中创建自定义排序方法 #94

Open
husky-dot opened this issue Aug 14, 2019 · 1 comment
Open

JS 中创建自定义排序方法 #94

husky-dot opened this issue Aug 14, 2019 · 1 comment

Comments

@husky-dot
Copy link
Owner

原文:https://www.youtube.com/watch?v=zVevl-K-m7Y

译者:前端小智

为了保证的可读性,本文采用意译而非直译。

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!

一般情况咱们排序大都按数字或字母顺序,但也有一些情况下,咱们可能需要自定义排序顺序。

在此之前先简单介绍一下 reduce 方法:

语法:arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

callback:执行数组中每个值的函数,包含四个参数:

accumulator:累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。

currentValue:数组中正在处理的元素。

currentIndex (可选):数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1

array(可选): 调用 reduce() 的数组

initialValue(可选):作为第一次调用 callback 函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

rudeuce 过程描述:

回调函数第一次执行时,accumulatorcurrentValue的取值有两种情况:如果调用reduce()时提供了initialValueaccumulator取值为initialValuecurrentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。

回到原文:

如下面的例子所示,咱们想让 inProgress 在第一位,接着是 todo,然后是 done

const tasks = [
  {id:1, title: 'Job A', status: 'done'},
  {id:2, title: 'Job B', status: 'inProgress'},
  {id:3, title: 'Job C', status: 'todo'},
  {id:4, title: 'Job D', status: 'inProgress'},
  {id:5, title: 'Job E', status: 'todo'}
]

首先按照所需的排序顺序创建一个数组。

const sortBy = ['inProgress', 'todo', 'done']

使用reduce来创建一个函数,参数为一个数组,最后输出以数组项为键,索引为值,如 {inProgress:0,todo:1,done:2}

const sortByObject = data => data.reduce(
  (obj,item,index) => ({
    ...obj,
    [item]:index
}), {}
)
console.log(sortByObject(sortBy))
/* {inProgress: 0, todo: 1, done: 2} */

这样就有了排序设置,咱们可以将它与一个可重用的函数放在一起,该函数传入一个数组(data)、一个sortby数组和一个sortField,这样咱们就知道要在哪个字段上排序:

const customSort = ({data, sortBy, sortField}) => {
  const sortByObject = sortBy.reduce(
  (obj, item, index) => ({
      ...obj,
      [item]: index
  }), {})
  return data.sort((a, b) => sortByObject[a[sortField]] - sortByObject[b[sortField]])
}

console.log(customSort({data:tasks, sortBy, sortField: 'status'}))

这样就可以按照咱们的自定义顺序排序,不过还有一个问题,如果列表中有一个status不同的项(不在咱们的排序顺序中),就会出现问题。因此,为了处理这个问题,咱们需要设置一个默认的sort字段来捕获排序中不需要的所有项。

const tasksWithDefault = tasks.map(item => (
  {  
    ...item,
    sortStatus: sortBy.includes(item.status) ? item.status:'other'
  })
 )

这次传递的是更新后的sort字段,那么现在就有了正确的排序顺序,列表底部还有包含状态为 other 的项目。

完整代码:

const tasks = [
  { id: 1, title: "Job A", status: "done" },
  { id: 2, title: "Job B", status: "inProgress" },
  { id: 3, title: "Job C", status: "todo" },
  { id: 3, title: "Job D", status: "onHold" },
  { id: 4, title: "Job E", status: "inProgress" },
  { id: 5, title: "Job F", status: "todo" }
];

const sortBy = ["inProgress", "todo", "done"];

const customSort = ({ data, sortBy, sortField }) => {
  const sortByObject = sortBy.reduce(
    (obj, item, index) => ({
      ...obj,
      [item]: index
    }),
    {}
  );
  return data.sort(
    (a, b) => sortByObject[a[sortField]] - sortByObject[b[sortField]]
  );
};

const tasksWithDefault = tasks.map(item => ({
  ...item,
  sortStatus: sortBy.includes(item.status) ? item.status : "other"
}));
console.log(
  customSort({
    data: tasksWithDefault,
    sortBy: [...sortBy, "other"],
    sortField: "sortStatus"
  })
);

运行结果:

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq449245884/xiaozhi

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。

@YoMiao
Copy link

YoMiao commented Sep 6, 2019

这种方式呢?有什么区别?

const tasks = [
      {id: 1, title: 'Job A', status: 'done'},
      {id: 2, title: 'Job B', status: 'inProgress'},
      {id: 3, title: 'Job C', status: 'todo'},
      {id: 4, title: 'Job D', status: 'inProgress'},
      {id: 5, title: 'Job E', status: 'todo'}
]

const sortBy = ['inProgress', 'todo', 'done']

const customSort = ({data, sortBy, sortField}) => {
      return data.sort((a, b) => {
            return sortBy.indexOf(a[sortField]) - sortBy.indexOf(b[sortField])
      })
}
console.log(customSort({data: tasks, sortBy, sortField: 'status'}))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants