supce's blog

听指令的小方块(四)


基于上个任务,继续进行改进

任务描述

  • 命令输入框由input变为textarea,可以允许输入多条指令,每一行一条
  • textarea左侧有一列可以显示当前行数的列(代码行数列),列数保持和textarea中一致
  • 当textarea发生上下滚动时,代码行数列同步滚动
  • 能够判断指令是否合法,不合法的指令给出提示
  • 点击执行时,依次逐条执行所有命令
  • 对于GO,TRA以及MOV指令增加可以移动格子数量的参数,例如
  • GO 3:向当前方向前进三格
  • TRA TOP 2:向屏幕上方平移两格
  • MOV RIG 4:方向转向屏幕右侧,向屏幕的右侧移动四格

整体思路

首先根据要求,修改HTML结构,并设置基本样式。

<div id="container" class="clearFix">
    <div id="dispaly_box">
        <canvas id="canvas_bg" width="441" height="441"></canvas>
        <div id="square"></div>
    </div>
    <div id="control_panel">
        <ol id="identifier">
            <li>1</li>
        </ol>
        <textarea id="orders"></textarea>
        <button id="btn_exe">执行</button>
    </div>
</div>
<div id="instruction">
   //介绍
</div>

    #control_panel{
        padding: 40px 0;
        float: right;
        width: 441px;
        height: 441px;
    }
    #control_panel ol{
        float: left;
        margin: 0;
        padding: 0;
        width: 25px;
        height: 400px;
        background-color: #ccc;
        overflow: hidden;
    }
    #control_panel li{
        list-style: none;
        width: 25px;
        height: 25px;
        line-height: 25px;
        text-align: center;
        color: white;
    }
    #orders{
        padding: 0;
        padding-left: 2px;
        width: 410px;
        height: 400px;
        outline: none;
        border: none;
        font-size: 20px;
        line-height: 25px;
        vertical-align: middle;
        overflow-y: auto;
        background-color: rgb(43,43,43);
        color: rgb(86,187,86);
        resize: none;
    }
    .clearFix:after{
        clear: both;
        display: block;
        visibility: hidden;
        content: "";
        height: 0;
        line-height: 0;
    }
    .error{
        background-color: red;
    }
    #instruction{
        margin: 10px auto;
        width: 800px;
    }

下面,新增一个textArea.js,添加一个函数,帮助获取文本域中的指令行数

function getTextLine(){
    var txt = $("#orders").value;
    var arr = txt.split("\n");
    return arr.length;
}

然后增加一个函数,以获取显示当前行数的列

function getIdentifier(){
    var eleNodes = [];
    var nodes = Array.prototype.slice.call($("#identifier").childNodes);
    for(var i=0;i<nodes.length;i++){
        if(nodes[i].nodeType == 1){
            eleNodes.push(nodes[i]);
        }
    }
    return eleNodes;
}

最后,编写一个检测指令是否合法的函数

function checkValue(value){
    var order_two = ["LEF","RIG","BAC"];
    var order_three = ["LEF","RIG","TOP","BOT"];
    var comms = value.split(" ");
    if(comms.length>3 || comms.length<0){ //如果指令组成大于3或者小于0 返回false
        return false;
    }else if(comms.length == 1){
        if(comms[0] == "GO"){
            return true;
        }
        return false;
    }else if(comms.length == 2){
        if(comms[0]=="GO" && !isNaN(comms[1])){
            return true;
        }else if(comms[0]=="TUN" && isMatch(comms[1],order_two)){
            return true;
        }else if((comms[0]=="TRA"||comms[0]=="MOV") && isMatch(comms[1],order_three)){
            return true;
        }else{
            return false;
        }   
    }else if(comms.length == 3){
        if((comms[0]=="TRA"||comms[0]=="MOV") && isMatch(comms[1],order_three) && !isNaN(comms[2])){
            return true;
        }else{
            return false;
        }
    }
    function isMatch(value,arr){
        for(var i=0,len=arr.length;i<len;i++){
            if(value == arr[i]){
                return true;
            }
        }
        return false;
    }
}

然后对文本域进行事件绑定,当用户按下回车键后,对指令进行检测,然后增加新的行数

addHandler($("#orders"),"keydown",function(e){
    if(e.keyCode == 13){
        //保存输入的指令并获取行数
        var txt = $("#orders").value;
        var arr = txt.split("\n");
        var line = arr.length;
        //获取最后一行的指令
        var value = arr[line-1];
        //获取行号节点
        var indexs = getIdentifier();
        //指令不正确则红色标注
        if(!checkValue(value)){
            indexs[line-1].className = "error";
        }
        //添加行数
        var li = document.createElement("li");
        li.innerHTML = line+1;
        $("#identifier").appendChild(li);
    }
});

为了实现删除某行指令后,删除前面行号的效果,需要绑定的键盘的keyup事件,检测实际指令行数和行号是否一致,不一致则删除最后一行。

addHandler($("#orders"),"keyup",function(e){
    if(e.keyCode == 8){
        var line = getTextLine();
        var indexs = getIdentifier();
        if(line !== indexs.length){
            $("#identifier").removeChild(indexs[indexs.length-1]);
            indexs[indexs.length-2].className = "";
        }
    }
});

最后实现行号列和指令列的同步滚动

addHandler($("#orders"),"scroll",function(e){
    var top = $("#orders").scrollTop;
    $("#identifier").scrollTop = top;
});

最终代码

最终代码
demo


两周时间一直专注于课题组的课题,今天是16年最后一天,挤出点时间,更新出今年的最后一篇 O(∩_∩)O