SOURCE

console 命令行工具 X clear

                    
>
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;
}