前面已经搞定了这个冒泡排序过程展示器的基础功能。详见:
一块学Vue:学习日记_2020.1.4 - 利用Vue实现冒泡排序的过程展示器https://blog.csdn.net/qq493919692/article/details/103800727
虽然已经算是能完成我们的需求了,但是使用的时候体验极差,前文在最后也列举了一些需要优化的问题。
本文就是介绍怎么解决这些问题。
前文列举出来的问题有三个。
问题1:
runRound()和runBubbleSort()因为没有设置延迟,所以点击之后,直接把最终结果呈现出来了,中间过程全部跳过。
这里就得看需求了,需不需要中间的过程,需要的话,我们还需要去设置延迟。
问题2:
按照逻辑来讲,GoToNext按钮必须在Compare按钮点击之后才可以点击。
GoToNextRound按钮必须在RunRound按钮点击之后,或者这轮最后一次compare()方法执行之后才可以点击。
对这两个按钮,我们也需要做一定的操作限制。
问题3:
使用的舒适度还欠佳。实际使用的时候,不能返回上一步,也不能重置数组,这就会使得操作失误的时候,想要重归正轨就很麻烦。
数组数据也还不能在网页上自定义改动,不够灵活。
需求:假设,我们的需求就是点击runRound()或runBubbleSort()后,能像看动画一样看着数组一步一步自动完成相应操作。
所需数据:
setTimerRound – Number变量,用于存储runRound()中需要使用到的setTimeout的id,初始值为NaN。
setTimerBubbleSort – Number变量,用于存储runBubbleSort()中需要使用到的setTimeout的id,初始值为NaN。
实现方法分析:
想要让runRound()或runBubbleSort()的过程逐步进行,最简单的方法就是使用setTimeout来设置延迟,模拟动画的效果。
先说runRound()该如何实现。
runRound()要完成的操作是compare() => goToNext() => compare() => goToNext() => … 直到游标到了倒数第二个数,再执行一次compare()。本来我们使用while循环来实现,现在有了setTimeout的加入,while循环就可以改成if判定语句。
假设,我们想要每个步骤执行完后要停留一秒,再执行下一步。
JS改动:
这样,runRound()就算完成了,再来看看runBubbleSort()该如何实现。
看了一下runBubbleSort()的代码,跟runRound()的格式很像啊。所以我们用同样的改动方法,while循环就可以改成if判定语句,加入setTimeout。
但这里需要注意一下,在runBubbleSort()中,我们是需要等runRound()执行完,才去执行goToNextRound(),所以触发goToNextRound()的延迟时间不能再是1000毫秒了,而是要大于一轮找最大值需要花费的时间。
一轮找值需要花费的时间应该等于里面所有的延迟加上里面所有操作需要花费的时间。延迟好计算,但是所以计算操作需要花费的时间就很难得知了。
所以,这里我准备换个思路来实现。让runRound()方法完成一整轮的操作之后再去调用goToNextRound()。想达到这个效果有种简单的方法:就是在runRound()中加入一个回调函数,当runRound()功能完成后调用这个回调函数。runRound()最后一次触发compare()之后,就意味着runRound()结束了,所以这个回调函数,我们放在最后一个compare()之后。
JS改动:
执行了一下runRound()和runBubbleSort(),确实实现了我们想要的效果。
但是,又发现了一个问题,就是在执行runRound()或runBubbleSort()时,如果我们点击了其他三个操作的按钮,是会造成一定影响的。这就涉及到问题2了,我们把这里的问题留到下面一块处理。
需求:
GoToNext按钮必须在Compare按钮点击之后才可以点击。
GoToNextRound按钮必须在runRound功能完全完成后,或者这轮找值最后一次compare()方法执行之后才可以点击。
在执行runRound()或runBubbleSort()时,另外的所有按钮包括他们自身不能被点击。
所需数据:
isCompareDisabled – Boolean变量,用于控制Compare按钮能否使用,初始值为false。
isGoToNextDisabled – Boolean变量,用于控制GoToNext按钮能否使用,初始值为true。
isRunRoundDisabled – Boolean变量,用于控制RunRound按钮能否使用,初始值为false。
isGoToNextRoundDisabled – Boolean变量,用于控制GoToNextRound按钮能否使用,初始值为true。
isRunBubbleSortDisabled – Boolean变量,用于控制RunBubbleSort按钮能否使用,初始值为false。
isAuto – Boolean变量,用于判断是否处在runRound或runBubbleSort状态。
实现方法分析:
button的禁用\启用涉及到一个特性:disabled,我们可以使用Vue中的v-bind绑定disabled特性来实现动态修改button的禁用\启用状态。
然后,我们开始分析需求。需求前两句是可以结合起来的,GoToNext按钮必须在Compare按钮点击之后才可以点击。GoToNextRound按钮必须在runRound功能完全完成后,或者这轮找值最后一次compare()方法执行之后才可以点击。
我们还可以再丰富一下需求,下一次Compare按钮必须在GoToNext按钮点击之后才能点击,下一次RunRound按钮必须在GoToNextRound按钮点击之后才能点击。
runRound()功能如何确定是否已经完全完成,在问题1中,我们已经分析过了,runRound中的最后一次compare()执行完就代表runRound()功能已经完全完成。
显然,都是跟compare()有关的,我们可以把这部分控制语句都放到compare()中去实现。前面其实已经做过一定工作了,就是提示语的添加。我们可以把这部分控制语句加到相应的提示语下面。
其他的控制语句就找到对应的方法中去添加。
再看最后一个需求,在执行runRound()或runBubbleSort()时,另外的所有按钮包括他们自身不能被点击。
需要在runRound()或runBubbleSort()的开头将所有操作按钮禁用,且保证中间这些按钮不再被启用。等到操作完成之后,再设置成他们该有的状态:
runRound结束后,Compare、GoToNextRound、RunBubbleSort按钮需要被启用;
runBubbleSort结束后,五个操作按钮需要保持禁用。
这里就需要isAuto参数来作为是否处在runRound或runBubbleSort状态的判定依据。因为当处在这两种状态时,RunRound按钮和RunBubbleSort按钮都是禁用的,所以isAuto = isRunRoundDisabled && isRunBubbleSortDisabled,再结合Vue的计算属性机制,就可以让isRunRoundDisabled或者isRunBubbleSortDisabled的数据发生变动时,isAuto的数值也能实时更新。
需求:
使用的舒适度还欠佳。实际使用的时候,不能返回上一步,也不能重置数组,这就会使得操作失误的时候,想要重归正轨就很麻烦。
数组数据也还不能在网页上自定义改动,不够灵活。
所需数据:
history – Array变量,记录过去的数据情况,用于实现返回上一步
destArrayStr – String变量,用于存储用户输入的数组字符串。
isBackDisabled – Boolean变量,用于控制Back按钮能否使用,初始值为false。
isRestartDisabled – Boolean变量,用于控制Restart按钮能否使用,初始值为false。
destArray
实现方法分析:
在需求中,提出了三种操作:1.返回上一步 2.重置 3.自定义设置数组
如何实现返回上一步的操作。
我们要知道,页面呈现的内容其实都是由data中的数据渲染出来的。所以,记录上一步的情况,就等于要记录上一步时data中的数据情况。为了实现能返回很多步之前的操作,我们用了一个数组来存储过去每一步的数据情况。
那如何实现重置功能就更简单了,data中数据恢复到初始状态就行。
最后,如何自定义设置数组呢。我们在网页中加入一个输入框,使用Vue中的v-model将输入内容与data中的destArrayStr绑定。然后把destArray的修改操作加入到侦听器中去,当destArrayStr发生变化时,destArray也会改动。
为什么要这样做处理呢,因为destArray变量是Array类型的,而input输入框中的内容是String类型的,是不能直接绑定的。当然,要是考虑输入的数组可能是错误的,我们还需要在计算的时候对destArrayStr做检查。
那这里为什么不用计算属性了呢。因为我们要考虑到当用户在输入新的数组时,操作按钮的启用\禁用状态也是要初始化的。需要做其他一系列数据改动的话,我觉得还是应该放在侦听器中使用。而且如果再考虑到要对用户输入操作添加防抖\节流的话,我觉得也是最好放在侦听器中实现。
下面开始具体的代码编写。
HTML改动:
HTML中添加了数组的输入框;back和restart的按钮;考虑到数组中可能出现相同的数,原先number-box中的v-bind:key="item"就不适用了,修改成v-bind:key=“index”。
问题完成的情况还是可以的,功能也都能实现,测试下来暂时没有发现bug。
但是吧,还是有优化的空间。
就我写的过程中发现的:
问题1.RunRound和RunBubbleSort结束后,点击Back按钮,会直接跳回到按钮点击前的状态,而不是冒泡排序操作流的前一步状态。
问题2.按钮启用\禁用状态的控制很杂乱,语句东一句西一句,不方便管理修改与进一步开发。
问题3.runRound()函数就从调用compare()开始的,如果现在处在刚点完compare()的状态,其实这一次compare()的调用会很多余。同样,runBubbleSort()是从runRound()开始的,如果刚点完runRound()的状态,这次调用也会很多余。
我暂时想到的一种解决方案就是,申请一个变量作为标识符,用于指明现在处在什么状态,然后各个按钮启用\禁用状态的绑定变量由这个标识符计算而出。这样在其他方法中只需要修改这个标识符,就可以做到对所有按钮的启用\禁用状态控制。
这样也可以方便解决问题一和问题3。我会说就是用现在的结构来解决这些问题太麻烦了,我才没有直接解决掉这些问题吗?等下一篇优化2中改完结构,我再来一块解决这个问题吧~
年底的事情还真的有点多呢,本来准备还每天写一篇日记的,再加上写作的水平也不太行,总感觉要考虑的东西好多啊,写的东西总得修修改改的。实际做下来,进度还是与预期相差甚远呢。还得继续加油呀!