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

一、开篇

最近在网上看到了一款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:这个具体指的是屏幕的分辨率宽度,一般在移动设备上使用

 

四、相关的源码

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

 

posted @ 2016-04-12 22:45  热衷理财的技术渣渣  阅读(2412)  评论(0编辑  收藏  举报