图片 5

时间流互联网之未来,小公式大乐趣

canvas学习笔记:小公式大乐趣

2014/03/20 · HTML5 · 1
评论 ·
HTML5

原文出处: WAxes   

最近想弄一个网页,把自己学HTML5过程中做的部分DEMO放上去做集合,但是,如果就仅仅做个网页把所有DEMO一个一个排列又觉得太难看了。就想,既然学了canvas,那就来折腾下浏览器,做个小小的开场动画吧。

开场动画的效果,想了一会,决定用粒子,因为觉得粒子比较好玩。还记得以前我写的第一篇技术博文,就是讲文字图片粒子化的:文字图片粒子化 ,
那时就仅仅做的是直线运动,顺便加了一点3D效果。运动公式很简单。所以就想这个开场动画就做的更动感一些吧。

先上DEMO:

效果是不是比直线的运动更加动感呢?而且也确实很简单,别忘了这篇博文的题目,小小滴公式,大大滴乐趣。要做出这样的效果,用的就仅仅是我们初中。。或者高中时候的物理知识,加速运动,减速运动的公式啦。所以确实是小小滴公式。楼主很喜欢折腾一些酷炫的东西,虽然可能平时工作上用不上,但是,这乐趣确实很让人着迷啊。而且,做下这些也可以加强一下编程的思维能力哈。

废话不多说,进入主题啦。就简单的解释一下原理吧~~~

粒子运动的核心代码就这么一点:

JavaScript

update:function(time){ this.x += this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y; var xc =
this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za = 20; var
ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; }else { var gravity = 9.8; var vy = this.vy+gravity*time;
if(this.y>canvas.height){ vy = -vy*0.7; } this.vy = vy; } },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&&this.y>0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y>canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },

粒子总共有两种状态,一种是自由落体,一种就是受到吸力。自由落体就不说了。说吸力之前先贴出粒子的属性:

JavaScript

var Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y;
this.vx=vx; this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color
= color; this.visible = true; this.globleDown = false; this.setEnd(tox ,
toy); } setEnd:function(tox , toy){     this.tox = tox;
    this.toy = toy;     var yc = this.toy – this.y;     var
xc = this.tox – this.x; },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
setEnd:function(tox , toy){
    this.tox = tox;
    this.toy = toy;
    var yc = this.toy – this.y;
    var xc = this.tox – this.x;
},

x,y就是粒子的位置,vx是粒子水平速度,vy是粒子的垂直速度,nexttox之类知不知道都无所谓,只是暂时保存变量的。tox,和toy就是粒子的目的地位置。

首先,先给予所有粒子一个目的地,这个目的地下面再会说。也就是要粒子到达的地方,然后再定义一个变量za作为加速度,具体数值的话,就自己多测试下就会有大概参数的了,我设成20,感觉就差不多了。za是粒子和目的地之间连线的加速度,所以,我们通过粒子的位置和目的地的位置,通过简单的三角函数,就可以把粒子的水平加速度和垂直加速度求出来了,就这段

JavaScript

var ax = za*(xc/this.jl), ay = za*(yc/this.jl),

1
2
var ax = za*(xc/this.jl),
  ay = za*(yc/this.jl),

有了水平加速度和垂直加速度后,接下来就更简单了,直接计算水平速度和垂直速度的增量,从而改变水平速度和垂直速度的值

JavaScript

vx = (this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97;

1
2
vx = (this.vx+ax*time)*0.97,
vy = (this.vy+ay*time)*0.97;

之所以要乘于0.97是为了模拟能量损耗,粒子才会减速。time是每一帧的时间差

计算出速度后就更新粒子位置就行了。

JavaScript

this.x += this.vx*time; this.y += this.vy*time;

1
2
this.x += this.vx*time;
this.y += this.vy*time;

因为粒子在飞行过程中,与目的地之间的连线方向是不停改变的,所以每一帧都要重新计算粒子的水平加速度和垂直加速度。

运动原理就是如此,是否很简单呢。

运动原理说完了,再扯一下上面那个动画的具体实现吧:动画初始化,在一个离屏canvas上把想要的字或者图片画出来,然后再通过getImageData这个方法获取离屏canvas的像素。然后用一个循环,把离屏canvas中有绘制的区域找出来,因为imageData里的data值就是一个rgba数组,所以我们判断最后一个的值也就是透明度大于128就是有绘制过的区域。然后获取该区域的xy值,为了防止粒子对象过多导致页面卡顿,所以我们就限制一下粒子的数量,取像素的时候x值和y值每次递增2,从而减少粒子数量。

JavaScript

this.osCanvas = document.createElement("canvas"); var osCtx =
this.osCanvas.getContext("2d"); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = "center";
osCtx.textBaseline = "middle"; osCtx.font="70px
微软雅黑,黑体 bold"; osCtx.fillStyle = "#1D181F"
osCtx.fillText("WelCome" , this.osCanvas.width/2 ,
this.osCanvas.height/2-40); osCtx.fillText("To wAxes'
HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
this.osCanvas = document.createElement(&quot;canvas&quot;);
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = &quot;center&quot;;
        osCtx.textBaseline = &quot;middle&quot;;
        osCtx.font=&quot;70px 微软雅黑,黑体 bold&quot;;
        osCtx.fillStyle = &quot;#1D181F&quot;
        osCtx.fillText(&quot;WelCome&quot; , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText(&quot;To wAxes&#039; HOME&quot; , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                    var dot = new Dot(
                        Math.random()&gt;0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }

通过循环获取到粒子的位置xy值后,把位置赋给粒子,成为粒子的目的地。然后动画开始,就可以做出文字图片粒子化的效果了。

下面贴出动画实现的js代码。如果对其他代码也有兴趣的,可以直接看控制台哈,没压缩的。

JavaScript

var part_1 = (function(w){ var dots = [],DOT_SIZE = 2,cube=null; var
Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y; this.vx=vx;
this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color = color;
this.visible = true; this.globleDown = false; this.setEnd(tox , toy); }
Dot.prototype = { paint:function(){ ctx.fillStyle=this.color;
ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE ,
DOT_SIZE); }, setEnd:function(tox , toy){ this.tox = tox; this.toy =
toy; var yc = this.toy – this.y; var xc = this.tox – this.x; //
this.initjl = Math.sqrt(xc*xc+yc*yc); }, update:function(time){ this.x
+= this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y;
var xc = this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za =
20; var ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; //
if(Math.abs(this.vx)<1&&Math.abs(this.vy)<1){ // this.y =
this.toy // this.x = this.tox // } }else { var gravity = 9.8; var vy =
this.vy+gravity*time; if(this.y>canvas.height){ vy = -vy*0.7; }
this.vy = vy; } }, loop:function(time){ this.update(time); this.paint();
} } var animate = function(){ this.state = "before" } var ap =
animate.prototype; ap.init = function(){ this.osCanvas =
document.createElement("canvas"); var osCtx =
this.osCanvas.getContext("2d"); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = "center";
osCtx.textBaseline = "middle"; osCtx.font="70px
微软雅黑,黑体 bold"; osCtx.fillStyle = "#1D181F"
osCtx.fillText("WelCome" , this.osCanvas.width/2 ,
this.osCanvas.height/2-40); osCtx.fillText("To wAxes'
HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }
console.log(dots.length) } ap.changeState = function(){ var osCtx =
this.osCanvas.getContext("2d");
osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
this.osCanvas.width = 460; this.osCanvas.height = 100;
osCtx.fillStyle="#5C5656" osCtx.fillRect(20,20,60,60)
drawLogo(this.osCanvas , osCtx); var bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); var
index=0; dots.sort(function(a , b){ return Math.random()-Math.random();
}) for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var d = dots[index];
if(d){ d.setEnd(x+(canvas.width/2-300) , y+50) d.color =
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)";
index++ } } } } setTimeout(function(){ var endindex = index; for(var
i=0;i<dots.length-endindex;i++){ if(dots[index]){ var d =
dots[index]; d.globleDown = true; d.vx = Math.random()*100-50; }
index++; } } , 2000) } function endState(){ canvas.width = 600;
canvas.height = 100; canvas.style.display="block";
canvas.style.top = "50px"; canvas.style.left =
(window.innerWidth-canvas.width)/2+"px"; cube = new Cube(50);
cube._initVector(50,50); } function drawLogo(canvas , ctx){
ctx.textAlign = "center"; ctx.textBaseline =
"middle"; ctx.font="65px 微软雅黑,黑体 bold"
ctx.fillStyle="#E06D2F" ctx.fillText("DEMO" , 300 ,
canvas.height/2) ctx.font="40px 微软雅黑,黑体 bold"
ctx.fillStyle="#405159" ctx.fillText("吖猩的" , 160
, canvas.height/2) ctx.fillText("小窝" , 420 ,
canvas.height/2) } var num = 0; ap.update = function(time){ time =
time/100;
if(this.state==="first"||this.state==="before"){ var
completeNum = 0; dots.forEach(function(dot){ if(dot.visible)
dot.loop(time); if(dot.jl<5){ completeNum++ } });
if(completeNum>=5*dots.length/6){
if(this.state==="before"){ this.state = "first";
dots.forEach(function(dot){ dot.setEnd(dot.nextox , dot.nextoy); });
}else { this.state = "second"; this.changeState(); } } }else
if(this.state==="second"){ var completeNum = 0, allnum = 0;
dots.forEach(function(dot){ if(dot.visible) dot.loop(time);
if(dot.globleDown){ allnum++; if(Math.abs(dot.y-canvas.height)<2){
completeNum++ } } }); if(completeNum===allnum&&allnum!==0){
this.state = "third"; part_2.animate(); endState(); } }else
if(this.state==="third"){ cube.update(); drawLogo(canvas ,
ctx); } } return new animate(); })(window)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
var part_1 = (function(w){
    var dots = [],DOT_SIZE = 2,cube=null;
 
    var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
    Dot.prototype = {
        paint:function(){
            ctx.fillStyle=this.color;
            ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE , DOT_SIZE);
        },
 
        setEnd:function(tox , toy){
            this.tox = tox;
            this.toy = toy;
            var yc = this.toy – this.y;
            var xc = this.tox – this.x;
            // this.initjl = Math.sqrt(xc*xc+yc*yc);
        },
 
        update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&amp;&amp;this.y&gt;0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
                // if(Math.abs(this.vx)&lt;1&amp;&amp;Math.abs(this.vy)&lt;1){
                //     this.y = this.toy
                //     this.x = this.tox
                // }
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y&gt;canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },
 
        loop:function(time){
            this.update(time);
            this.paint();
        }
    }
 
    var animate = function(){
        this.state = &quot;before&quot;
    }
 
    var ap = animate.prototype;
 
    ap.init = function(){
        this.osCanvas = document.createElement(&quot;canvas&quot;);
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = &quot;center&quot;;
        osCtx.textBaseline = &quot;middle&quot;;
        osCtx.font=&quot;70px 微软雅黑,黑体 bold&quot;;
        osCtx.fillStyle = &quot;#1D181F&quot;
        osCtx.fillText(&quot;WelCome&quot; , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText(&quot;To wAxes&#039; HOME&quot; , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                    var dot = new Dot(
                        Math.random()&gt;0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }
        console.log(dots.length)
    }
 
    ap.changeState = function(){
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
        osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
        this.osCanvas.width = 460;
        this.osCanvas.height = 100;
 
        osCtx.fillStyle=&quot;#5C5656&quot;
        osCtx.fillRect(20,20,60,60)
 
        drawLogo(this.osCanvas , osCtx);
 
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        var index=0;
        dots.sort(function(a , b){
            return Math.random()-Math.random();
        })
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                        var d = dots[index];
                        if(d){
                            d.setEnd(x+(canvas.width/2-300) , y+50)
                            d.color = &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;;
                            index++
                        }
                }
            }
        }
 
        setTimeout(function(){
            var endindex = index;
            for(var i=0;i&lt;dots.length-endindex;i++){
                if(dots[index]){
                    var d = dots[index];
 
                    d.globleDown = true;
                    d.vx = Math.random()*100-50;
                }
                index++;
            }
        } , 2000)
    }
 
    function endState(){
        canvas.width = 600;
        canvas.height = 100;
        canvas.style.display=&quot;block&quot;;
        canvas.style.top = &quot;50px&quot;;
        canvas.style.left = (window.innerWidth-canvas.width)/2+&quot;px&quot;;
        cube = new Cube(50);
        cube._initVector(50,50);
    }
 
    function drawLogo(canvas , ctx){
        ctx.textAlign = &quot;center&quot;;
        ctx.textBaseline = &quot;middle&quot;;
        ctx.font=&quot;65px 微软雅黑,黑体 bold&quot;
        ctx.fillStyle=&quot;#E06D2F&quot;
        ctx.fillText(&quot;DEMO&quot; , 300 , canvas.height/2)
 
        ctx.font=&quot;40px 微软雅黑,黑体 bold&quot;
        ctx.fillStyle=&quot;#405159&quot;
        ctx.fillText(&quot;吖猩的&quot; , 160 , canvas.height/2)
        ctx.fillText(&quot;小窝&quot; , 420 , canvas.height/2)
    }
 
    var num = 0;
    ap.update = function(time){
        time = time/100;
        if(this.state===&quot;first&quot;||this.state===&quot;before&quot;){
            var completeNum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.jl&lt;5){
                    completeNum++
                }
            });
            if(completeNum&gt;=5*dots.length/6){
 
                if(this.state===&quot;before&quot;){
                    this.state = &quot;first&quot;;
                    dots.forEach(function(dot){
                        dot.setEnd(dot.nextox , dot.nextoy);
                    });
                }else {
                    this.state = &quot;second&quot;;
                    this.changeState();
                }
            }
        }else if(this.state===&quot;second&quot;){
            var completeNum = 0,
                allnum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.globleDown){
                    allnum++;
                    if(Math.abs(dot.y-canvas.height)&lt;2){
                        completeNum++
                    }
                }
            });
 
            if(completeNum===allnum&amp;&amp;allnum!==0){
                this.state = &quot;third&quot;;
                part_2.animate();
                endState();
            }
        }else if(this.state===&quot;third&quot;){
            cube.update();
            drawLogo(canvas , ctx);
        }
    }
 
    return new animate();
})(window)

赞 1 收藏 1
评论

图片 1

时间流互联网之未来(下)

2013/04/15 · HTML5 · 1
评论 ·
HTML5

来源:pingwest

危险的 target=”_blank” 与 “opener”

2018/09/05 · JavaScript
· target

原文出处:
创宇前端   

图片 2

在网页中使用链接时,如果想要让浏览器自动在新的标签页打开指定的地址,通常的做法就是在
a 标签上添加 target等于"_blank" 属性。

然而,就是这个属性,为钓鱼攻击者带来了可乘之机。

《时间流互联网之未来(上)》

起源

手机、Google Glass、智能手表、平板、电视……

移动互联网的发展,不仅让网络时间流特性更加明显、信息更加扁平化,同时对于普通大众来说,最大的变化便是多屏化趋势、以及每个屏幕信息扁平化展现形式的变化。而这最重要的一个原因,就是互联网从PC
走向手机、电视、手表等物联网时代的各种设备。本章我们就介绍一下各种大大小小的屏幕之间的差别、互联网内容在这些设备上的展现方式。

图片 3

在互联网还仅局限于PC
上之前,业内就有第一屏幕(电视)、第二屏幕(手机)、第三屏幕(PC)等等的说法。后来随着科技的发展,手机渐渐成为了第一屏幕,平板兴起并开始和电视争夺客厅的掌控权,而手表、眼镜也成了新兴屏幕,更别提Nest、冰箱、微波炉这些小屏幕了。

智能手机

移动互联网的发展,已经让智能手机成为了PC之外兼容互联网内容最优的设备,未来的网络内容展现形式和现在差异也不会太大。但手机的演化,也会使得未来我们使用手机的方式有些不同。

首先,手机屏幕越来越大,从3.5英寸到4英寸,从4英寸到5甚至5.5英寸,人们开始慢慢接受大屏幕。屏幕一大,自然呈现的信息就多,很多隐藏的很深的信息便可以直接放到桌面上,比如天气、信息、各种小插件等。这符合互联网时间流的变化,信息层级变浅,更多内容聚集到桌面上。

其次,触屏手机的流行,使得未来语音、智能传感器(如眼动仪、距离感应器等)得到发展。未来只需对着手机说句话,它就会告诉你任何信息,你不用去打开某款App,设备就可以自动从网络上找到你想要的东西。信息进一步扁平,HTML5网站内容可直接呈现在手机屏幕上。

平板电脑

平板电脑的流行也就这两三年的事(2010年iPad第一代发布),虽然之前也有各种Pad
概念和设备。平板延续了智能手机的操作系统,导致其易用性也比PC更高。相比PC
这种生产力工具,平板更像是一个生活设备,而大部分家庭需要的,也只是用来休闲娱乐的生活设备。

所以整体上,平板和智能手机差不多,在互联网内容兼容、内容展示方式、人机交互等方面都已经非常成熟了。随着互联网时间流的扁平化,未来的平板更像是一个信息流自动展示平台。

智能电视

电视以前是客厅的霸主,现在平板的出现让人们在客厅也有了其他的事情可做,但智能电视很有可能挽回这种局面。和平板一样,智能电视也是一个互联网的时间流展示平台:所有内容在人们不看电视的时候自动滚动一些信息,比如天气、新闻、社交好友照片、新信息、分享内容等。而且智能电视的视讯系统和手势操控,能分别控制客厅视频通话和游戏这两大项目,在电视前和家人视频聊天、玩游戏是再自然不过的事了。

在网络信息流展示形式上,电视相比平板其呈现内容更少(虽然屏幕大但距离远),所以电视上的内容更偏向于后面的要讲的眼镜,即卡片式展示。除了语音和手势控制,电视上都是以大块内容展示的,比如一个电影海报可能就占据了半个屏幕,一场球赛直播可能就占据了3/4甚至更多的屏幕。但从目前智能电视的界面设计看,还没有做的很好的展现方式。

智能眼镜(Google Glass)

虽然本段我们以Google
Glass为例,但这里要声明的是:智能眼镜并不单独指Google
Glass这种形式。Google
Glass在智能眼镜研发上做的很好,但不排除未来会有其他的形式(比如Vuzix
的Smart Glasses M100),而且微软、索尼、Bluester
等竞争对手的加入,可能也会让智能眼镜领域拥有更多样性的生态。

在互联网时间流概念上,Google Glass
的信息展现方式可以说是最典型的了:Timeline Card 。Glass
的每一个信息都是一个小卡片,并以时间为排序方式。卡片上可以显示天气、时间、照片、短消息、视频通话等等,Google
把互联网内容进行了分解,社交好友的一条状态、Instagram上的一张图片都只放在一张卡片上,这样信息更加集中,也不会给用户造成干扰。

Google
Glass的这种“时间流卡片”的展示方式可以用在很多设备上,比如智能电视、智能手表、冰箱、洗衣机、Nest智能家居检测仪等。由于可是屏幕足够小,所以这种方式比较适合。而且HTML5的跨平台特性,也能让网络资源在这些小屏幕设备上很好展现。

智能手表

智能手表有很多,它可能也会像智能眼镜一样成为各大科技厂商的战略性产品,而且由于智能手表门槛要比眼镜低,可能更会有一批小厂商也涌进来。如果我们拿Pebble 为例,就可以知道手表屏幕很小,只能显示很少的内容,所以Timeline
Card的形式也适用,在此我们就不多说了。

但智能手表和智能眼镜都面临着同样的一个问题:由于体积太小,导致硬件受限,很难开发一个独立的操作系统,只能通过连接到手机成为一个显示屏。(虽然Google
Glass是独立运行的,但未来不保证其他眼镜也能解决这一问题。)

PC

互联网就是在这上面诞生的,PC
的价值毋庸置疑。但科技的发展,已经让PC慢慢退居二线了,我们现在绝大部分操作都可以在移动终端上完成,未来也不保证不会完全抛弃PC
。有人说,现在的PC 不应该叫PC 了,应该叫WC (Work Computer)。确实,PC
现在基本上成为了一个生产力工具,人们下班之后基本都不会摸电脑了,更何况对于老人孩子还非常难用。

 

parentopener

在说 opener 之前,可以先聊聊 <iframe> 中的 parent

我们知道,在 <iframe> 中提供了一个用于父子页面交互的对象,叫做 window.parent,我们可以通过 window.parent 对象来从框架中的页面访问父级页面的 window

opener 与 parent 一样,只不过是用于 <a target="_blank"> 在新标签页打开的页面的。通过 <a target="_blank"> 打开的页面,可以直接使用 window.opener 来访问来源页面的 window 对象。

Facebook Home、HTC BlinkFeed功能、SO.HO……

Facebook 发布了一款基于Android 的深度应用 Facebook
Home,到现在国内外仍不乏许多媒体称赞Mark
Zuckerberg的明智之举。虽然我不认为Facebook
Home称得起如此大的赞誉,但它却实实在在地可以说是互联网时间流形态很好的例子。本文除了介绍Facebook
Home ,还会介绍HTC
Sence UI的BlinkFeed、第三方应用SO.HO 以及和互联网时间流理论类似的简单演示 lifestreams.com等。

图片 4

Facebook Home

关于Facebook Home
,PingWest之前的几篇文章有过介绍。它是一款Android手机深度定制App,相当于在应用层和系统层中间加了一层。用户的直接使用感受就是:你的Facebook
好友图片信息流都会在主屏幕显示,你可以滑动桌面浏览Facebook好友照片;当有短信、消息或Facebook
Message时,可以直接在主屏幕上进行回复、删除、存档等操作;与Facebook好友聊天也可以指直接在桌面上进行;另外Facebook
Home的 Launcher允许用户选取几个最常用的进行快速打开或使用。

可以看出,Facebook已经把互联网信息流(只有Facebook内容)直接推到用户的主屏幕上了,用户每时每刻都在浏览Facebook上的信息,而Facebook
的Newsfeed恰恰又是一时间流的形式排序的,所以这是一个非常典型的互联网时间流应用形式。

但互联网时间流并不只是newsfeed这一种类型,它还包括消息流、任务流等更细分的内容。Facebook
Home也把消息流很好的给用户展现出来了,但做的并不完美,而且Facebook
Home毕竟只是Facebook
一家的产品,未来用户桌面的互联网时间流会集成Facebook、Twitter、纽约时报、邮件等各种各样的内容。具体有哪些,完全依靠用户添加。

HTC Sence UI的BlinkFeed 功能

二月中下旬,当看到HTC Sence 5.0上的BlinkFeed
功能之后,我的心情相当激动,这就是互联网时间流的真正展现形式。BlinkFeed将你的社交网络、新闻资讯、生活娱乐、照片视频等各种信息一网打尽,直接在你的主屏幕上显示出来。BlinkFeed的信息源来自全球1400多家媒体和网站,同时还可以显示日历等用户信息,基本满足了所以用户的要求。

可能很多人并不习惯这样的浏览方式,而且直接把互联网信息推送到桌面上,对网速、手机续航、内存等也是一个压力。而且如果订阅的信息流很多的话,便会出现信息爆炸的情况,导致用户根本看不过来。不过这些问题都有各种办法来解决或优化,最后一章我们会详细介绍。

HTC的 Sence
UI本身就不错(现在手机也越来越漂亮了),而在手机的交互设计上,这家公司也越来越大胆。BlinkFeed
这种形式虽然现在还有点超前,但随着系统的不断迭代,以后会越来越符合人们的使用习惯。

lifestreams.com

lifestreams.com是一个互联网时间流概念的一个简单Demo,它本身也是根据David
Gelernter的理论设计的。其采用了Google Glass 的 Timeline
Card形式,并根据时间流排序。我们在前一章也介绍过,Timeline Card
这种形式非常适合智能手表、眼镜或其他的小屏幕设备,但在手机或平板上这种展示方式并不合适。

lifestreams.com 虽然严格依据David
Gelernter的时间流互联网概念,但还是太偏理论。不过这种形式基本上给出了未来网络信息展示形态的基本样式,以后的网络信息流会以此为基本形式进行各种更高级的演化。

第三方应用SO.HO

SO.HO是一款Android
App,准确地说,是一款Android启动器(Launcher)。在Google
Play上线也只有一个月左右的时间,和Facebook
Home差不多,SO.HO也是让你在屏幕上直接显示Facebook上的内容,同时还支持Twitter。产品做得很糙,但已经有点未来的意思了。

SO.HO上线两天,Google
Play下就有人评论说:“可以加上Google+、多账户twitter、Foursquare、Instagram、tumblr、RSS”。显然,大家想得都一样,我们可以把手机桌面上塞满各种我们想要的信息……

正如前面在BlinkFeed
那段我们提到的一样,把所有信息都放在一个屏幕上显然很不靠谱。我们应该对其进行合理的分类,比如社交信息、新闻资讯一个屏幕,短信、消息、邮件等一个屏幕,专业内容(工作需要)的东西再放一个屏幕(如BlackBerry
10的Balance生活工作切换功能),这样就简单多了。

 

同域与跨域

浏览器提供了完整的跨域保护,在域名相同时,parent 对象和 opener
对象实际上就直接是上一级的 window 对象;而当域名不同时,parent
opener 则是经过包装的一个 global 对象。这个 global
对象仅提供非常有限的属性访问,并且在这仅有的几个属性中,大部分也都是不允许访问的(访问会直接抛出
DOMException)。

图片 5

在 <iframe> 中,提供了一个 sandbox 属性用于控制框架中的页面的权限,因此即使是同域,也可以控制 <iframe> 的安全性。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

标签:, ,
网站地图xml地图