本帖最后由 黑黑黑黑黑黑 于 2017-12-21 15:07 编辑
用vue开发一个所谓的数独1.前言最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了!这个实例也是基于vue的,代码分享给大家。给大家代码,并不是要让大家直接拷贝代码,而是希望能让大家当做是一个练手的项目,或者学习到知识。如果大家觉得我哪里写得不好,写错了,欢迎指出,让大家交流意见,一起进步。代码上传到github了:有需要的可以star一下!vue-demos 2.运行效果3.实现步骤实现步骤,感觉说得有点绕,建议大家边写边看文章,这样不会懵。或者直接去看源码(sudoku),把源码看懂!这个项目也不复杂! 3-1.准备数据和排版排版的html+css代码我不多说了,排版很简单,这个相信都难不倒大家的。复杂一点的就是数据的交互!
下面开始第一步,把数独的数据先准备好,数据是什么,大家都知道,就是像下面这样的数据! 排版出来的效果就是下面这样。 html代码如下 [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> 代码也很简单,如下 [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)
}
} 大家也可以发现,这个数据,的每一行和每一列的数字都是不同样的! 3-2.打乱行之后就是随机打乱顺序了,打乱顺序这个得保证一个前提,就是保证每一行每一列的数字都不一样。这样的话,我用了一个简单粗暴的方法-以行或者列为单位,进行打乱。比如,第一行和第三行进行位置交互,第一列和第五列进行位置的交换。下面说下以行为单位的打乱顺序!
行的打乱,很简单,就是随机打乱数组而已!一行代码搞定! [JavaScript] 纯文本查看 复制代码 this.allNum.sort((n1, n2) => Math.random() - 0.5); 3-3.打乱列行打乱了,下面进行以列为单位的打乱,这个稍微复杂一点。
大家想下,比如第二列是第五列的值进行交换,那就是每一行的第二个格子的值和第五个格子的值进行交换,那么就需要遍历每一行!来进行交换,至于前面说的第二列和第五列的这个列数,可以用一个函数实现!
下面看代码! [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;
}
} 3-3.随机掏空单元格掏空单元格就是把一些格子随机设空,然后让玩数独的人。把这些单元格给填上!
需求,我现在实现的就是,每一行有把两个格子设空,这里我的做法是,把每一个格子的坐标先记录下来,然后再从记录的坐标里面随机获取坐标,用获取到的坐标,进行设空!
首先,获取所有点的坐标 [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); 看到这个坐标,大家很容易的知道,数组的一个元素,就是第一行,‘0-0’就是第一行第一个格子。数组最后一个元素,就是最后一行,‘8-8’就是最后一行,最后一个格子,其他如此类推!
下面进行随机掏空,代码也很简单! [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]] = '';
}
}
这样相信大家都觉得奇怪,下面进行下样式的该写,就是把设空了的格子的样式改一下!.no这个class对应的样式我在css那里写好了,大家注意下。 [HTML] 纯文本查看 复制代码 <!--遍历每一行-->
<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'。
代码如下 [HTML] 纯文本查看 复制代码 <!--遍历每一行-->
<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> js代码 [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;
}
}, 运行效果 3-5.高亮显示同行同列这一步很简单,首先,高亮显示行,大家都知道怎么做了,就是行对应的div,设置一个:hover,然后对应设置单元格的样式而已!这个不多说! 然后,高亮显示列,复杂一点,但是也很简单,原理我想大家也知道,就是当鼠标进如格子的时候,在data里面,用一个变量储存进入的格子的列的索引,然后加上判断,如果格子的列的索引等于进入的格子的列的索引。就加上一个class,这里我用.cur-col。代码如下 [HTML] 纯文本查看 复制代码 <!--遍历每一行-->
<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.填写操作和错误提示这一步的操作函数,我直接发代码吧,看代码比我说的会清晰些,毕竟说的有点绕 reset.css和vue.min.js大家自行到github下载! 5.小结好了,用vue做的所谓的数独,就写到这里了,主要就是逻辑有点绕,其它的问题相信都难不倒大家。这个实例比之前快速入门的三个小实例要麻烦一点,但是也很好理解!大家只要稍微看下估计都不难理解!最后,如果大家觉得文章写得不好,哪里写错了,欢迎给建议或者指点下迷津。期待和大家交流意见,共同进步!
|