• 分享一次失败的项目实践经验


    一、开篇

    最近在网上看到了一款canvas实现网页涂鸦效果的作品,感觉这个效果比较奇特而且在以前没有学习canvas这样的功能是不可思议的,所以本人秉着程序员的那一份执着,花了两三个小时的时间来研究了一下canvas涂鸦作品的代码,发现里面代码比较精辟,但是美中不足的是有些代码的结构会比较的混乱,让人感觉层次上面有点不太分明。所以本人就打算对这个代码结构进行重构使其更具有可读性。但是理想是丰满的现实是骨感的,经过这一次代码的分析和实践下来,对我也是打击蛮大的,以前从来都是认为前端只要能够熟悉调试工具就行了,但是这一次调试工具居然“失灵”了,具体的失灵原因最终也没有找到,失灵表现在:在调试上面去监控元素会发现得到的值是正确的,但是最终运行的结果却是错误。打击虽大,但是我也是挺高兴的,至少我现在懂得了学会了一些代码重构的方法和理解清楚了什么是this的指向之类的问题

    二、代码结构的编写

    由于我为了巩固之前在深入学习JavaScript(二)中提到的继承,所以采用的方法是将执行的方法都书写在new方法(对应下面的canvas)的父类中,然后在window.onload事件中实例化canvas类,canvas类中是将传入的参数传递给canvas的父类来的
    简化后的JavaScript结构代码如下:

    window.onload=function(){
        const A=1;
        var B=2;
        new canvas(A,B);
    }
    function canvas(a,b){
       var c=3;
       console.log(this.c):
    this.init.apply(this,arguments); } canvas.prototype={ init:function(A,B){ console.log(A+","+B); } }

     这里面我们需要注意的是:this.init.apply(this,arguments);这句话主要是用来this指的是当前调用的对象,也就是canvas对象(通过new canvas(A,B)来调用),但是你有没有注意到将变量c打印出来的结果是undefined,但是我们说this指的是canvas对象,这是为什么呢?其实我们在深入学习JavaScript(一)中就已经介绍过了,只不过没有在实际的项目中进行详解,因为通过var创建的变量c,是在window对象中声明的,不是在canvas对象中,所以我们只需要将var c=3改为this.c=3这样就可以正常运行了。还有这个时候this所指代的canvas对象包含有它的父类。总的一句话:调用这个方法或者是类的时候调用的对象是什么,那么这里面的this指代的就是什么。如果在调用对象不明确的时候,我们可以在调用对象的上级查找,因为如果是当前的对象没有发生变化的时候是会继承上级的this对象到下级的,这样会导致当前的对象比较难发现,示例:

    window.onload=function(){
        const A=1;
        var B=2;
        console.log(this);
        new canvas(A,B);
    }
    function canvas(a,b){
        this.c=3;
        console.log(this.c);
        this.init.apply(this,arguments);
    }
    canvas.prototype={
        init:function(A,B){
            console.log(A+","+B);
            this.test();
        },
        test:function(){
            alert('this is test');
        }
    }

    分析:在this.test()这个执行语句中,我们单从这个语句很难分析出this指代的是什么,所以我们需要向上查找,在canvas对象中的apply方法调用了init这个函数,由于这个canvas对象是被new canvas(A,B)初始化的,所以canvas对象中的this指代的是canvas对象,即canvas对象中的方法和变量。因为this对象没有改变,所以this会一级一级的向下继承,最终this.test()中的this就是指代canvas对象

    PS:apply的用法跟call的用法相似,但是只要的用途是用来将当前传入的参数传递给父类,这里我们以apply为例来进行讲解

    在上面的例子中我们对apply这个方法传入的参数是:A=1;B=2,这一步相信地球人都可以看得出来。所以关键还是理解arguments这个代表什么意思,arguments这个会被编译器解析为不定长的数组(其实在JavaScript中的数组都是不定长的,这个有别于其他的高级语言,例如:C#、java),然后会分别将A=1,B=2分别存放在数组的0号位上和1号位上,所以arguments=[1,2],call的作用是一样一样的,但是不是通过arguments这个参数来代表要传入的参数,而是直接将参数写在里面,例如:call(this,A,B)

    三、其他一些需要注意的细节和知识点回顾

    CSS 精灵技术

    CSS精灵技术这个对于比较年老的程序员来说应该都听说过吧,但是新一代的程序员中使用的比较少

    个人认为主要的原因是:

    1、制作一张精灵图花费的时间比较久(但是node.js的出现已经有了生成图片的工具)

    2、精灵图不是矢量图,所以不能够适应现在的响应式布局

    3、精灵要求在CSS定位上面的操作准确,这个会增大程序员的时间成本

    但是CSS精灵技术也是有自己的有点的

    1、精灵图其实就是将图标集成为一张图片,所以在浏览器向服务器发送请求的时候,服务器也就只需要返回一次数据就够了(当然这里没有包括JavaScript、HTML、CSS文件和其他文件),这个也是最重要的。

    PS:这里面的CSS精灵技术权当温故知新,如果没兴趣的同学可以跳过。本人也认为现在的SVG图标已经基本上代替了以前的这种CSS精灵技术,而且更加方便

     好的,我们这就来开始精灵技术的案例

    我们先准备一张雪碧图

     然后HTML代码是这样的

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>CSS精灵技术DEMO</title>
        <style>
            #showArea{
    
            }
            .btn{
                width:200px;
                height:65px;
                background:url(DEMO.png);
                background-position:0px -65px;
                
            }
            .btn:hover{
                background-position:0px -130px;
            }
        </style>
    </head>
    <body>
        <div id="showArea">
            <div class="btn"></div>
        </div>
    </body>
    </html>

    运行后的结果是:

    几个获取坐标的API之间的辨析

    这里我们以宽相关的来做辨析,获取长的基本上一模一样

    offsetX,clientX,offsetLeft,window.screen.width

    offsetX:所在的DOM对象中的坐标,以DOM对象的左上角坐标为原点

    clientX:获取的是相对于WINDOW对象的宽度

    如果是DOM对象与左边距为0的时候,那么clientX=offsetX

    但是如果是存在margin-left这个值得时候,那么clientX=offsetX+offsetLeft

    相信说到这里大家都猜到offsetLeft指的是什么吧,没错offetLeft指的是DOM对象相对于WINDOW的偏移量

    window.screen.width:这个具体指的是屏幕的分辨率宽度,一般在移动设备上使用

     

    四、相关的源码

    这里面提供了一个制作失败的代码供大家引以为鉴,里面的代码中有很多功能都没有实现,主要的问题是在画布中画笔和线段不能同步,这个也是导致失败的原因,希望各位大神看一看怎样修改,知道的麻烦再留言中告诉我一下,在此不胜感激,以上就是在这个项目中的体会所得。下载地址

  • 相关阅读:
    spring mvc中的@PathVariable
    JSP禁用缓存的方式 response.setHeader( "Pragma", "no-cache" ); setDateHeader("Expires", 0);
    request.getSession(true)和request.getSession(false)的区别
    Spring Mvc中DispatcherServlet和Servlet的区别小结
    web.xml中load-on-startup的作用
    Spring MVC过滤器-字符集过滤器(CharacterEncodingFilter)
    web.xml配置中的log4jRefreshInterval
    web.xml中webAppRootKey
    关于tolua的使用
    关于#pragma pack
  • 原文地址:https://www.cnblogs.com/st-leslie/p/5380768.html
Copyright © 2020-2023  润新知