用vue开发一个所谓的数独

HesterMarin 6年前
   <h2>1.前言</h2>    <p>最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了!这个实例也是基于vue的,代码分享给大家。给大家代码,并不是要让大家直接拷贝代码,而是希望能让大家当做是一个练手的项目,或者学习到知识。如果大家觉得我哪里写得不好,写错了,欢迎指出,让大家交流意见,一起进步。</p>    <h2>2.运行效果</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/59899c6c992bda689a9a7d7bf7914194.gif"></p>    <h2>3.实现步骤</h2>    <p>实现步骤,感觉说得有点绕,建议大家边写边看文章,这样不会懵。或者直接去看源码( <a href="/misc/goto?guid=4959755957392597981" rel="nofollow,noindex">sudoku</a> ),把源码看懂!这个项目也不复杂!</p>    <h3>3-1.准备数据和排版</h3>    <p>排版的 html+css 代码我不多说了,排版很简单,这个相信都难不倒大家的。复杂一点的就是数据的交互!</p>    <p>下面开始第一步,把数独的数据先准备好,数据是什么,大家都知道,就是像下面这样的数据!</p>    <p><img src="https://simg.open-open.com/show/4a6651a31d8b84e322d53bcf2f174274.png"></p>    <p>排版出来的效果就是下面这样。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/50cb18bfcd189c4bdb9b1253623d96d4.png"></p>    <p>html 代码如下</p>    <pre>  <code class="language-javascript"><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></code></pre>    <p>代码也很简单,如下</p>    <pre>  <code class="language-javascript">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)      }  }</code></pre>    <p>大家也可以发现,这个数据,的每一行和每一列的数字都是不同样的!</p>    <h3>3-2.打乱行</h3>    <p>之后就是随机打乱顺序了,打乱顺序这个得保证一个前提,就是保证每一行每一列的数字都不一样。这样的话,我用了一个简单粗暴的方法-以行或者列为单位,进行打乱。比如,第一行和第三行进行位置交互,第一列和第五列进行位置的交换。下面说下以行为单位的打乱顺序!</p>    <p>行的打乱,很简单,就是随机打乱数组而已!一行代码搞定!</p>    <pre>  <code class="language-javascript">this.allNum.sort((n1, n2) => Math.random() - 0.5);</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/346a18f735a91254c0c868a0fc05e325.png"></p>    <h3>3-3.打乱列</h3>    <p>行打乱了,下面进行以列为单位的打乱,这个稍微复杂一点。</p>    <p>大家想下,比如第二列是第五列的值进行交换,那就是每一行的第二个格子的值和第五个格子的值进行交换,那么就需要遍历每一行!来进行交换,至于前面说的第二列和第五列的这个列数,可以用一个函数实现!</p>    <p>下面看代码!</p>    <pre>  <code class="language-javascript">//随机获取两列的索引  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>    <p style="text-align:center"><img src="https://simg.open-open.com/show/60e3607ebdd6ab51617e718f0afcb080.png"></p>    <h3>3-3.随机掏空单元格</h3>    <p>掏空单元格就是把一些格子随机设空,然后让玩数独的人。把这些单元格给填上!</p>    <p>需求,我现在实现的就是,每一行有把两个格子设空,这里我的做法是,把每一个格子的坐标先记录下来,然后再从记录的坐标里面随机获取坐标,用获取到的坐标,进行设空!</p>    <p>首先,获取所有点的坐标</p>    <pre>  <code class="language-javascript">//记录所有坐标  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);</code></pre>    <p><img src="https://simg.open-open.com/show/908c990e15efc5fcf49b14d39bac5122.png"></p>    <p>看到这个坐标,大家很容易的知道,数组的一个元素,就是第一行,‘ 0-0 ’就是第一行第一个格子。数组最后一个元素,就是最后一行,‘ 8-8 ’就是最后一行,最后一个格子,其他如此类推!</p>    <p>下面进行随机掏空,代码也很简单!</p>    <pre>  <code class="language-javascript">//随机掏空  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>    <p style="text-align:center"><img src="https://simg.open-open.com/show/cbe70aad4e9ef00b0be4c465efb05705.png"></p>    <p>这样相信大家都觉得奇怪,下面进行下样式的该写,就是把设空了的格子的样式改一下! .no 这个 class 对应的样式我在 css 那里写好了,大家注意下。</p>    <pre>  <code class="language-javascript"><!--遍历每一行-->  <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></code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/240e45a5cf916deaed5910f08c9bea52.png"></p>    <h3>3-4.显示数字键盘</h3>    <p>首先,我简单的用一个流程图说下逻辑,如下</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/39065ad76963c16d2ac8070ec2c940c7.png"></p>    <p>然后关于数字键盘的位置,看下图(数字键盘的样式我不多说了,就是一个是相对定位,一个绝对定位的设置而已)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3a701e4d6c82bdfe1387caea05640d39.png"></p>    <p>如上图,我点击的是第一行第三个格子,首先,我期待被点击的格子的样式有所改变,方便我区分,这个不难,用一个 class 改变样式就可以了,这个可以看下面的代码,我用一个 .cur 的 class 控制样式。还有一个就是期待数字键盘在第二行,第四个格子那里出现。这样的话,大家就知道,数字键盘的位置是怎么定位的了!数字键盘的 top 就是,被点击格子所在的行的索引+1 <em> 60(60是格子的宽高), left 就是,被点击格子所在的列的索引+1 </em> 60(60是格子的宽高)。比如上图,第一行第三个格子, top=(0+1)*60+'px',left=(2+1)*60+'px' 。</p>    <p>代码如下</p>    <pre>  <code class="language-javascript"><!--遍历每一行-->      <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>    <p>js代码</p>    <pre>  <code class="language-javascript">/**   * @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>    <p>运行效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/db298e5d9193eb4479680235fde47cd0.png"></p>    <h3>3-5.高亮显示同行同列</h3>    <p>这一步很简单,首先,高亮显示行,大家都知道怎么做了,就是行对应的 div ,设置一个 :hover ,然后对应设置单元格的样式而已!这个不多说!</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1dfec94f295c3c6f21def32b6cd8e546.png"></p>    <p>然后,高亮显示列,复杂一点,但是也很简单,原理我想大家也知道,就是当鼠标进如格子的时候,在 data 里面,用一个变量储存进入的格子的列的索引,然后加上判断,如果格子的列的索引等于进入的格子的列的索引。就加上一个 class ,这里我用 .cur-col 。代码如下</p>    <pre>  <code class="language-javascript"><!--遍历每一行-->  <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></code></pre>    <p>运行效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/13975930a2fcc254f480f57893aa241a.png"></p>    <h3>3-6.填写操作和错误提示</h3>    <p>这一步的操作函数,我直接发代码吧,看代码比我说的会清晰些,毕竟说的有点绕</p>    <pre>  <code class="language-javascript"><!--遍历每一行-->  <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></code></pre>    <p>js代码</p>    <pre>  <code class="language-javascript">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;  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9443cce31566fdeec62cf72fb18a3485.gif"></p>    <p>上面的代码逻辑,简单说下</p>    <p>1. .err 这个class是设置红色字体所使用的,至于判断,就是在 inputText 这个函数里面,有 optionNow 和 optionNowInRow 和 optionNowInCol 。只要格子的坐标等于三者其中之一,就会添加这个class,就会变红。</p>    <p>2. .isShake 这个class是控制,抖动的动画,添加上了之后,在一秒后,要去掉这个class,不然下次添加没有动画效果。</p>    <p>3.在 inputText 这个函数里面,我操作的数独列表,并不是之前,提到的 allNum ,而是利用 allNum ,深度拷贝生成出的 allNumText ( this.allNumText = JSON.parse(JSON.stringify(this.allNum)); )。主要就是为了避免下图的情况!</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e7a84a3957ff80af41986457694355d8.gif"></p>    <p>这样是为了往掏空的格子输入数字的时候,然后那个格子就不能再改了,即使是填错了,都不能改。样式控制也不正确!正确的格式应该是下面这样,即使填入了,格子的样式还是灰色的,这样可以方便的知道哪个格子是当时被掏空的,填写错了,也是可以改的。</p>    <h2>4.完整代码</h2>    <pre>  <code class="language-javascript"><!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></code></pre>    <p> </p>    <h2>5.小结</h2>    <p>好了,用vue做的所谓的数独,就写到这里了,主要就是逻辑有点绕,其它的问题相信都难不倒大家。这个实例比之前快速入门的三个小实例要麻烦一点,但是也很好理解!大家只要稍微看下估计都不难理解!最后,如果大家觉得文章写得不好,哪里写错了,欢迎给建议或者指点下迷津。期待和大家交流意见,共同进步!</p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000012517876</p>    <p> </p>