学习记录,利用canvas写扫雷游戏

2023-11-01

记录js学习后制作的第一关小游戏。

这里的代码还不够精简,许多地方偷懒没有封装,逻辑也有许多可以优化。

<body>

    胜利条件,找出所有地雷并标记
    <form action="javaScript:createContent()">
        <div id="message" style="color: red; display: none;">地雷数量必须小于地图大小xy的平方</div>
        <br /> 
        地图大小xy :<input id="xyNum" type="number" required="true" name="points" min="1" max="50"  /> 
        booNum:<input id="booNum" type="number" required="true" name="points" min="1" max="2500"/>
        <input type="submit" value="OK" : />
        <br /> 1. 输入宽度 <br />2. 输入地雷数(地雷数小于宽*宽) <br /> 3. 单击确定  <br />
        鼠标右键:<br />
        第一次:标记您的猜测<br />
        第二次: 取消标签<br />
    </form>
    <div id= 'game'>

    </div>
    <script src="./js/MarkObs.js"></script>
    <script src="./js/Isboo.js"></script>
    <script src="./js/lei.js"></script>
    <script>
    let xy = document.getElementById('xyNum');
    let boo = document.getElementById('booNum');
    let meg = document.getElementById("message");
    let div = document.getElementById('game');

    //获取输入的宽高和地雷数
    createContent = function (){
            // console.log(xy.value);
            // console.log(boo.value);
            let xyNum = xy.value; 
            let booNum = boo.value; 
            // console.log(Math.pow(xyNum,2));
            
            //判断输入是否合法
            if(Math.pow(xyNum,2)<boo.value){
                meg.style.display = 'block';
            }
            else {//绘制地图
                div.innerHTML = '';//清除上次div里的地图
                let game = new Game('game',xyNum,booNum);
            }
        }
    </script>
</body>

 lei.js

/* 一个自定义原型数组方法  可以放到html里
二维数组查找
arr:要找数组第一第二项 找到返回下标,没有返回-1
PS:只要this数组和arr数组第一第二项的值相等,即为找到。
*/
Array.prototype.myindexOf = function(arr){
    for(let i=0;i<this.length;i++){
        
        if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){
            return i;
        }
    }
    return -1;
}
/*
初始化地雷图
id:传入绘制地图的容器id
xyNum:长||宽的格子数(地图固定正方形)
booNum:地雷数
*/ 
class Game {
    constructor(id,xyNum,booNum){
        this.xyNum = xyNum;
        this.booNum = booNum;
        this.id = id;

        this.booArrs = [];//保存雷的位置
        this.boox = -1;//地雷在x轴第几个块
        this.booy = -1;//地雷在x轴第几个块

        this.numArrs = [];//保存提醒数字的位置以及数字
        this.num = 0;//保存找到的提醒数字的个数

        this.markArrs = [];//保存标记位置的数组

        //单个块的宽高
        this.divw = 20;

        // 初始化画布
        this.initCanvas(xyNum);
        // 初始化地雷位置(地雷用-1代替,图片绘制麻烦)
        this.initBooxy(xyNum,booNum);
        // 初始化遮挡物
        this.initObs(xyNum);

        //判断是否胜利
        this.win();
    

    }
    /*初始化画布(包括网格)
    xyNum:传入需要绘制的宽格子数
    */ 
    initCanvas(xyNum){
        this.canvas = document.createElement('canvas');
        this.ctx = this.canvas.getContext('2d');
        
        //1为border
        this.canvas.width = (this.divw+1)*xyNum;
        this.canvas.height = (this.divw+1)*xyNum;

        // 绘制网格坐标
                // 获取canvas的宽高;
                let w = this.canvas.width;
                let h = this.canvas.height;
                // 绘制水平线
                for (let i = 1; i < h / 21; i++) {
                    this.ctx.beginPath();
                    this.ctx.lineTo(0,  21 * i) //起点
                    this.ctx.lineTo(w, 21 * i); //重点
                    this.ctx.stroke();
        
                }
                // h绘制垂直线
                for (let i = 1; i < w / 21; i++) {
                    this.ctx.beginPath();
                    this.ctx.lineTo(21 * i,0) //起点
                    this.ctx.lineTo(21 * i,h); //重点
                    this.ctx.stroke();
        
                }
                // ctx.stroke();

        // 放入容器
        this.div = document.getElementById(this.id);
        this.div.appendChild(this.canvas);
        
        // 绑定点击事件!!!
        this.canvas.addEventListener('mousedown',this.mouseDown.bind(this))//!!!!注意需要更改this指向,用bind
        
        // 清除鼠标右键的默认事件 “contextmenu“
        this.canvas.addEventListener("contextmenu",function(event){
            event.preventDefault()
        })
    }

    /*初始化地雷(包括提醒数字)
    xyNum:传入地图的宽的格子数
    booNum:传入地雷数
    */ 
    initBooxy (xyNum,booNum){

        // 随机地雷位置 并保存起来
        for(let i=0;i<booNum;i++){

            // x,y为地雷所在格子坐标,从0开始
            this.boox = parseInt(Math.random()*xyNum);
            this.booy = parseInt(Math.random()*xyNum);

            //避免雷的位置重复
            while(this.booArrs.myindexOf([this.boox,this.booy])!=-1){
                this.boox = parseInt(Math.random()*xyNum);
                this.booy = parseInt(Math.random()*xyNum);
            }

            this.booArrs.push([this.boox,this.booy])//!!!保存地雷的位置
            console.log(i,'x:'+this.boox,'y:'+this.booy);

            //绘制地雷
            this.ctx.beginPath();//不清楚可不可以删
            this.ctx.rect(this.boox*21,this.booy*21,20,20);
            this.ctx.fillStyle = 'red';
            this.ctx.fill();
        }

        // 绘制地雷位置周围提醒数字
            // 这里的逻辑可以优化,不提前绘制数字,在点击清除障碍物后再判断绘制。  

        /*
            想法一:在每个雷周围添加数字1,如果在多个雷交集处累加
            想法二:所有块依次判断周围是否有雷,有几个雷,就fillText()多少
            想法三:(一二结合)先找每个雷,该雷周围的8个块依次 判断周围有几个雷
        */ 
            // 这里为法二
       for(let i=0;i<xyNum;i++){
           for(let j=0;j<xyNum;j++){
               let num = 0;//提醒数字 ,每次重置为0
            
                if(this.booArrs.myindexOf([i-1,j-1]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i-1,j]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i-1,j+1]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i,j-1]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i,j+1]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i+1,j-1]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i+1,j]) !=-1){
                    num++;
                }
                if(this.booArrs.myindexOf([i+1,j+1]) !=-1){
                    num++;
                }
               
                //绘制提醒数字  
                if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若。要标注需要+1(本身)

                this.ctx.font = '18px fasdg'
                this.ctx.fillStyle = '#000'
                this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标
                
                this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)
                }
                // this.NUM = num;
           }
       }
        

        
    }

    /*初始化遮挡物
     xyNum:传入地图的宽的格子数
    */ 
   initObs(xyNum){
    for(let i=0;i<xyNum;i++){
        for(let j=0;j<xyNum;j++){

            this.ctx.beginPath();
            this.ctx.rect(i*21,j*21,20,20);
            // this.ctx.fillStyle = 'rgb(155,25,205,0.7)';//设置障碍物透明度可以方便查看雷的位置
            this.ctx.fillStyle = 'rgb(155,25,205,1)';//正常游戏时透明度为’1‘
            this.ctx.fill();
        }
    }
   }


/*点击事件在initCanvas中绑定*/  
   mouseDown(){
 
    //这里使用preventDefault,默认事件被没有消除,是因为触发鼠标右键的默认事件的事件类型不是mousedown,是contextmenu
    // event.preventDefault(); //ie9以下不兼容 
    
    this.clix = Math.floor(event.layerX/( this.divw+1));//this.divw为20是块的宽
    this.cliy = Math.floor(event.layerY/( this.divw+1)); 


    

    // 鼠标左键
    if(event.button==0){
        this.clearObs(this.clix,this.cliy);


    }
    
    // 鼠标右键
    else if(event.button==2){
        
        
        this.markObs(this.clix,this.cliy);
    }
   
   }


   /*扫雷*/  //这里的代码可以封装一下 为了方便此处没有封装
   clearObs(x,y){
    // console.log(x,y);点击坐标

    this.ctx.clearRect(x*21,y*21,20,20);//清除指定块
    
    // 点击到标记,点击到提醒数字,点击到地雷,点击到空白,
    if(this.markArrs.myindexOf([x,y])!=-1){  //点击到标记,重新覆盖
        this.ctx.rect(x*21,y*21,20,20);
        this.ctx.fillStyle = 'rgb(155,25,205,1)';
        this.ctx.fill();
        
        this.ctx.beginPath();
        this.ctx.fillStyle = 'red';
        this.ctx.fillText('?',x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);
        this.ctx.fill();

    }
    else if(this.numArrs.myindexOf([x,y])!=-1){//点击到提醒数字
        let index = this.numArrs.myindexOf([x,y]);//下标
        let num = this.numArrs[index][2];//提醒数字
        this.ctx.fillText(num,x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标
        this.num++;
    }
    else if(this.booArrs.myindexOf([x,y])!=-1){//,点击到地雷,全部绘制
        console.log(this.booArrs.myindexOf([x,y]));
            //绘制全图
            // 绘制提醒数字
            for(let i=0;i<this.xyNum;i++){
                for(let j=0;j<this.xyNum;j++){
                    let num = 0;//提醒数字 ,每次重置为0
                     // if(booArrs.indexof([i-1,j-1]) != -1){//数组是对象这样永远-1
                     this.ctx.clearRect(i*21,j*21,20,20);
                     if(this.booArrs.myindexOf([i-1,j-1]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i-1,j]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i-1,j+1]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i,j-1]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i,j+1]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i+1,j-1]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i+1,j]) !=-1){
                         num++;
                     }
                     if(this.booArrs.myindexOf([i+1,j+1]) !=-1){
                         num++;
                     }
                     
     
                    
                     //绘制提醒数字
                     if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若要标注需要+1(本身)
     
                     this.ctx.font = '18px fasdg'
                     this.ctx.fillStyle = '#000'
                     this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标
                     
                     this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)
                     }
                     // this.NUM = num;
                }
            }
            // 绘制地雷
            for(let i=0;i<this.booArrs.length;i++){
                this.ctx.fillStyle = 'red';
                this.ctx.rect(this.booArrs[i][0]*21,this.booArrs[i][1]*21,20,20);
                this.ctx.fill(); 
            }
            this.ctx.clearRect((this.xyNum-1)*21,(this.xyNum-1)*21,20,20);//每次最后一个都会变红,不知道原因,此处专门删除。
           
            alert('你惊动了雷雷');

            
    }

    else {

        this.isboo(this.ctx,x,y,this.booArrs,this.numArrs,this.markArrs,this.xyNum);


    } 
   }

   win (){//标记数组==地雷数组
    this.tim = setInterval(()=>{
        if(this.booArrs.length ==this.markArrs.length){
            for(let i=0;i<this.booNum;i++){
                
                if( true == this.booArrs.some(()=>{
                    return this.markArrs.myindexOf(this.booArrs[i])!=-1;
                })){
                   this.booNum--;
                }
                if(this.booNum==0){
                    clearInterval(this.tim);
                    alert('you are win');
                    }
            }
        }
    },10)

   }
   isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
       new Isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
   }


    /*标记 
    */
   markObs(x,y){  
       console.log(x,y);
    new MarkObs(this.ctx,x,y,this.booArrs,this.divw,this.markArrs);
    

   }

   
}

isboo.js

Array.prototype.myindexOf = function(arr){
    for(let i=0;i<this.length;i++){
        
        if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){
            return i;
        }
    }
    return -1;
}
/*
这里解决点击到空白格子时,把周围的空白格一起显示。此处的逻辑可以再优化.
ctx:布局
x,点击位置
y,点击位置
booArrs:炸弹的位置数组
numArrs:提示数的位置
markArrs:标记的位置
*/ 
class Isboo {
    constructor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
        this.x = x;
        this.y = y;
        
        // 判断有没有提醒数字
        this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
    }
    isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
        if((numArrs.myindexOf([x,y])==-1)&&(x<xyNum)&&(markArrs.myindexOf([x,y])==-1)){
            ctx.clearRect(x*21,y*21,20,20);
            x+=1;
            this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        }else {
            return ;
        }
    }
    isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
        if((numArrs.myindexOf([x,y])==-1)&&(x>=0)&&(markArrs.myindexOf([x,y])==-1)){
            ctx.clearRect(x*21,y*21,20,20);
            x-=1;
            // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        }else {
            return ;
        }
    }
    isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
        if((numArrs.myindexOf([x,y])==-1)&&(y<xyNum)&&(markArrs.myindexOf([x,y])==-1)){
            ctx.clearRect(x*21,y*21,20,20);
            y+=1;
            // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            // this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);

        }else {
            return ;
        }
    }
    isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum){
        if((numArrs.myindexOf([x,y])==-1)&&(y>=0)&&(markArrs.myindexOf([x,y])==-1)){
            ctx.clearRect(x*21,y*21,20,20);
            y-=1;
            // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            // this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
            this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);
        }else {
            return ;
        }
    }

}

MarkObs.js

Array.prototype.myindexOf = function(arr){
    for(let i=0;i<this.length;i++){
        
        if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){
            return i;
        }
    }
    return -1;
}
/*
ctx:布局
x,点击位置
y,点击位置
booArrs:炸弹的位置数组
divw:各自宽度
markarrs:标记数组
*/ 
class MarkObs{
    constructor(ctx,x,y,booArrs,divw,markarrs){
        this.markObs(ctx,x,y,booArrs,divw,markarrs);
    }

    markObs(ctx,x,y,booArrs,divw,markarrs){

        if(markarrs.myindexOf([x,y])==-1){//如果标记数组里没有该地址,则标记,并添加进数组
        ctx.beginPath();
        ctx.fillStyle = 'red';
        ctx.fillText('?',x*(divw+1)+2,(y+1)*(divw+1)-2);
        markarrs.push([x,y]);
        }else {//如果标记数组里有该地址,则取消标记,并从数组中删除
            ctx.clearRect(x*(divw+1),y*(divw+1),divw,divw);
            ctx.beginPath();
            ctx.rect(x*21,y*21,20,20);
            ctx.fillStyle = 'rgb(155,25,205,1)';
            ctx.fill();
            markarrs.splice((markarrs.myindexOf([x,y])),1);
        }
    }

}

页面效果

初始化障碍物设置了透明度时

正常游戏时

这里点击右键标记后忘了把填充颜色设置回来。所以后面变红。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习记录,利用canvas写扫雷游戏 的相关文章

随机推荐

  • 微信小程序-解决scroll-view抖动

    微信小程序scroll view抖动 原因 产品需要点击换一换 列表置顶并刷新 所以需要动态绑定scroll view里面的scrollTop属性 scrollTop属性用法需要保存 scroll时的值 如果在 scroll时直接复制给sc
  • 01内存对齐之结构体偏移量

    01内存对齐之结构体偏移量 前提概念 结构体偏移量 所谓偏移量 就是我们每个结构体成员的首地址而已 1 求结构体成员偏移量的两中办法 1 简单求结构体成员偏移量 注意 求偏移量时 必须将地址转成int整数才能求偏移量 不能直接地址相减 否则
  • Easyexcel导出带下拉框选项excel模板(解决下拉框超50个的问题)

    1 为了避免excel下拉框选项过多会导致内容不显示 或者生成的时候报错 String literals in formulas can t be bigger than 255 characters ASCII easyexcel 将下拉
  • MobaXterm下载提示输入Master密码,如何使用ResetMasterPassword工具恢复MobaXterm和设置MobaXterm主密码

    MobaXterm忘记主密码 如何恢复和设置主密码 点此下载ResetMasterPassword MobaXterm 20 0汉化版下载 MobaXterm是一款非常好用的远程管理软件 支持SSH FTP 串口 VNC X server等
  • 基础算法题——异或和之和(位运算、组合数)

    异或和之和 题目链接 解题思路 解题方案 暴力枚举 时间复杂度 O n3 超时 位操作 组合数 解铃还须系铃人 对于这种与 或 异或的位操作 一般也是通过位操作来解答 总结规律 题目要求在 n 个正整数中枚举 3 个数进行位操作 若要确定
  • Spring Boot v2.4.4源码解析(十)依赖注入原理下 —— 依赖解析

    从 Spring Boot v2 4 4源码解析 八 依赖注入原理上 由一道面试题引起的思考 Autowired和 Resource的区别 可以看出 解析待注入字段或参数主要由 org springframework beans facto
  • windows与linux字符集转换

    linux下不能显示windows下的汉字 Windows和LINUX中缺省使用的字符集不同 Windows下工具可以识别LINUX中使用的UTF8字符集 而LINUX下一般工具不会自动转换Windows下的GBK字符集 如果确实需要显示
  • Mysql数据备份及数据恢复

    数据备份概述 根据数据备份的方式 分为逻辑备份和物理备份 物理备份 物理备份就是备份数据文件了 比较形象点就是cp下数据文件 但真正备份的时候自然不是的cp这么简单 逻辑备份 将数据导出至文本文件中 mysqldump是采用SQL级别的备份
  • IDEA配置Scala,使用IDEA创建第一个Scala项目

    1 首先安装IDEA IDEA的官网 https www jetbrains com idea download section mac 选择你对应的系统 版本选择社区版即可 如果有需要的可以选择Ultimate版 2 安装后 打开IDEA
  • java常用类及其方法使用StringBuffer

    基本介绍 1 StringBuffer类是对String类的增强 其代表了可变字符序列 可以对字符串的内容进行增删 2 很多方法和String是相同的 但是StringBuffer是可变长度的 3 StringBuffer是一个容器 4 类
  • stata做计量入门常用代码一览!

    现在越来越多人有写论文的需求啦 经管领域的论文中 实证研究已成为必备操作 有了下面的代码 直接上手跑数据 一 分组回归 实证中 常常要分行业分年度 分省份分年度等分组回归 保存出回归出来的某些参数 statsby就是一个有用的命令 命令语句
  • MySQL基础——多表查询练习题

    文章目录 1 查询员工的姓名 年龄 部门信息 隐式内连接 2 查询年龄小于30岁的员工的姓名 年龄 职位 部门信息 显示内连接 3 查询拥有员工的部门id 部门名称 4 查询所有年龄大于40岁的员工 及其归属的部门名称 如果没有分配部门 也
  • 人工智能ai算法_AI算法比您想象的要脆弱得多

    人工智能ai算法 In William Gibson s 2010 novel Zero History a character preparing to go in a high stakes raid wears an oddly pa
  • window像mac一样使用快捷键(AutoHotkey、SharpKeys和PowerToys)

    自己有win和mac两台笔记本 每天都需要在两台电脑切换进行开发 快捷键的差异就让人很难受 个人喜好mac快捷键 常用的几个快捷键分布比较合理 所以网上找来了解决方案供大家参考 我想作为一名 Mac User 使用 Win 首先感到不适应的
  • ####好好好#####时序数据库介绍和使用

    1 基础 1 1 时序数据的定义 什么是时间序列数据 Time Series Data TSD 以下简称时序 从定义上来说 就是一串按时间维度索引的数据 用描述性的语言来解释什么是时序数据 简单的说 就是这类数据描述了某个被测量的主体在一个
  • webpack3 CommonsChunkPlugin插件分离三方库(jQuery.js/vue.js等)和公共模块 分别打包

    需求 使用webpack进行打包时 我们不想自己写的js文件与第三方的js库一起打包成一个庞大的文件 而是想要第三方插件库单独打包一个js 我们自己写的js独立打包 优点 1 分割js文件避免单独一个js文件太大影响用户使用体验 2 通常来
  • fastdfs特点

    FastDFS是一个开源的轻量级分布式文件系统 它对文件进行管理 功能包括 文件存储 文件同步 文件访问 文件上传 文件下载 等 解决了大容量存储和负载均衡的问题 特别适合以文件为载体的在线服务 如相册网站 视频网站等等 FastDFS为互
  • 每个开发人员都应该知道的10个CSS选择器

    对于任何网站而言 要在用户上产生良好印象是什么 是的 它是任何网站的用户界面 每个开发人员都知道为用户创建美观的设计以便与任何网站进行交互非常重要 如果你不熟悉CSS及其选择器 那么在最短的时间内巧妙地对网页进行样式设置并不是一件容易的事
  • css中display属性作用大全

    定义和用法 display 属性规定元素应该生成的框的类型 实例 设置段落生成一个行内框 p inline display inline 使用说明 说明 这个属性用于定义建立布局时元素生成的显示框类型 对于 HTML 等文档类型 如果使用
  • 学习记录,利用canvas写扫雷游戏

    记录js学习后制作的第一关小游戏 这里的代码还不够精简 许多地方偷懒没有封装 逻辑也有许多可以优化 胜利条件 找出所有地雷并标记