xiaoyu's blog

Coding for a better life!

0%

可视化之冒泡排序

  • 实现思路

使用js移动元素位置,利用css的transition属性实现过渡动画。在线体验

创建一个数组arr,数组的每一项保存着节点元素的文本值(innerText)和元素在节点列表中的索引nodeIndex, 因为接下来的并不是真的交换两个节点,而是交换两个节点的位置(可能有点不好理解)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function init() {
let fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
let div = document.createElement('div'),
num = parseInt(Math.random() * 10);
arr.push({
val: num,
nodeIndex: i, //这里保存的是节点在nodeList中的位置
});

//

}
}

举例说明:

在页面中,从左往右肉眼观测到的元素位置是这样的(order表示从左往右的顺序)

order 0 1 2
nodeIndex 0 1 2
val 3 2 1

3 > 2, swap(3, 2)

在经过第一次交换之后,元素的位置变成了:

order 0 1 2
nodeIndex 1 0 2
val 2 3 1

所以,接下来要交换位置的节点是 (0, 2) 而不是 (1, 2)。

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<script>
let nodeList = document.getElementsByClassName('num'),
reloadBtn = document.querySelector('.reload'),
sortBtn = document.querySelector('.sort');
let initColor = 'rgb(173, 216, 230)', activeColor = 'rgb(0, 128, 0)', sortedColor = 'rgb(255, 165, 0)';
let showConsoleNode = document.querySelector('.showConsole');
let arr = [], timeout = 1;

function handleChange() {
let selectOps = document.querySelector('#speed-control');
// console.log(selectOps)
let selectIdx = selectOps.selectedIndex;
let val = selectOps.options[selectIdx].value;
timeout = Number(val);
console.log(timeout)
}

function swapPosition(node1, node2) {
[node1.style.left, node2.style.left] = [node2.style.left, node1.style.left];
}

function setBgColor(nodeArr, color) {
for (let i = 0; i < nodeArr.length; i++) {
nodeArr[i].style.background = color;
}
}

function resetColor(node1, node2, lastIndex) {
setTimeout(() => {
// console.log(node1.style.left);
if (Number(node1.style.left.replace('px', '')) === lastIndex * 50) {
setBgColor([node2], initColor);
setBgColor([node1], sortedColor)
} else {
setBgColor([node1, node2], initColor)
}
}, timeout * 0.7 * 1000);
}

function swap(arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
function bubbleSort(arr) {
let len = arr.length, cnt = 0;
sortBtn.disabled = reloadBtn.disabled = true;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - i - 1; j++) {
let node1 = nodeList[arr[j].nodeIndex],
node2 = nodeList[arr[j + 1].nodeIndex];
cnt++;
let val1 = arr[j].val, val2 = arr[j + 1].val;
if (val1 > val2) {
setTimeout(() => {
resetColor(node1, node2, len - i - 1);
setBgColor([node1, node2], activeColor);
setTimeout(() => {
swapPosition(node1, node2);
}, timeout * 0.6 * 1000);
showConsoleNode.innerText =
`compare ${val1} with ${val2}\n${val1} > ${val2}, swap(${val1}, ${val2})`;
}, cnt * timeout * 1.6 * 1000);
swap(arr, j, j + 1);
} else {
setTimeout(() => {
setBgColor([node1, node2], activeColor);
showConsoleNode.innerText =
`compare ${val1} with ${val2}`;
resetColor(node2, node1, len - i - 1);
}, cnt * timeout * 1.6 * 1000);
}
}
}
setTimeout(() => {
showConsoleNode.innerText = null;
sortBtn.disabled = reloadBtn.disabled = false;
setBgColor(nodeList, initColor)
}, cnt * timeout * 1.6 * 1000 + timeout * 1.6 * 1000);
}

function init() {
let fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
let div = document.createElement('div'),
num = parseInt(Math.random() * 10 + 1);
arr.push({
val: num,
nodeIndex: i, //这里保存的是节点在nodeList中的位置
});
div.className = 'num';
div.style.height = `${num * 20}px`;
div.style.left = `${i * 50}px`;
div.style.bottom = '0';
div.style.background = initColor;
div.style.transition = `left ${timeout}s, background ${timeout * 0.6}s`;
div.innerText = num;
fragment.append(div);
}
document.querySelector('.animate-contanier').append(fragment);
}

function reload() {
arr = [];
for (let i = 0; i < 10; i++) {
let div = nodeList[i],
num = parseInt(Math.random() * 10 + 1);
arr.push({
val: num,
nodeIndex: i,
});
div.style.left = `${i * 50}px`;
div.style.bottom = '0';
div.style.height = `${num * 20}px`;
div.innerText = num;
}
}

init();
</script>