缘起

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

因为项目是使用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. Ajax错误处理

    控制台报的错误是: Access to XMLHttpRequest at 'http://localhost:3000/error' from origin 'null' has been bloc ...

  2. 超越iTerm! 号称下一代终端神器,功能贼强大!

    程序员的一生,用的最多的两个工具,一个是代码编辑器(Code Editor),另外一个就是命令行终端工具(Terminal).这两个工具对于提高开发效率至关重要. 代码编辑器在过去的 40 年里不断进 ...

  3. windows 安装 kalfka 并快速启动

    1.安装Java 环境 https://www.java.com/zh_CN/ 直接下载安装即可 (如果之前有配置过java环境 可以先跳过此步骤,但是如果运行的时候报错就需要把之前的jdk环境变量删 ...

  4. 4.27-Postman和JMeter总结及实战描述

    一.数据格式 常用的请求方法有8种,但是最常用的有4-5种 1.GET 获取资源 2.POST 添加资源(对服务端已存在的资源也可以做修改和删除操作) 3.PUT 修改资源 4 .DELETE删除资源 ...

  5. vmware安装或卸载时,显示无法打开注册表项

    ​ vmware卸载是出了名的臭名昭著,因为太难删干净了,删不干净又会有各种各样的问题.比如下文这个"无法打开注册表项" 这个我相信有很多人在重装vmware的时候遇到过,因此我来 ...

  6. Azure DevOps (十二) 通过Azure Devops部署一个SpringBoot应用

    文章配套视频专栏: https://space.bilibili.com/38649342/channel/seriesdetail?sid=2267536 视频正在努力更新. 上一篇文章中,我们通过 ...

  7. 3D离线地图开发

    3D离线地图介绍(3D离线采用矢量数据作为地图基础,可保持地图数据最新) 一.开发中引用3D离线地图(可独立部署通过内外IP+端口进行访问,也可拷贝js库文件到项目中通过绝对路径访问) 1).离线AP ...

  8. 评价管理后台PC端

    1.css动画效果    --2020.12.26 2.remove() --2020.12.28 3.执行顺序 --2020.12.30 4.联动 --2021.01.06 5.奥利给~ --202 ...

  9. springcloud + nacos实现共用基础服务(灰度版本)

    背景: 当我们使用微服务时,若想在本地联调就需要启动多个服务,为了避免本地启动过多服务,现将注册中心等基础服务共用.当我们在服务A开发时,都是注册到同一个nacos,这样本地和开发环境的服务A就会同时 ...

  10. 实验:Python图形图像处理

    1. 准备一张照片,编写Python程序将该照片进行图像处理,分别输出以下效果的图片:(a)灰度图:(b)轮廓图: (c)变换RGB通道图:(d)旋转45度图. 2. 假设当前文件夹中data.csv ...