console
const INTERVAL = 500;
class Controller {
constructor(node, tree) {
const self = this;
this.node = node;
this.tree = tree;
this.stopBtn = node.querySelector('.stop');
this.preBtn = node.querySelector('.pre');
this.inBtn = node.querySelector('.in');
this.postBtn = node.querySelector('.post');
this.resetBtn = node.querySelector('.reset');
this.inBtn.addEventListener('click', this.in.bind(this));
this.preBtn.addEventListener('click', this.pre.bind(this));
this.postBtn.addEventListener('click', this.post.bind(this));
this.stopBtn.addEventListener('click', this.stop.bind(this));
this.resetBtn.addEventListener('click', this.reset.bind(this));
}
pre() {
if (this.tree.isStop()) {
this.tree.exec('preOrderTraversal');
}
}
in() {
if (this.tree.isStop()) {
this.tree.exec('inOrderTraversal');
}
}
post() {
if (this.tree.isStop()) {
this.tree.exec('postOrderTraversal');
}
}
stop() {
this.tree.pause();
}
reset() {
this.tree.clean();
}
}
class Tree {
constructor(node) {
this.node = node;
this._stop = true;
this._couter = 0;
}
async exec(command) {
await this.clean();
this._stop = false;
switch(command) {
case 'preOrderTraversal':
await this._preOrderTraversal(this.node, this._traversal);
break;
case 'inOrderTraversal':
await this._inOrderTraversal(this.node, this._traversal);
break;
case 'postOrderTraversal':
await this._postOrderTraversal(this.node, this._traversal);
break;
default:
break;
}
this._stop = true;
}
async _postOrderTraversal(node, handler) {
if (!node)
return;
await this._postOrderTraversal(node.children[0], handler);
await this._postOrderTraversal(node.children[1], handler);
await handler.call(this, node);
}
async _inOrderTraversal(node, handler) {
if (!node)
return;
await this._inOrderTraversal(node.children[0], handler);
await handler.call(this, node);
await this._inOrderTraversal(node.children[1], handler);
}
async _preOrderTraversal(node, handler) {
if (!node)
return;
await handler.call(this, node);
await this._preOrderTraversal(node.children[0], handler);
await this._preOrderTraversal(node.children[1], handler);
}
async clean() {
this._stop = true;
this._couter = 0;
await this._preOrderTraversal(this.node, this._cancleTraversal);
}
async _traversal(node) {
if (this._stop) {
return Promise.reject();
}
node.classList.add('active');
node.setAttribute('data-num', ++this._couter);
await this.delay(INTERVAL);
}
async _cancleTraversal(node) {
node.classList.remove('active');
node.setAttribute('data-num', '');
}
async delay(ms) {
return (new Promise((resolve, reject)=> {
setTimeout(()=> {
resolve();
}, ms);
}));
}
pause() {
this._stop = true;
}
isStop() {
return this._stop;
}
}
const tree = new Tree(document.querySelector('#root'));
const controller = new Controller(document.querySelector('.controller'), tree);
controller.pre();
<div class="box" id="root">
<div class="box">
<div class="box">
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
</div>
<div class="box">
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
</div>
</div>
<div class="box">
<div class="box">
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
</div>
<div class="box">
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
<div class="box">
<div class="box">
</div>
<div class="box">
</div>
</div>
</div>
</div>
</div>
<div class="controller">
<button class="stop">Stop</button>
<button class="pre">先序遍历</button>
<button class="in">中序遍历</button>
<button class="post">后序遍历</button>
<button class="reset">Reset</button>
</div>
* {
box-sizing: border-box;
}
.box {
display: flex;
flex: 0 0 50%;
height:70%;
flex-wrap: wrap-reverse;
justify-content:center;
align-items: flex-end;
color:#fff;
&:after {
content:attr(data-num);
height:30%;
flex: 0 0 50%;
background-color: #ddd;
border-radius: 100%;
text-align:center;
line-height:2;
}
}
#root {
width: 100%;
height: 300px;
}
.active:after {
background-color: #0000ff;
}
.test {
width: 200px;
height: 200px;
background-color: #ddd;
&:after {
content:'1';
width: 90px;
height:90px;
background-color: #aaa;
}
}
.controller {
display: flex;
justify-content: space-around;
}