缘起

最近做的一个小需求涉及到排序,界面如下所示:

因为项目是使用vue的,所以实现方式很简单,视图部分不用管,本质上就是操作数组,代码如下:

{
// 上移
moveUp (i) {
// 把位置i的元素移到i-1上
let tmp = this.form.replayList.splice(i, 1)
this.form.replayList.splice(i - 1, 0, tmp[0])
}, // 下移
moveDown (i) {
// 把位置i的元素移到i+1上
let tmp = this.form.replayList.splice(i, 1)
this.form.replayList.splice(i + 1, 0, tmp[0])
}
}

这样就可以正常的交换位置了,但是是突变的,没有动画,所以不明显,于是一个码农的自我修养(实际上是太闲)让我打开了vue的网站,看到了这个示例:https://cn.vuejs.org/v2/guide/transitions.html#%E5%88%97%E8%A1%A8%E7%9A%84%E6%8E%92%E5%BA%8F%E8%BF%87%E6%B8%A1

这个示例我已看过多遍,但是一直没用过,这里刚好就是我要的效果,于是一通复制粘贴大法:

<template>
<transition-group name="flip-list" tag="p">
<!--循环生成列表部分,略-->
</transition-group>
</template> <style>
.flip-list-move {
transition: transform 0.5s;
}
</style>

这样就有交换的过渡效果了,如下:

嗯,舒服了很多,这个需求到这里就完了,但是事情并没有结束,我突然想到了以前看一些算法文章的时候通常会配上一些演示的动画,感觉跟这个很类似,那么是不是可以用这个来实现呢,当然是可以的。

实现算法演示动画

先写一下基本的布局和样式:

<template>
<div class="sortList">
<transition-group name="flip-list" tag="p">
<div
class="item"
v-for="item in list"
:key="item.index"
:style="{height: (item.value / max * 100) + '%'}"
>
<span class="value">{{item.value}}</span>
</div>
</transition-group>
</div>
</template> <style>
.flip-list-move {
transition: transform 0.5s;
}
</style>

list是要排序的数组,当然是经过处理的,在真正的源数组上加上了唯一的index,因为要能正常过渡的话列表的每一项需要一个唯一的key:

const arr = [10, 43, 23, 65, 343, 75, 100, 34, 45, 3, 56, 22]

export default {
data () {
return {
list: arr.map((item, index) => {
return {
index,
value: item
}
})
}
}
}

max是这个数组中最大的值,用来按比例显示高度:

{
computed: {
max () {
let max = 0
arr.forEach(item => {
if (item > max) {
max = item
}
})
return max
}
}
}

其他样式可以自行发挥,显示效果如下:

简约而不简单~,现在万事俱备,只欠让它动起来,排序算法有很多,但是本人比较菜,所以就拿冒泡算法来举例,最最简单的冒泡排序算法如下:

{
mounted(){
this.bubbleSort()
},
methods: {
bubbleSort() {
let len = this.list.length for (let i = 0; i < len; i++) {
for (let j = 0; j < len - i - 1; j++) {
if (this.list[j] > this.list[j + 1]) { // 相邻元素两两对比
let tmp = this.list[j] // 元素交换
this.$set(this.list, j, this.list[j + 1])
this.$set(this.list, j + 1, tmp)
}
}
}
}
}
}

但是这样写它是不会动的,瞬间就给你排好了:

试着加个延时:

{
mounted () {
setTimeout(() => {
this.bubbleSort()
}, 1000)
}
}

刷新看效果:

有动画了,不过这种不是我们要的,我们要的应该是下面这样的才对:

所以来改造一下,因为for循环是只要开始执行就不会停的,所以需要把两个for循环改成两个函数,这样可以控制每个循环什么时候执行:

{
bubbleSort () {
let len = this.list.length
let i = 0
let j = 0
// 内层循环
let innerLoop = () => {
// 每个内层循环都执行完毕后再执行下一个外层循环
if (j >= (len - 1 - i)) {
j = 0
i++
outLoop()
return false
}
if (this.list[j].value > this.list[j + 1].value) {
let tmp = this.list[j]
this.$set(this.list, j, this.list[j + 1])
this.$set(this.list, j + 1, tmp)
}
// 动画是500毫秒,所以每隔800毫秒执行下一个内层循环
setTimeout(() => {
j++
innerLoop()
}, 800)
}
// 外层循环
let outLoop = () => {
if (i >= len) {
return false
}
innerLoop()
}
outLoop()
}
}

这样就实现了每一步的动画效果:

但是这样不太直观,因为有些相邻不用交换的时候啥动静也没有,不知道当前具体排到了哪两个,所以需要突出当前正在比较交换的两个元素,首先模板部分给当前正在比较的元素加一个类名,用来高亮显示:

<div
:class="{sortingHighlight: sorts.includes(item.index)}"
>
<span class="value">{{item.value}}</span>
</div>

js部分定义一个数组sorts来装载当前正在比较的两个元素的唯一的index值:

{
data() {
return {
sorts: []
}
},
methods: {
bubbleSort () {
// ...
// 内层循环
let innerLoop = () => {
// 每个内层循环都执行完毕后再执行下一个外层循环
if (j >= (len - 1 - i)) {
// 清空数组
this.sorts = []
j = 0
i++
outLoop()
return false
}
// 将当前正在比较的两个元素的index装到数组里
this.sorts = [this.list[j].index, this.list[j + 1].index]
// ...
}
// 外层循环
// ...
}
}
}

修改后效果如下:

最后,再参考刚才别人的示例把已排序的元素也加上高亮:

{
data() {
return {
sorted: []
}
},
methods: {
bubbleSort () {
// ...
// 内层循环
let innerLoop = () => {
// 每个内层循环都执行完毕后再执行下一个外层循环
if (j >= (len - 1 - i)) {
this.sorts = []
// 看这里,把排好的元素加到数组里就ok了
this.sorted.push(this.list[j].index)
j = 0
i++
outLoop()
return false
}
// ...
}
// 外层循环
// ...
}
}
}

最终效果如下:

接下来看一下选择排序,这是选择排序的算法:

{
selectSort() {
for (let i = 0; i < len - 1; i++) {
minIndex = i
for (let j = i + 1; j < len; j++) {
if (this.list[j].value < this.list[minIndex].value) {
minIndex = j
}
}
tmp = this.list[minIndex]
this.$set(this.list, minIndex, this.list[i])
this.$set(this.list, i, tmp)
}
}
}

选择排序涉及到一个当前最小元素,所以需要新增一个高亮:

<div
:class="{minHighlight: min === item.index , sortingHighlight: sorts.includes(item.index), sortedHighlight: sorted.includes(item.index)}"
>
<span class="value">{{item.value}}</span>
</div>
{
data () {
return {
min: 0
}
},
methods: {
selectSort () {
let len = this.list.length
let i = 0; let j = i + 1
let minIndex, tmp
// 内层循环
let innerLoop = () => {
if (j >= len) {
// 高亮最后要交换的两个元素
this.sorts = [this.list[i].index, this.list[minIndex].index]
// 延时是用来给高亮一点时间
setTimeout(() => {
// 交换当前元素和比当前元素小的元素的位置
tmp = this.list[minIndex]
this.$set(this.list, minIndex, this.list[i])
this.$set(this.list, i, tmp)
this.sorted.push(this.list[i].index)
i++
j = i + 1
outLoop()
}, 1000)
return false
}
// 高亮当前正在寻找中的元素
this.sorts = [this.list[j].index]
// 找到比当前元素小的元素
if (this.list[j].value < this.list[minIndex].value) {
minIndex = j
this.min = this.list[j].index
}
setTimeout(() => {
j++
innerLoop()
}, 800)
}
let outLoop = () => {
if (i >= len - 1) {
this.sorted.push(this.list[i].index)
return false
}
minIndex = i
this.min = this.list[i].index
innerLoop()
}
outLoop()
}
}
}

效果如下:

其他的排序也是同样的套路,将for循环或while循环改写成可以控制的函数形式,然后可能需要稍微修改一下显示逻辑,如果你也有打算写排序文章的话现在就可以给自己加上动图展示了!

总结

之前看到这些动图的时候也有想过怎么实现,但是都没有深究,这次业务开发无意中也算找到了其中的一种实现方式,其实核心逻辑很简单,关键是很多时候没有想到可以这么做,这也许是框架带给我们的另一些好处吧。

使用vue实现排序算法演示动画的更多相关文章

  1. Canvas制作排序算法演示动画

    tips: 形象化演示排序算法可以让初学者快速理解,比较好的例子:jun-lu的SortAnimate,旧金山大学的David Galles教授的算法演示课件.最近在看canvas,试着用js+can ...

  2. JS写的排序算法演示

    看到网上有老外写的,就拿起自已之前完成的jmgraph画图组件也写了一个.想了解jmgraph的请移步:https://github.com/jiamao/jmgraph 当前演示请查看:http:/ ...

  3. 用HTML5实现的各种排序算法的动画比较 及算法小结

    用HTML5实现的各种排序算法的动画比较 http://www.webhek.com/misc/comparison-sort/ 几种排序算法效率的比较 来源:http://blog.chinauni ...

  4. 链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

    关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学 ...

  5. 用HTML5实现的各种排序算法的动画比較

    用HTML5实现的各种排序算法的动画比較 非常有意思,详见: http://www.webhek.com/misc/comparison-sort/

  6. GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)

    带插件的排序算法演示器 请尊重本人的工作成果,转载请留言.并说明转载地址,谢谢. 地址例如以下: http://blog.csdn.net/fukainankai/article/details/27 ...

  7. http://www.html5tricks.com/demo/jiaoben2255/index.html 排序算法jquery演示源代码

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.or ...

  8. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  9. 用python编写排序算法

    交换排序 === 冒泡排序,快速排序 插入排序 ===直接插入排序,希尔排序 选择排序 === 简单选择排序,堆排序 归并排序 基数排序 冒泡排序 要点 冒泡排序是一种交换排序. 什么是交换排序呢? ...

随机推荐

  1. Junit单元测试:

    * 测试分类: 1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值. 2. 白盒测试:需要写代码的.关注程序具体的执行流程. * Junit使用:白盒测试 * 步骤: 1. 定义一个测 ...

  2. B3log开源博客compose搭建

    B3log开源博客搭建 docker 安装 yum install docker-ce-17.12.1.ce docker-compose 安装 curl -L https://github.com/ ...

  3. MKL库矩阵乘法

    此示例是利用Intel 的MKL库函数计算矩阵的乘法,目标为:\(C=\alpha*A*B+\beta*C\),由函数cblas_dgemm实现: 其中\(A\)为\(m\times k\)维矩阵,\ ...

  4. Bugku CTF练习题---MISC---贝斯手

    Bugku CTF练习题---MISC---贝斯手 flag:flag{this_is_md5_and_base58} 解题步骤: 1.观察题目,下载附件 2.下载后进行解压,得到了一张图片.一个压缩 ...

  5. bs4 & 二进制写入图片视频

    适用于:数据都在网页源代码上,可以直接从中提取到对应数据 例子:北京新发地网 原理:拿到页面源代码的文本,交给BeautifulSoup解析,然后找到对应的标签,获取值 关键词:BeautifulSo ...

  6. 【Java分享客栈】超简洁SpringBoot使用AOP统一日志管理-纯干货干到便秘

    前言 请问今天您便秘了吗?程序员坐久了真的会便秘哦,如果偶然点进了这篇小干货,就麻烦您喝杯水然后去趟厕所一边用左手托起对准嘘嘘,一边用右手滑动手机看完本篇吧. 实现 本篇AOP统一日志管理写法来源于国 ...

  7. ansible中的playbook脚本的介绍与使用

    playbook的数据结构,遵循yaml 后缀名为yaml或者yml,这两个后缀名没有区别 字典{key:value} 列表[]或者- - alex - wusir - yantao - yuchao ...

  8. Nacos源码系列—订阅机制的前因后果(上)

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 nacos,即可免费获取源码 前因 我们在了解Nacos订阅机制之前, ...

  9. 1903021121-刘明伟-java十一周作业-java面向对象编程

    项目 内容 课程班级博客链接 19级信计班(本) 作业要求链接 第十一周作业 博客名称 1903021121-刘明伟-java十一周作业-java面向对象 要求 每道题要有题目,代码(使用插入代码,不 ...

  10. 词云图value传递数据不显示(已解决)

    问题描述: 今天在做词云图时,虽然词云图能够展现出来,但是后台传递过来的数据(每个词出现的次数)却不显示. 错误原因: 错误的将tooltip写在了series内部,如图: 解决方案: 将toolti ...