0

0

使用javascript中canvas实现拼图小游戏

不言

不言

发布时间:2018-09-10 17:02:45

|

10001人浏览过

|

来源于php中文网

原创

本篇文章给大家带来的内容是关于使用javascript中canvas实现拼图小游戏 ,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

如果您想要综合使用javascript中canvas、原生拖拽、本地存储等多种技术完成一个有趣的项目,那么这篇文章将非常适合您

1 简介和源码

该项目中的拼图小游戏使用javascript原创,相比于网站上类似的功能,它使用到的技术点更先进丰富,功能更强大,还包含程序开发中更多先进的思想理念,从该项目中您将能学到:

  • FileReader、Image对象的配合canvas对图片进行压缩,切割的技巧。

  • 学习小游戏开发中最常用的碰撞检测、状态监控、刷新保持状态的处理方法。

    立即学习Java免费学习笔记(深入)”;

  • 深入了解拖拽交换元素的细节,学习到动态元素绑定事件、回调函数的处理方式。

项目源码-github

下面是游戏界面的示例图:

2164685860-5b94dfed46af2_articlex.png

2 实现思路

根据游戏界面图我们可以将完成这么一个小游戏分为以下几步来实现:

  • 1.拖拽图片到指定区域,使用FileReader对象读取到图片的base64内容,然后添加到Image对象中

  • 2.当Image对象加载完成后,使用canvas对图片进行等比缩放,然后取到缩略图的base64内容,添加到另外一个缩略图Image对象中,并将该缩略图base64的内容保存到本地存储(localStorage)中

  • 3.当缩略图Image对象加载完成后,再次使用canvas对缩略图进行切割,该游戏中将缩略图切割成3*4一共12等份,使用本地存储保存每份切割缩略图base64内容,将缩略图顺序打乱,使用img标签显示在web页面上

  • 4.当缩略图切片都添加到web界面上以后,为每一份缩略图切片添加注册拖拽事件,使得缩略图切片可以相互交换,在这个过程当中,添加对缩略图切片顺序状态的监控,一旦完成拼图,就直接展示完整的缩略图,完成游戏

从以上对小游戏制作过程的分析来看,第4步是程序功能实现的重点和难点,在以上的每个步骤中都有很多小细节需要注意和探讨,下面我就详细分析一下每个步骤的实现细节,说的不好的地方,欢迎大家留言指正。

3 开发细节详解

3.1 图片内容读取和加载

在游戏开发第1步中,我们将图片拖拽到指定区域后,程序是怎样得到图片内容信息的呢?fileReader对象又是怎样将图片信息转化为base64字符串内容的?Image对象拿到图片的base64内容之后,又是怎样初始化加载的?带着这些疑问,我们来研究一下实现项目中实现了第一步的关键代码。

var droptarget = document.getElementById("droptarget"),
            output = document.getElementById("ul1"),
            thumbImg = document.getElementById("thumbimg");
            
 //此处省略相关代码........
           
function handleEvent(event) {
                var info = "",
                    reader = new FileReader(),
                    files, i, len;

                EventUtil.preventDefault(event);
                localStorage.clear();

                if (event.type == "drop") {
                    files = event.dataTransfer.files;
                    len = files.length;
                    if (!/image/.test(files[0].type)) {
                        alert('请上传图片类型的文件');
                    }
                    if (len > 1) {
                        alert('上传图片数量不能大于1');
                    }

                    var canvas = document.createElement('canvas');
                    var context = canvas.getContext('2d');
                    var img = new Image(),          //原图
                        thumbimg = new Image();     //等比缩放后的缩略图

                    reader.readAsDataURL(files[0]);
                    reader.onload = function (e) {
                        img.src = e.target.result;
                    }

                    //图片对象加载完毕后,对图片进行等比缩放处理。缩放后最大宽度为三百像素
                    img.onload = function () {
                        var targetWidth, targetHeight;
                        targetWidth = this.width > 300 ? 300 : this.width;
                        targetHeight = targetWidth / this.width * this.height;
                        canvas.width = targetWidth;
                        canvas.height = targetHeight;
                        context.clearRect(0, 0, targetWidth, targetHeight);
                        context.drawImage(img, 0, 0, targetWidth, targetHeight);
                        var tmpSrc = canvas.toDataURL("image/jpeg");
                        //在本地存储完整的缩略图源
                        localStorage.setItem('FullImage', tmpSrc);
                        thumbimg.src = tmpSrc;
                    }
                    
        //此处省略相关代码......
        
         EventUtil.addHandler(droptarget, "dragenter", handleEvent);
         EventUtil.addHandler(droptarget, "dragover", handleEvent);
         EventUtil.addHandler(droptarget, "drop", handleEvent);            
}

这段代码的思路就是首先获得拖拽区域目标对象droptarget,为droptarget注册拖拽监听事件。代码中用到的EventUtil是我封装的一个对元素添加事件、事件对象的兼容处理等常用功能的简单对象,下面是其添加注册事件的简单简单代码,其中还有很多其他的封装,读者可自行查阅,功能比较简单。

var EventUtil = {

    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    
    //此处省略代......
 }

当用户将图片文件拖放到区域目标对象droptarget时,droptarget的事件对象通过event.dataTransfer.files获取到文件信息,对文件进行过滤(限制只能为图片内容,并且最多只能有一张图片)。拿到文件内容以后,使用FileReader对象reader读取文件内容,使用其readAsDataURL方法读取到图片的base64内容,赋值给Image对象img的src属性,就可以等到img对象初始化加载完毕,使canvas对img进行下一步的处理了。这里有一个重点的地方需要说明:一定要等img加载完成后,再使用canvas进行下一步的处理,不然可能会出现图片损坏的情况。原因是:当img的src属性读取图片文件的base64内容时,可能还没有将内容加载到内存中时,canvas就开始处理图片(此时的图片是不完整的)。所以我们可以看到canvas对图片的处理是放在img.onload方法中进行的,程序后边还会有这种情况,之后就不再赘述了。

3.2 图片等比缩放和本地存储

在第一步中我们完成了对拖拽文件的内容读取,并将其成功加载到了Image对象img中。接下来我们使用canvas对图片进行等比缩放,对图片进行等比缩放,我们采取的策略是限制图片的最大宽度为300像素,我们再来看一下这部分代码吧:

 img.onload = function () {
                        var targetWidth, targetHeight;
                        targetWidth = this.width > 300 ? 300 : this.width;
                        targetHeight = targetWidth / this.width * this.height;
                        canvas.width = targetWidth;
                        canvas.height = targetHeight;
                        context.clearRect(0, 0, targetWidth, targetHeight);
                        context.drawImage(img, 0, 0, targetWidth, targetHeight);
                        var tmpSrc = canvas.toDataURL("image/jpeg");
                        //在本地存储完整的缩略图源
                        localStorage.setItem('FullImage', tmpSrc);
                        thumbimg.src = tmpSrc;
                    }

确定了缩放后的宽度targetWidth和高度targetHeight之后,我们使用canvas的drawImage方法对图像进行压缩,在这之前我们最好先使用画布的clearRect对画布进行一次清理。对图片等比缩放以后,使用canvas的toDataURL方法,获取到缩放图的base64内容,赋给新的缩放图Image对象thumbimg的src属性,待缩放图加载完毕,进行下一步的切割处理。缩放图的base64内容使用localStorage存储,键名为"FullImage"。浏览器的本地存储localStorage是硬存储,在浏览器刷新之后内容不会丢失,这样我们就可以在游戏过程中保持数据状态,这点稍后再详细讲解,我们需要知道的是localStorage是有大小限制的,最大为5M。这也是为什么我们先对图片进行压缩,减少存储数据大小,保存缩放图base64内容的原因。关于开发过程中存储哪些内容,下一小节会配有图例详细说明。

3.3 缩略图切割

生成缩略图之后要做的工作就是对缩略图进行切割了,同样的也是使用canvas的drawImage方法,而且相应的处理必须放在缩略图加载完成之后(即thumbimg.onload)进行处理,原因前面我们已经说过。下面我们再来详细分析一下源代码吧:

thumbimg.onload = function () {
                        //每一个切片的宽高[切割成3*4格式]
                        var sliceWidth, sliceHeight, sliceBase64, n = 0, outputElement = '',
                            sliceWidth = this.width / 3,
                            sliceHeight = this.height / 4,
                            sliceElements = [];

                        canvas.width = sliceWidth;
                        canvas.height = sliceHeight;

                        for (var j = 0; j < 4; j++) {
                            for (var i = 0; i < 3; i++) {
                                context.clearRect(0, 0, sliceWidth, sliceHeight);
                                context.drawImage(thumbimg, sliceWidth * i, sliceHeight * j, sliceWidth, sliceHeight, 0, 0, sliceWidth, sliceHeight);
                                sliceBase64 = canvas.toDataURL("image/jpeg");
                                localStorage.setItem('slice' + n, sliceBase64);
                                //为了防止图片三像素问题发生,请为图片属性添加 display:block
                                newElement = "
  • @@##@@
  • "; //根据随机数打乱图片顺序 (Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement); n++; } } //拼接元素 for (var k = 0, len = sliceElements.length; k < len; k++) { outputElement += sliceElements[k]; } localStorage.setItem('imageWidth', this.width + 18); localStorage.setItem('imageHeight', this.height + 18); output.style.width = this.width + 18 + 'px'; output.style.height = this.height + 18 + 'px'; (output.innerHTML = outputElement) && beginGamesInit(); droptarget.remove(); }

    上面的代码对于大家来说不难理解,就是将缩略图分割成12个切片,这里我给大家解释一下几个容易困惑的地方:

    • 1.为什么我们再切割图片的时候,代码如下,先从列开始循环?

     for (var j = 0; j < 4; j++) {
        for (var i = 0; i < 3; i++) {
            //此处省略逻辑代码
        }
      }

    这个问题大家仔细想一想就明白了,我们将图片进行切割的时候,要记录下来每一个图片切片的原有顺序。在程序中我们使用 n 来表示图片切片的原有顺序,而且这个n记录在了每一个图片切片的元素的name属性中。在后续的游戏过程中我们可以使用元素的getAttribute('name')方法取出 n 的值,来判断图片切片是否都被拖动到了正确的位置,以此来判断游戏是否结束,现在讲起这个问题可能还会有些迷惑,我们后边还会再详细探讨,我给出一张图帮助大家理解图片切片位置序号信息n:

    使用javascript中canvas实现拼图小游戏

    序号n从零开始是为了和javascript中的getElementsByTagName()选择的子元素坐标保持一致。

    • 2 我们第3步实现的目的不仅是将缩略图切割成小切片,还要将这些图片切片打乱顺序,代码程序中这一点是怎样实现的?
      阅读代码程序我们知道,我们每生成一个切片,就会构造一个元素节点: newElement = "

    • 1381663001-5b951e0a68eb5_articlex.png
    • "; 。我们在是在外部先声明了一个放新节点的数组sliceElements,我们每生成一个新的元素节点,就会把它放到sliceElements数组中,但是我们向sliceElements头部还是尾部添加这个新节点则是随机的,代码是这样的:

    (Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement);

    我们知道Math.random()生成一个[0, 1)之间的数,所以再canvas将缩略图裁切成切片以后,根据这些切片生成的web节点顺序是打乱的。打乱顺序以后重新组装节点:

    //拼接元素
    for (var k = 0, len = sliceElements.length; k < len; k++) {
        outputElement += sliceElements[k];
    }

    然后再将节点添加到web页面中,也就自然而然出现了图片切片被打乱的样子了。

    • 3.我们根据缩略图切片生成的DOM节点是动态添加的元素,怎样给这样动态元素绑定事件呢?我们的项目中为每个缩略图切片DOM节点绑定的事件是“拖动交换”,和其他节点都有关系,我们要保证所有的节点都加载后再对事件进行绑定,我们又是怎样做到的呢?

      PageOn
      PageOn

      AI驱动的PPT演示文稿创作工具

      下载

    下面的一行代码,虽然简单,但是用的非常巧妙:

    (output.innerHTML = outputElement) && beginGamesInit();

    有开发经验的同学都知道 && 和 || 是短路运算符,代码中的含义是:只有当切片元素节点都添加到
    WEB页面之后,才会初始化为这些节点绑定事件。

    3.4 本地信息存储

    代码中多次用到了本地存储,下面我们来详细解释一下本游戏开发过程中都有哪些信息需要存储,为什么要存储?下面是我给出的需要存储的信息图示例(从浏览器控制台获取):

    使用javascript中canvas实现拼图小游戏

    浏览器本地存储localStorage使用key:value形式存储,从图中我们看到我们本次存储的内容有:

    • FullImage:图片缩略图base64编码。

    • imageWidth:拖拽区域图片的宽度。

    • imageHeight:拖拽区域图片的高度。

    • slice*:每一个缩略图切片的base64内容。

    • nodePos:保存的是当前缩略图的位置坐标信息。

    保存FullImage缩略图的信息是当游戏结束后显示源缩略图时,根据FullImage中的内容展示图片。而imageWidth,imageHeight,slice*,nodePos是为了防止浏览器刷新导致数据丢失所做的存储,当刷新页面的时候,浏览器会根据本地存储的数据加载没有完成的游戏内容。其中nodePos是在为缩略图切片发生拖动时存入本地存储的,并且它随着切片位置的变化而变化,也就是它追踪着游戏的状态,我们在接下来的代码功能展示中会再次说到它。

    3.5 拖拽事件注册和监控

    接下来我们要做的事才是游戏中最重要的部分,还是先来分析一下代码,首先是事件注册前的初始化工作:

    //游戏开始初始化
    function beginGamesInit() {
        aLi = output.getElementsByTagName("li");
        for (var i = 0; i < aLi.length; i++) {
            var t = aLi[i].offsetTop;
            var l = aLi[i].offsetLeft;
            aLi[i].style.top = t + "px";
            aLi[i].style.left = l + "px";
            aPos[i] = {left: l, top: t};
            aLi[i].index = i;
            //将位置信息记录下来
            nodePos.push(aLi[i].getAttribute('name'));
        }
        for (var i = 0; i < aLi.length; i++) {
            aLi[i].style.position = "absolute";
            aLi[i].style.margin = 0;
            setDrag(aLi[i]);
        }
    }

    可以看到这部分初始化绑定事件代码所做的事情是:记录每一个图片切片对象的位置坐标相关信息记录到对象属性中,并为每一个对象都注册拖拽事件,对象的集合由aLi数组统一管理。这里值得一提的是图片切片的位置信息index记录的是切片现在所处的位置,而我们前边所提到的图片切片name属性所保存的信息n则是图片切片原本应该所处的位置,在游戏还没有结束之前,它们不一定相等。待所有的图片切片name属性所保存的值和其属性index都相等时,游戏才算结束(因为用户已经正确完成了图片的拼接),下面的代码就是用来判断游戏状态是否结束的,看起来更直观一些:

    //判断游戏是否结束
    function gameIsEnd() {
        for (var i = 0, len = aLi.length; i < len; i++) {
            if (aLi[i].getAttribute('name') != aLi[i].index) {
                return false;
            }
        }
    
        //后续处理代码省略......
    }

    下面我们还是详细说一说拖拽交换代码相关逻辑吧,拖拽交换的代码如下图所示:

    //拖拽
    function setDrag(obj) {
        obj.onmouseover = function () {
            obj.style.cursor = "move";
            console.log(obj.index);
        }
    
        obj.onmousedown = function (event) {
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
            obj.style.zIndex = minZindex++;
            //当鼠标按下时计算鼠标与拖拽对象的距离
            disX = event.clientX + scrollLeft - obj.offsetLeft;
            disY = event.clientY + scrollTop - obj.offsetTop;
            document.onmousemove = function (event) {
                //当鼠标拖动时计算p的位置
                var l = event.clientX - disX + scrollLeft;
                var t = event.clientY - disY + scrollTop;
                obj.style.left = l + "px";
                obj.style.top = t + "px";
    
                for (var i = 0; i < aLi.length; i++) {
                    aLi[i].className = "";
                }
                var oNear = findMin(obj);
                if (oNear) {
                    oNear.className = "active";
                }
            }
    
            document.onmouseup = function () {
                document.onmousemove = null;       //当鼠标弹起时移出移动事件
                document.onmouseup = null;         //移出up事件,清空内存
                //检测是否普碰上,在交换位置
                var oNear = findMin(obj);
                if (oNear) {
                    oNear.className = "";
                    oNear.style.zIndex = minZindex++;
                    obj.style.zIndex = minZindex++;
    
                    startMove(oNear, aPos[obj.index]);
                    startMove(obj, aPos[oNear.index], function () {
                        gameIsEnd();
                    });
    
                    //交换index
                    var t = oNear.index;
                    oNear.index = obj.index;
                    obj.index = t;
    
                    //交换本次存储中的位置信息
                    var tmp = nodePos[oNear.index];
                    nodePos[oNear.index] = nodePos[obj.index];
                    nodePos[obj.index] = tmp;
                    localStorage.setItem('nodePos', nodePos);
                } else {
                    startMove(obj, aPos[obj.index]);
                }
            }
            clearInterval(obj.timer);
    
            return false;//低版本出现禁止符号
        }
    }

    这段代码所实现的功能是这样子的:拖动一个图片切片,当它与其它的图片切片有碰撞重叠的时候,就和与其左上角距离最近的一个图片切片交换位置,并交换其位置信息index,更新本地存储信息中的nodePos。移动完成之后判断游戏是否结束,若没有,则期待下一次用户的拖拽交换。
    下面我来解释一下这段代码中比较难理解的几个点:

    • 1.图片切片在被拖动的过程中是怎样判断是否和其它图片切片发生碰撞的?这就是典型的碰撞检测问题。
      程序中实现碰撞检测的代码是这样的:

    //碰撞检测
    function colTest(obj1, obj2) {
        var t1 = obj1.offsetTop;
        var r1 = obj1.offsetWidth + obj1.offsetLeft;
        var b1 = obj1.offsetHeight + obj1.offsetTop;
        var l1 = obj1.offsetLeft;
    
        var t2 = obj2.offsetTop;
        var r2 = obj2.offsetWidth + obj2.offsetLeft;
        var b2 = obj2.offsetHeight + obj2.offsetTop;
        var l2 = obj2.offsetLeft;
    
        `if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2)` {
            return false;
        } else {
            return true;
        }
    }

    这段代码看似信息量很少,其实也很好理解,判断两个图片切片是否发生碰撞,只要将它们没有发生碰撞的情形排除掉就可以了。这有点类似与逻辑中的非是即否,两个切片又确实只可能存在两种情况:碰撞、不碰撞。图中的这段代码是判断不碰撞的情况:if (t1 > b2 || r1 r2),返回false, else 返回true。

    2.碰撞检测完成了之后,图片切片之间又是怎样寻找左上角定点距离最近的元素呢?

    代码是这个样子的:

    //勾股定理求距离(左上角的距离)
    function getDis(obj1, obj2) {
        var a = obj1.offsetLeft - obj2.offsetLeft;
        var b = obj1.offsetTop - obj2.offsetTop;
        return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
    }
    
    //找到距离最近的
    function findMin(obj) {
        var minDis = 999999999;
        var minIndex = -1;
        for (var i = 0; i < aLi.length; i++) {
            if (obj == aLi[i]) continue;
            if (colTest(obj, aLi[i])) {
                var dis = getDis(obj, aLi[i]);
                if (dis < minDis) {
                    minDis = dis;
                    minIndex = i;
                }
            }
        }
        if (minIndex == -1) {
            return null;
        } else {
            return aLi[minIndex];
        }
    }

    因为都是矩形区块,所以计算左上角的距离使用勾股定理,这点相信大家都能明白。查找距离最近的元素原理也很简单,就是遍历所有已经碰撞的元素,然后比较根据勾股定理计算出来的最小值,返回元素就可以了。代码中也是使用了比较通用的方法,先声明一个很大的值最为最小值,当有碰撞元素比其小时,再将更小的值最为最小值,遍历完成后,返回最小值的元素就可以了。

    • 3.图片区块每次交换之后,是怎样监控判断游戏是否已经结束的呢?

    答案是回调函数,图片切片交换函数通过回调函数来判断游戏是否已经结束,游戏是否结束的判断函数前面我们已经说过。图片切片交换函数就是通过添加gameIsEnd作为回调函数,这样在每次图片切片移动交换完成之后,就判断一下游戏是否结束。图片切片的交换函数还是比较复杂的,有兴趣的同学可以研究一下,下面是其实现代码,大家重点理解其中添加了回调函数监控游戏是否结束就好了。

    //通过class获取元素
    function getClass(cls){
        var ret = [];
        var els = document.getElementsByTagName("*");
        for (var i = 0; i < els.length; i++){
            //判断els[i]中是否存在cls这个className;.indexOf("cls")判断cls存在的下标,如果下标>=0则存在;
            if(els[i].className === cls || els[i].className.indexOf("cls")>=0 || els[i].className.indexOf(" cls")>=0 || els[i].className.indexOf(" cls ")>0){
                ret.push(els[i]);
            }
        }
        return ret;
    }
    function getStyle(obj,attr){//解决JS兼容问题获取正确的属性值
        return obj.currentStyle?obj.currentStyle[attr]:getComputedStyle(obj,false)[attr];
    }
    
    function gameEnd() {
        alert('游戏结束!');
    }
    
    function startMove(obj,json,fun){
        clearInterval(obj.timer);
        obj.timer = setInterval(function(){
            var isStop = true;
            for(var attr in json){
                var iCur = 0;
                //判断运动的是不是透明度值
                if(attr=="opacity"){
                    iCur = parseInt(parseFloat(getStyle(obj,attr))*100);
                }else{
                    iCur = parseInt(getStyle(obj,attr));
                }
                var ispeed = (json[attr]-iCur)/8;
                //运动速度如果大于0则向下取整,如果小于0想上取整;
                ispeed = ispeed>0?Math.ceil(ispeed):Math.floor(ispeed);
                //判断所有运动是否全部完成
                if(iCur!=json[attr]){
                    isStop = false;
                }
                //运动开始
                if(attr=="opacity"){
                    obj.style.filter = "alpha:(opacity:"+(json[attr]+ispeed)+")";
                    obj.style.opacity = (json[attr]+ispeed)/100;
                }else{
                    obj.style[attr] = iCur+ispeed+"px";
                }
            }
            //判断是否全部完成
            if(isStop){
                clearInterval(obj.timer);
                if(fun){
                    fun();
                }
            }
        },30);
    }

    4 补充和总结

    4.1 游戏中值得完善的功能

    我认为该游戏中值得优化的地方有两个:

    • 1.为拼图小游戏添加缩略图,因为缩略图有利于为玩游戏的用户提供思路。我们又在浏览器本地存储中保存了缩略图的base64内容,所以实现起来也很容易。

    • 2.缓存有的时候也让人很痛苦,就比如说在游戏中有些用户就想要重新开始,而我们的小游戏只有在游戏完成之后才清空缓存,刷新页面,游戏才能够重新开始。这给用户的体验很不好,我们可以加一个重置游戏按钮,清空缓存并优化游戏结束后的一些逻辑。

    这些功能感兴趣的小伙伴可以尝试一下。

    相关推荐:

    用javascript实现web拼图游戏

    H5的canvas实现贪吃蛇小游戏

    2255600358-5b9526feb8426_articlex.png

    相关专题

    更多
    js获取数组长度的方法
    js获取数组长度的方法

    在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

    557

    2023.06.20

    js刷新当前页面
    js刷新当前页面

    js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

    374

    2023.07.04

    js四舍五入
    js四舍五入

    js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

    754

    2023.07.04

    js删除节点的方法
    js删除节点的方法

    js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

    478

    2023.09.01

    JavaScript转义字符
    JavaScript转义字符

    JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

    434

    2023.09.04

    js生成随机数的方法
    js生成随机数的方法

    js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

    1011

    2023.09.04

    如何启用JavaScript
    如何启用JavaScript

    JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

    658

    2023.09.12

    Js中Symbol类详解
    Js中Symbol类详解

    javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

    553

    2023.09.20

    Java JVM 原理与性能调优实战
    Java JVM 原理与性能调优实战

    本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

    19

    2026.01.20

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    React 教程
    React 教程

    共58课时 | 3.9万人学习

    TypeScript 教程
    TypeScript 教程

    共19课时 | 2.3万人学习

    Bootstrap 5教程
    Bootstrap 5教程

    共46课时 | 2.9万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号