用vue開發一個所謂的數獨

HesterMarin 7年前發布 | 19K 次閱讀 Vue.js Vue.js開發

1.前言

最近的后臺管理系統頁面,功能暫時沒有新的需求,就在想首頁放什么東西,最近我想到的就是放個所謂的數獨,為什么是所謂的數獨,因為規則不同于標準的數獨,只要求每一行每一列數字不一樣就可以了!這個實例也是基于vue的,代碼分享給大家。給大家代碼,并不是要讓大家直接拷貝代碼,而是希望能讓大家當做是一個練手的項目,或者學習到知識。如果大家覺得我哪里寫得不好,寫錯了,歡迎指出,讓大家交流意見,一起進步。

2.運行效果

3.實現步驟

實現步驟,感覺說得有點繞,建議大家邊寫邊看文章,這樣不會懵。或者直接去看源碼( sudoku ),把源碼看懂!這個項目也不復雜!

3-1.準備數據和排版

排版的 html+css 代碼我不多說了,排版很簡單,這個相信都難不倒大家的。復雜一點的就是數據的交互!

下面開始第一步,把數獨的數據先準備好,數據是什么,大家都知道,就是像下面這樣的數據!

排版出來的效果就是下面這樣。

html 代碼如下

<div class="num-table" @mouseleave="hoverCol=''" :class="{'shake':isShake}">
    <!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row chearfix">
        <!--遍歷行里面的每一列-->
        <div v-for="num1,indexSub in row" class="num-col">
            {{allNumText[index][indexSub]}}
        </div>
    </div>
</div>

代碼也很簡單,如下

mounted(){
    let arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let row = [], rowCol = 0;
    for (let i = 0, len = arr1.length; i < len; i++) {
        row = Object.assign([], arr1);
        this.allNum.push(row);
        //刪除第一個數字并記錄下來
        rowCol = arr1.splice(0, 1)[0];
        //在最后面插入數字
        arr1.push(rowCol)
    }
}

大家也可以發現,這個數據,的每一行和每一列的數字都是不同樣的!

3-2.打亂行

之后就是隨機打亂順序了,打亂順序這個得保證一個前提,就是保證每一行每一列的數字都不一樣。這樣的話,我用了一個簡單粗暴的方法-以行或者列為單位,進行打亂。比如,第一行和第三行進行位置交互,第一列和第五列進行位置的交換。下面說下以行為單位的打亂順序!

行的打亂,很簡單,就是隨機打亂數組而已!一行代碼搞定!

this.allNum.sort((n1, n2) => Math.random() - 0.5);

3-3.打亂列

行打亂了,下面進行以列為單位的打亂,這個稍微復雜一點。

大家想下,比如第二列是第五列的值進行交換,那就是每一行的第二個格子的值和第五個格子的值進行交換,那么就需要遍歷每一行!來進行交換,至于前面說的第二列和第五列的這個列數,可以用一個函數實現!

下面看代碼!

//隨機獲取兩列的索引
function randomText() {
    let rondomIndex = 0, rondomIndexAfter = 0;
    //獲取第一列的索引
    rondomIndex = Math.floor(Math.random()  9);
    function randomDo() {
        rondomIndexAfter = Math.floor(Math.random()  9);
        //如果第一列和第二列索引一樣,第二列的索引再次重新隨機獲取
        if (rondomIndexAfter === rondomIndex) {
            randomDo();
        }
    }

randomDo();
//返回兩列的索引
return [rondomIndex, rondomIndexAfter]

}

//打亂列 let randomArr = [], nowValue = 0; //同樣遍歷9次 for (let i = 0; i < 9; i++) { randomArr = Object.assign([], randomText()); //遍歷每一行,給每一行的隨機兩列交換值 for (let j = 0, len = this.allNum.length; j < len; j++) { //隨機兩列交換值 nowValue = this.allNum[j][randomArr[0]]; this.allNum[j][randomArr[0]] = this.allNum[j][randomArr[1]]; this.allNum[j][randomArr[1]] = nowValue; } }</code></pre>

3-3.隨機掏空單元格

掏空單元格就是把一些格子隨機設空,然后讓玩數獨的人。把這些單元格給填上!

需求,我現在實現的就是,每一行有把兩個格子設空,這里我的做法是,把每一個格子的坐標先記錄下來,然后再從記錄的坐標里面隨機獲取坐標,用獲取到的坐標,進行設空!

首先,獲取所有點的坐標

//記錄所有坐標
let rowText = '', arrText = []
for (let i = 0; i < 9; i++) {
    rowText = ''
    for (let j = 0; j < 9; j++) {
        rowText += i + '-' + j + ',';
    }
    arrText.push(rowText.substr(0, rowText.length - 1))
}
console.log(arrText);

看到這個坐標,大家很容易的知道,數組的一個元素,就是第一行,‘ 0-0 ’就是第一行第一個格子。數組最后一個元素,就是最后一行,‘ 8-8 ’就是最后一行,最后一個格子,其他如此類推!

下面進行隨機掏空,代碼也很簡單!

//隨機掏空
let nowItme = [], _option, nowOption = [];
for (let i = 0; i < 9; i++) {
    //抽取當前行的所有坐標
    nowItme = arrText[i].split(',');
    nowOption = [];
    //當前行的隨機兩個坐標掏空
    for (let j = 0; j < 2; j++) {
        //抽取當前行的隨機一個坐標
        _option = Math.floor(Math.random() * nowItme.length);
        //分割坐標的x,y
        nowOption = nowItme.splice(_option,1)[0].split("-");
        this.allNum[nowOption[0]][nowOption[1]] = '';
    }

}</code></pre>

這樣相信大家都覺得奇怪,下面進行下樣式的該寫,就是把設空了的格子的樣式改一下! .no 這個 class 對應的樣式我在 css 那里寫好了,大家注意下。

<!--遍歷每一行-->
<div v-for="row,index in allNum" class="num-row chearfix">
    <!--遍歷行里面的每一列-->
    <!--
        no:被掏空數組的樣式
    -->
    <div v-for="num1,indexSub in row" :class="{'no':num1===''}" class="num-col">
        {{allNumText[index][indexSub]}}
    </div>
</div>

3-4.顯示數字鍵盤

首先,我簡單的用一個流程圖說下邏輯,如下

然后關于數字鍵盤的位置,看下圖(數字鍵盤的樣式我不多說了,就是一個是相對定位,一個絕對定位的設置而已)

如上圖,我點擊的是第一行第三個格子,首先,我期待被點擊的格子的樣式有所改變,方便我區分,這個不難,用一個 class 改變樣式就可以了,這個可以看下面的代碼,我用一個 .cur 的 class 控制樣式。還有一個就是期待數字鍵盤在第二行,第四個格子那里出現。這樣的話,大家就知道,數字鍵盤的位置是怎么定位的了!數字鍵盤的 top 就是,被點擊格子所在的行的索引+1 60(60是格子的寬高), left 就是,被點擊格子所在的列的索引+1 60(60是格子的寬高)。比如上圖,第一行第三個格子, top=(0+1)*60+'px',left=(2+1)*60+'px' 。

代碼如下

<!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row chearfix">
        <!--遍歷行里面的每一列-->
        <!--
            no:被掏空數組的樣式
            cur:格子被點擊時觸發,被點擊的格子樣式
        -->
        <div v-for="num1,indexSub in row"
             :class="{'no':num1==='',
             'cur':curRow===index&&indexSub===curCol}"
             @click="showCheck(index,indexSub)" class="num-col">
            {{allNumText[index][indexSub]}}

    </div>
</div>

<!--數字鍵盤--> <div class="num-check chearfix" :style="{'top':(curRow+1)60+'px','left':(curCol+1)60+'px'}" v-show="checkShow"> <ul> <li @click="inputText(1)">1</li> <li @click="inputText(2)">2</li> <li @click="inputText(3)">3</li> <li @click="inputText(4)">4</li> <li @click="inputText(5)">5</li> <li @click="inputText(6)">6</li> <li @click="inputText(7)">7</li> <li @click="inputText(8)">8</li> <li @click="inputText(9)">9</li> </ul> </div></code></pre>

js代碼

/**

  • @description 顯示數字鍵盤
  • @param i1
  • @param i2 */ showCheck(i1, i2){ //點擊的格子是否是被掏空的格子 if (this.allNum[i1][i2] !== '') {

     return
    

    } //點擊的格子如果是上一次點擊的格子(當前格子) if (i1 === this.curRow && i2 === this.curCol) {

     //隱藏數字鍵盤,curRow和curCol設空
     this.checkShow = false;
     this.curRow = '';
     this.curCol = '';
    

    } else {

     //隱藏數字鍵盤,curRow和curCol分別設置成當前的點
     this.checkShow = true;
     this.curRow = i1;
     this.curCol = i2;
    

    } },</code></pre>

    運行效果

    3-5.高亮顯示同行同列

    這一步很簡單,首先,高亮顯示行,大家都知道怎么做了,就是行對應的 div ,設置一個 :hover ,然后對應設置單元格的樣式而已!這個不多說!

    然后,高亮顯示列,復雜一點,但是也很簡單,原理我想大家也知道,就是當鼠標進如格子的時候,在 data 里面,用一個變量儲存進入的格子的列的索引,然后加上判斷,如果格子的列的索引等于進入的格子的列的索引。就加上一個 class ,這里我用 .cur-col 。代碼如下

    <!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row clear">
     <!--遍歷行里面的每一列-->
     <!--
         no:被掏空數組的樣式
         cur:格子被點擊時觸發,被點擊的格子樣式
         cur-col:鼠標進入的時候觸發,和被點擊格子同一列的格子的樣式
     -->
     <div v-for="num1,indexSub in row"
          :class="{'no':num1==='',
          'cur':curRow===index&&indexSub===curCol,
          'cur-col':hoverCol===indexSub}"
          @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
         {{allNumText[index][indexSub]}}
     </div>
    </div>

    運行效果

    3-6.填寫操作和錯誤提示

    這一步的操作函數,我直接發代碼吧,看代碼比我說的會清晰些,畢竟說的有點繞

    <!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row clear">
     <!--遍歷行里面的每一列-->
     <!--
         no:被掏空數組的樣式
         cur:格子被點擊時觸發,被點擊的格子樣式
         cur-col:鼠標進入的時候觸發,和被點擊格子同一列的格子的樣式
         err:填寫錯誤的時候觸發的樣式
     -->
     <div v-for="num1,indexSub in row"
          :class="{'no':num1==='',
          'cur':curRow===index&&indexSub===curCol,
          'cur-col':hoverCol===indexSub,
          'err':(optionNow.x===index&&optionNow.y===indexSub)||(optionNowInRow.x===index&&optionNowInRow.y===indexSub)||(optionNowInCol.x===index&&optionNowInCol.y===indexSub)}"
          @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
         {{allNumText[index][indexSub]}}
    
     </div>
    </div>

    js代碼

    inputText(_text){
     //*****************************檢查前的初始化
     let _row = this.curRow, _col = this.curCol;
     this.curRow = '';
     this.curCol = '';
     this.isErr = false;
     this.optionNow = {
         x: '',
         y: '',
     }
     this.optionNowInRow = {
         x: '',
         y: '',
     }
     this.optionNowInCol = {
         x: '',
         y: '',
     }
     //*****************************檢查行
     //根據當前格子進行賦值
     this.allNumText[_row][_col] = _text;
     let rowCheck = Object.assign(this.allNumText[_row], []);
     this.checkShow = false;
     for (let i = 0, len = rowCheck.length; i < len; i++) {
         //如果值一樣,但是坐標不一樣,就是填寫錯誤
         if (_text === rowCheck[i] && _col !== i) {
             this.isErr = true;
             this.isShake = true;
             //記錄當前格子的信息
             this.optionNow = {
                 x: _row,
                 y: _col,
             }
             //記錄和當前格子同一行,以及同一個值的格子的坐標
             this.optionNowInRow = {
                 x: _row,
                 y: i,
             }
         }
     }
     //*****************************檢查列
     let colCheck = [];
     //首先把每一行的那一列的數值保存起來
     for (let i = 0, len = this.allNumText.length; i < len; i++) {
         colCheck.push(this.allNumText[i][_col]);
     }
     //遍歷檢查
     for (let i = 0, len = colCheck.length; i < len; i++) {
         //如果值一樣,但是坐標不一樣,就是填寫錯誤
         if (_text === colCheck[i] && _row !== i) {
             this.isErr = true;
             this.isShake = true;
             //記錄和當前格子同一列,以及同一個值的格子的坐標
             this.optionNowInCol = {
                 x: i,
                 y: _col,
             }
         }
     }
     //如果發現的同樣的
     if (this.isErr) {
         setTimeout(() => {
             this.isShake = false;
         }, 1000)
         return;
     }
     //如果數組去重后,長度小于9,就是行沒完成
     rowCheck = rowCheck.filter(item => item !== '');
     if (rowCheck.length !== 9) {
         //console.log('行沒完成')
         return;
     }
    
     let coloCheck = [];
     //如果數組去重后,長度小于9,就是列沒完成
     for (let i = 0, len = this.allNumText.length; i < len; i++) {
         coloCheck = [...new Set(this.allNumText[i])];
         coloCheck = coloCheck.filter(item => item !== '');
         if (coloCheck.length !== 9) {
             //console.log('沒完成')
             return;
         }
     }
     alert('挑戰成功,但是沒獎品');
     this.numShow = false;
    }

    上面的代碼邏輯,簡單說下

    1. .err 這個class是設置紅色字體所使用的,至于判斷,就是在 inputText 這個函數里面,有 optionNow 和 optionNowInRow 和 optionNowInCol 。只要格子的坐標等于三者其中之一,就會添加這個class,就會變紅。

    2. .isShake 這個class是控制,抖動的動畫,添加上了之后,在一秒后,要去掉這個class,不然下次添加沒有動畫效果。

    3.在 inputText 這個函數里面,我操作的數獨列表,并不是之前,提到的 allNum ,而是利用 allNum ,深度拷貝生成出的 allNumText ( this.allNumText = JSON.parse(JSON.stringify(this.allNum)); )。主要就是為了避免下圖的情況!

    這樣是為了往掏空的格子輸入數字的時候,然后那個格子就不能再改了,即使是填錯了,都不能改。樣式控制也不正確!正確的格式應該是下面這樣,即使填入了,格子的樣式還是灰色的,這樣可以方便的知道哪個格子是當時被掏空的,填寫錯了,也是可以改的。

    4.完整代碼

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <meta charset="UTF-8">
     <title>vue-所謂的數獨</title>
     <link rel="stylesheet" href="../../reset.css">
     <style>
         li{
             list-style-type: none;
         }
         .shake {
             animation: shake-opacity 500ms 1 ease-in-out;
         }
         @keyframes shake-opacity {
             0% {
                 transform: translate(0px, 0px) rotate(0deg);
                 opacity: 0.6;
             }
             10% {
                 transform: translate(-2px, -1px) rotate(-0.5deg);
                 opacity: 0.5;
             }
             20% {
                 transform: translate(-4px, 4px) rotate(1.5deg);
                 opacity: 0.4;
             }
             30% {
                 transform: translate(-4px, -1px) rotate(-1.5deg);
                 opacity: 0.8;
             }
             40% {
                 transform: translate(-2px, -1px) rotate(-2.5deg);
                 opacity: 0.3;
             }
             50% {
                 transform: translate(-4px, 1px) rotate(-2.5deg);
                 opacity: 0.5;
             }
             60% {
                 transform: translate(-2px, 4px) rotate(0.5deg);
                 opacity: 0.1;
             }
             70% {
                 transform: translate(-3px, 1px) rotate(-0.5deg);
                 opacity: 0.4;
             }
             80% {
                 transform: translate(0px, 0px) rotate(-0.5deg);
                 opacity: 0.5;
             }
             90% {
                 transform: translate(2px, -1px) rotate(-2.5deg);
                 opacity: 0.8;
             }
         }
         .num-box {
             margin: 0 auto;
             width: 540px;
             position: relative;
         }
         .num-box .num-check {
             position: absolute;
             width: 180px;
             box-shadow: 0 0 10px 0 #000;
             left: 0;
             top: 0;
         }
         .num-box .num-check li {
             box-sizing: border-box;
             float: left;
             background: #fff;
             color: #58B7FF;
             width: 60px;
             height: 60px;
             text-align: center;
             line-height: 60px;
             font-size: 24px;
             border: 1px solid #58B7FF;
             cursor: pointer;
             transition: all .5s;
         }
         .num-box .num-check li:hover {
             color: #fff;
             background: #58B7FF;
             border: 1px solid #fff;
         }
         .num-tips{
             color: #333;
             line-height: 32px;
             font-size: 16px;
         }
         .num-table{
             position: relative;
         }
         .num-row {
             font-size: 0;
         }
         .num-row:hover .num-col, .num-row:hover .num-col.no, .num-row:hover .num-col.cur-col {
             background: #0068b7;
         }
         .num-row .num-col {
             width: 60px;
             height: 60px;
             line-height: 60px;
             float: left;
             box-sizing: border-box;
             text-align: center;
             background: #58B7FF;
             color: #fff;
             font-size: 24px;
             font-weight: bold;
             border: 1px solid #ccc;
         }
         .num-row .num-col.no {
             background: #ccc;
             border: 1px solid #fff;
         }
         .num-row .num-col.err {
             color: #ff4949;
         }
         .num-row .num-col.cur-col {
             background: #0068b7;
         }
         .num-row .num-col.cur {
             background: #fff !important;
         }
     </style>
    </head>
    <body>
    <div class="num-box" v-show="numShow" id="num">
     <div class="num-tips">
         <p>所謂的數獨:規則</p>
         <p>1.每一行數字不重復</p>
         <p>2.每一列數字不重復</p>
     </div>
     <div class="num-table" @mouseleave="hoverCol=''" :class="{'shake':isShake}">
         <!--遍歷每一行-->
         <div v-for="row,index in allNum" class="num-row clear">
             <!--遍歷行里面的每一列-->
             <!--
                 no:被掏空數組的樣式
                 cur:格子被點擊時觸發,被點擊的格子樣式
                 cur-col:鼠標進入的時候觸發,和被點擊格子同一列的格子的樣式
                 err:填寫錯誤的時候觸發的樣式
             -->
             <div v-for="num1,indexSub in row"
                  :class="{'no':num1==='',
                  'cur':curRow===index&&indexSub===curCol,
                  'cur-col':hoverCol===indexSub,
                  'err':(optionNow.x===index&&optionNow.y===indexSub)||(optionNowInRow.x===index&&optionNowInRow.y===indexSub)||(optionNowInCol.x===index&&optionNowInCol.y===indexSub)}"
                  @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
                 {{allNumText[index][indexSub]}}
    
             </div>
         </div>
         <!--數字鍵盤-->
         <div class="num-check clear" :style="{'top':(curRow+1)*60+'px','left':(curCol+1)*60+'px'}"
              v-show="checkShow">
             <ul>
                 <li @click="inputText(1)">1</li>
                 <li @click="inputText(2)">2</li>
                 <li @click="inputText(3)">3</li>
                 <li @click="inputText(4)">4</li>
                 <li @click="inputText(5)">5</li>
                 <li @click="inputText(6)">6</li>
                 <li @click="inputText(7)">7</li>
                 <li @click="inputText(8)">8</li>
                 <li @click="inputText(9)">9</li>
             </ul>
         </div>
     </div>
    </div>
    </body>
    <script src="../vue.min.js"></script>
    <script>
     new Vue({
         el:'#num',
         data:{
                 name: 'welcome',
                 testText: '歡迎來到',
                 nowIndex: 0,
                 allNum: [],//數字排列
                 answer: [],//所有答案的坐標點
                 allNumText: [],//數字,包括輸入后的數字
                 curRow: '',//當前格子所在的行的索引
                 curCol: '',//當前格子所在的列的索引
                 checkShow: false,//數字鍵盤的顯示
                 hoverCol: '',//鼠標進去的當前列
                 hoverRow: 0,//鼠標進入的當前行
                 numShow: true,//數獨的顯示
                 optionNow: {},//輸入后的格子的坐標
                 optionNowInRow: {},//和輸入后的格子在同一行,并且同樣值的格子的坐標
                 optionNowInCol: {},//和輸入后的格子在同一列,并且同樣值的格子的坐標
                 isErr: false,//是否輸入錯誤后
                 isShake: false//是否顯示震動的樣式
         },
         methods: {
             /**
              * @description 顯示數字鍵盤
              * @param i1
              * @param i2
              */
             showCheck(i1, i2){
                 //點擊的格子是否是被掏空的格子
                 if (this.allNum[i1][i2] !== '') {
                     return
                 }
                 //點擊的格子如果是上一次點擊的格子(當前格子)
                 if (i1 === this.curRow && i2 === this.curCol) {
                     //隱藏數字鍵盤,curRow和curCol設空
                     this.checkShow = false;
                     this.curRow = '';
                     this.curCol = '';
                 }
                 else {
                     //隱藏數字鍵盤,curRow和curCol分別設置成當前的點
                     this.checkShow = true;
                     this.curRow = i1;
                     this.curCol = i2;
                 }
             },
             inputText(_text){
                 //*****************************檢查前的初始化
                 let _row = this.curRow, _col = this.curCol;
                 this.curRow = '';
                 this.curCol = '';
                 this.isErr = false;
                 this.optionNow = {
                     x: '',
                     y: '',
                 }
                 this.optionNowInRow = {
                     x: '',
                     y: '',
                 }
                 this.optionNowInCol = {
                     x: '',
                     y: '',
                 }
                 //*****************************檢查行
                 //保存當前格子的值
                 this.allNumText[_row][_col] = _text;
                 let rowCheck = Object.assign(this.allNumText[_row], []);
                 this.checkShow = false;
                 for (let i = 0, len = rowCheck.length; i < len; i++) {
                     //如果值一樣,但是坐標不一樣,就是填寫錯誤
                     if (_text === rowCheck[i] && _col !== i) {
                         this.isErr = true;
                         this.isShake = true;
                         //記錄當前格子的信息
                         this.optionNow = {
                             x: _row,
                             y: _col
                         }
                         //記錄和當前格子同一行,以及同一個值的格子的坐標
                         this.optionNowInRow = {
                             x: _row,
                             y: i
                         }
                     }
                 }
                 //*****************************檢查列
                 let colCheck = [];
                 //首先把每一行的那一列的數值保存起來
                 for (let i = 0, len = this.allNumText.length; i < len; i++) {
                     colCheck.push(this.allNumText[i][_col]);
                 }
                 //遍歷檢查
                 for (let i = 0, len = colCheck.length; i < len; i++) {
                     //如果值一樣,但是坐標不一樣,就是填寫錯誤
                     if (_text === colCheck[i] && _row !== i) {
                         this.isErr = true;
                         this.isShake = true;
                         //記錄和當前格子同一列,以及同一個值的格子的坐標
                         this.optionNowInCol = {
                             x: i,
                             y: _col
                         }
                     }
                 }
                 //如果發現的同樣的
                 if (this.isErr) {
                     setTimeout(() => {
                         this.isShake = false;
                     }, 1000)
                     return;
                 }
                 //如果數組去重后,長度小于9,就是行沒完成
                 rowCheck = rowCheck.filter(item => item !== '');
                 if (rowCheck.length !== 9) {
                     console.log('行沒完成')
                     return;
                 }
    
                 let coloCheck = [];
                 //如果數組去重后,長度小于9,就是列沒完成
                 for (let i = 0, len = this.allNumText.length; i < len; i++) {
                     coloCheck = [...new Set(this.allNumText[i])];
                     coloCheck = coloCheck.filter(item => item !== '');
                     if (coloCheck.length !== 9) {
                         console.log('沒完成')
                         return;
                     }
                 }
                 alert('挑戰成功,但是沒獎品');
                 this.numShow = false;
             }
         },
         mounted(){
             let arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
             let row = [], rowCol = 0;
             for (let i = 0, len = arr1.length; i < len; i++) {
                 row = Object.assign([], arr1);
                 this.allNum.push(row);
                 rowCol = arr1.splice(0, 1)[0];
                 arr1.push(rowCol)
             }
             //打亂行
             this.allNum.sort((n1, n2) => Math.random() - 0.5);
             //隨機獲取兩列的索引
             function randomText() {
                 let rondomIndex = 0, rondomIndexAfter = 0;
                 //獲取第一列的索引
                 rondomIndex = Math.floor(Math.random() * 9);
                 function randomDo() {
                     rondomIndexAfter = Math.floor(Math.random() * 9);
                     //如果第一列和第二列索引一樣,第二列的索引再次重新獲取
                     if (rondomIndexAfter === rondomIndex) {
                         randomDo();
                     }
                 }
    
                 randomDo();
                 //返回兩列的索引
                 return [rondomIndex, rondomIndexAfter]
             }
    
             //打亂列
             let randomArr = [], nowValue = 0;
             //同樣遍歷9次
             for (let i = 0; i < 9; i++) {
                 randomArr = Object.assign([], randomText());
                 //遍歷每一行,給每一行的隨機兩列交換值
                 for (let j = 0, len = this.allNum.length; j < len; j++) {
                     //隨機兩列交換值
                     nowValue = this.allNum[j][randomArr[0]];
                     this.allNum[j][randomArr[0]] = this.allNum[j][randomArr[1]];
                     this.allNum[j][randomArr[1]] = nowValue;
                 }
             }
    
             //記錄所有坐標
             let rowText = '', arrText = []
             for (let i = 0; i < 9; i++) {
                 rowText = ''
                 for (let j = 0; j < 9; j++) {
                     rowText += i + '-' + j + ',';
                 }
                 arrText.push(rowText.substr(0, rowText.length - 1))
             }
             console.log(arrText);
             //隨機掏空
             let nowItme = [], _option, nowOption = [];
             for (let i = 0; i < 9; i++) {
                 //抽取當前行的所有坐標
                 nowItme = arrText[i].split(',');
                 nowOption = [];
                 //當前行的隨機兩個坐標掏空
                 for (let j = 0; j < 2; j++) {
                     //抽取當前行的隨機一個坐標
                     _option = Math.floor(Math.random() * nowItme.length);
                     //分割坐標的x,y
                     nowOption = nowItme.splice(_option,1)[0].split("-");
                     this.allNum[nowOption[0]][nowOption[1]] = '';
                 }
    
             }
             //深度拷貝數獨的數字
             this.allNumText = JSON.parse(JSON.stringify(this.allNum));
         }
     })
    </script>
    </html>

     

    5.小結

    好了,用vue做的所謂的數獨,就寫到這里了,主要就是邏輯有點繞,其它的問題相信都難不倒大家。這個實例比之前快速入門的三個小實例要麻煩一點,但是也很好理解!大家只要稍微看下估計都不難理解!最后,如果大家覺得文章寫得不好,哪里寫錯了,歡迎給建議或者指點下迷津。期待和大家交流意見,共同進步!

     

    來自:https://segmentfault.com/a/1190000012517876

     

 本文由用戶 HesterMarin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!