指尖上行-移动前端开发进阶之路第1章学习笔记

01 移动页面开发

1.1页面布局

1.1.1 viewport

viewport,视图窗口,指移动设备上能用来显示页面的那部分区域。

默认情况下,部分移动设备上的浏览器会把自己默认的viewport设为980像素,也可能是其他值。

1)设备像素

设备物理像素指设备显示屏中使用的最小显示单元,也就是屏幕分辨率。iphone5是640*1136像素,iphone6是750*1334像素。

设备独立像素指web编程中的逻辑像素,也就是css像素。iphone5的css像素是320*568像素。

2)像素密度(PPI)

PPI是用来表示设备每英寸所拥有的物理像素数目。这个数值越高,我们看到的屏幕越清晰。

iphone5的PPI大约等于326。

当显示屏的PPI超过某一数值时,人的肉眼就无法分辨其中的单独像素了,这就是Retina显示屏。

3)设备像素比DPR

DPR指物理像素和CSS像素的比例。

var dpr = window.devicePixelRatio;

在前端,CSS像素是常用的尺寸单位。对于常规显示屏来说,物理像素和CSS像素的比值是1:1,但是在Retina屏幕设备中,一个CSS像素可能等于多个物理像素。

关于设备像素、像素密度及设备像素比等具体的数据可以到网站http://screensiz.es/上查看。

4)3个viewport

<1>Layout viewport

可以通过 document.documentElement.clientWidth,document.documentElement.clientHeight获取

<2>Visual viewport

浏览器或者APP的webview中的可视区域,称为visual viewport,可以通过window.innerWidth和window.innerHeight获取。

<3>Ideal viewport

Ideal viewport是一个理想中的、抽象的视图,在这个视图下,图片和文字无论在什么设备和分辨率下,看起来都会保持差不多的大小。

Ideal viewport的宽度并没有一个固定的尺寸,不同的设备之间存在差异。

通过设置viewport为width=device-width可以将layout viewport的宽度设置为Ideal viewport的宽度。

5)设置viewport

为了将浏览器默认的layout viewport宽度设置为Ideal viewport的宽度,在开发移动页面时一般都会在head标签中输入以下这段代码。

这段meta标签的作用就是让当前的layout viewport的宽度等于设备的Ideal viewport的宽度,同时不允许用户手动缩放。

viewport可以用js动态的修改。

6)图片模糊问题

在Retina显示屏等屏幕下,一个位图像素中对应了多个物理像素,导致位图像素中的色彩值不够分,多出来的那些物理像素只能就近取色,从而导致图片模糊。

解决方案就是将图片原本的尺寸放大一定的倍数,这个倍数便是参考DPR值,一般放大两倍设计即可,现在也有很多放大3倍。

1.1.2 布局形式

1)传统页面布局

一是需要考虑Retina屏幕的内容清晰度,主要内容限定在640px像素以内。

二是要注意测试不同分辨率的移动设备下,页面两边的背景图留白问题。

前端重构时所有元素的尺寸都缩小1倍

2)滑屏页面布局

通过CSS百分比来设置页面高度实现每一屏100%撑满

通过js实现滑屏效果,通过记录手指在屏幕上的位移量,计算滑动的方向,当手指离开屏幕时执行滑动切换。

1.1.3 Media Queries

通过CSS3的媒体查询来为不同设备应用不同的CSS规则。

1)使用Media queries

方式1:用link在外链样式表

方式2:直接写入的style里

@media screen and (max-width:320px){background:#fff;}

and用于链接多个媒体条件,当页面是竖屏并且分辨率在320px以上这样写

screen and (min-width:320px) and (orientation:landscape)

css3准备了许多媒体条件

device-aspect-ratio:高宽比例

device-height:设备屏幕输出高度

device-width:设备屏幕输出宽度

height:窗口渲染的高度

width:窗口渲染的宽度

resolution:分辨率

orientation:横/竖屏

grid:是否基于栅格设备

color-index:色彩表中的色彩数

color:每种色彩的字节数

css3新增的媒体类型

all:所有设备

braille:盲文触觉反馈设备

embossed:盲文打印机

handled:手持设备

print:打印预览

projection:投影设备

screen:彩色显示器

speech:语音同步器

tty:打字机

tv:电视设备

2)媒体查询中的断点设置

断点是指页面布局发生改变的临界点。

第1种:根据设备尺寸设置,有新尺寸设备需要额外适配

根据设备宽度设置(Ideal viewport的宽度尺寸)

@media screen and (max-width:320px){针对iphone5/5s的样式设备}

@media screen and (max-width:360px){针对部分android的样式设备}

@media screen and (max-width:375px){针对iphone6/6s的样式设备}

@media screen and (max-width:414px){针对iphone6p/6sp的样式设备}

@media screen and (max-width:768px)针对ipad mini竖屏的样式设备{}

根据设备方向设置

@media screen and (orientation:portrait){针对竖屏时的样式设备}

@media screen and (orientation:landscape){针对竖屏时的样式设备}

根据设备像素比设置

@media screen and (device-pixel-ratio:2){针对设备像素比为2的样式设备}

第2种:根据页面内容尺寸设置,主要用在将PC页面适配多终端的工作中

@media screen and (max-width:1000px){针对浏览器视窗小于1000px时的样式设备}

@media screen and (max-width:700px){针对浏览器视窗小于700px时的样式设备}

1.1.4 屏幕适应

1)百分比布局

百分比布局适合移动端页面的设备尺寸碎片化情况。

width的百分比值是以父元素的宽度为参考计算的

height在实际工作中只有在父元素的高度是一个指定值时,其子元素设置的百分比高度才会起作用,否则高度会被重置为auto。

W(元素当前百分比宽度)/H(padding-bottom) = 图片真实宽度/图片真实高度

2)缩放法

思路是,直接按640px重构设计稿,通过计算浏览器的实际宽度和页面宽度之间的比例,对页面进行缩放。

(function(fixwidth,id){

var elm = document.getElementById(id);

function setzoom(){

var cliwidth = document.documentElement.clientWidth || document.body.clientWidth;

var blwidth = cliwidth/fixwidth;

elm.style.zoom = blwidth;

};

window.addEventListener('resize',setzoom,false);

setzoom();

})(640,'wrap')

打开页面和出行窗口大小改变时,运行setzoom函数。setzoom函数先获取屏幕分辨率,然后通过设计稿来计算缩放比例。

好处是可以按设计稿的尺寸进行页面开发,然后让页面自动根据浏览器的分辨率进行缩放。

缺点是高度是随着宽度进行等比缩放的,所以滑屏布局不适合。

3)Rem自适应

根据根页面标签的字号匹配大小。比如的字号font-size:20px,那么CSS设定1rem的页面元素实际上会显示20px的大小,1.2rem会显示24px大小。

Rem不仅可以作为字号尺寸单位,还可用于其他如width,height,margin,padding等。

和缩放法的思路一样,如果整个页面的容器元素尺寸都是以rem为单位,只需根据当前浏览器分辨率动态的设置根目录的字号尺寸,页面就可以自动地去适应分辨率了。

将标签的字号设置成font-size:100px,比较方便处理。

(function(){

if(!window.addEventListener) return;

var html = document.documentElement;

function setfont(){

var cliwidth = html.clientWidth;

html.style.fontSize = 100*(cliwidth/640)+'px';

}

document.addEventListener('DOMContentLoaded',setfont,false)

})()

setfont函数先获取屏幕分辨率,然后按比例设置页面标签的字号。

对于雪碧图背景,设置好相应的background-size和background-position就可以了。

rem适用于移动端,PC部分浏览器不支持。

4)模块和内容的适应

针对PC和移动的特点,在模块和内容的显示上做一些小的调整和删减。

可以使用媒体查询针对大小手机分辨率做一些调整。

1.1.5 内容排布技巧

1)视频与iframe的自适应

w(元素当前百分比宽度)/H(padding-bottom)=4/3or16/9or16/10

.video{position:relative;width:100%;height:0;pading:0 0 56.25% 0;/*按照16:9的比例计算获得*/}

.video video{position:absolute;top:0;left:0;width:100%;height:100%;}

2)水平垂直居中

可以使用display:box来实现在移动端的水平垂直居中,加上前缀-webkit-和-moz-

外框的样式

.wrap{

width:100%;

height:100%;

display:-webkit-box;

-webkit-box-orient:horizontal;/*设置子元素的排列方式*/

-webkit-box-pack:center;/*水平居中*/

-webkit-box-align:center;/*垂直居中*/

}

1.2 页面调试

Chrome开发者工具

win操作系统下,f12键可以唤起开发者工具。

1.3 常用库和框架

1.3.1 jquery mobile 基于jquery和jquery UI

1.3.2 zepto 提供与jquery类似的API,但并不是100%覆盖jquery。

zepto支持自定义模块打包,可以按自己的业务需求进行打包下载。

1.3.3 cocos2d

cocos2d-JS是整合了cocos2d-html5和cocos2d-x javascript bindings的游戏引擎,一次编码可游戏同时部署在网页和原生应用渠道。

1)目录结构

frameworks--框架文件

res--图片、plist及音频文件

src--我们写的js文件

tools--工具类文件

.cocos-project.json

CMakeLists.txt

index.html

main.js--游戏入口

project.json--项目配置文件

在index.html页面加载了一个游戏画布canvas和游戏入口,其中main.js文件如下:

cc.game.onStart = function(){

  cc.view.adjustViewPort(true);//设置浏览器meta来适配屏幕

  cc.view.setDesignResolutionSize(320,480,cc.ResolutionPolicy.SHOW_ALL);//分辨率设置

  cc.view.resizeWithBrowserSize(true);

  //先预加载资源

  cc.LoaderScene.preload(g_resources,function(){

    cc.director.runScene(new MainMenuScene());//导演启动场景

  },this)

}

cc.game.run();

Project.json文件如下:

{

"project_type":"javascript",//工程类型

"debugMode":1,//debug模式

"showFPS":true,//是否显示FPS

"frameRate":60,//帧率

"id":"gameCanvas",//canvas的id

"renderMode":0,//渲染模式

"engineDir":"frameworks/cocos2d-html5",//引擎路径

"modules":["cocos2d"],

"jsList":[//自定义js源文件的一个集合

  "src/resource.js",

  "src/app.js",

]

}

src文件夹中的resource.js文件是用来填写预加载的图片列表,如下:

var res = {

HelloWorld_png:"res/HelloWorld.png",

CloseNormal_png:"res/CloseNormal.png",

CloseSelected_png:"res/CloseSelected.png",

}

var g_resources=[];

for(var i in res){

  g_resources.push(res[i])

}

src文件夹中的app.js,新建了一个层并在这个层当中添加了一张图片,最后把这个层添加到场景中,如下:

var HelloWorldLayer=cc.Layer.extend({

sprite:null,

ctor:function(){

  this._super();

  this.sprite=new cc.Sprite(res.HelloWorld_png);

  this.addChild(this.sprite)

}

})

var HelloWorldScene = cc.Scene.extend({

  onEnter:function(){

    this._super();

    var layer=new HelloWorldLayer();

    this.addChild(layer);

  }

})

2)Scene场景

Scene代表我们在游戏中需要构建不同的场景,如游戏菜单、游戏界面及游戏设置等。

var GameLayer = cc.Layer.extend({

  init:function(){

  //需要显示的场景内容,例如背景

  }

})

var GameScene = cc.Scene.extend({

  onEnter:function(){

    this._super();

    var layer = new GameLayer();

    this.addChild(layer);

    layer.init();

  }

})

场景跳转到另一个场景

var scene = new GameScene();

cc.director.runScene(scene);

3)Sprite(精灵)

sprite是一个2D图像,可以对它进行移动,旋转,缩放及动画等操作。

颜色精灵

var colorSprite = new cc.Sprite();

colorSprite.setTextureRect(cc.rect(0,0,128,128));

colorSprite.setColor(cc.color(255,128,128));

this.addChild(colorSprite)

普通精灵

var sprite = new cc.Sprite(res.bg_png);

this.addChild(sprite);

var rectSprite = new cc.Sprite(res.bg_png,cc.rect(x,y,w,h));//剪切其中的一小块

this.addChild(rectSprite)

使用texture创建

var texture = cc.textureCache.addImage("res/bg.png");

var  textureSprite= new cc.Sprite(texture);

this.addChild(textureSprite);

通过plist(帧动画常用到)

cc.spriteFrameCache.addSpriteFrames(res.skill_plist);

var frameSprite =new cc.Sprite("#skill_1.png");

this.addChild(frameSprite);

4)定时器

schedule表示间隔执行自定义函数,scheduleOnce表示执行一次自定义函数。

schedule(callback_fn,interval,repeat,delay)

scheduleOnce(callback_fn,delay)

callback_fn调用的方法名

interval间隔多久进行调用

repeat重复的次数

delay延迟多久再进行调用

schedule(callback_fn)每帧都调用一次,调用无数次,马上调用

schedule(callback_fn,interval)间隔interval调用一次,调用无数次,马上调用

scheduleUpdate每隔一帧执行一次默认函数update()

var Helloworld = cc.Layer.extend({

  init:function(){

    this._super();

    this.schedule(this.timeCallback,2,2,1)

    this.scheduleOnce(this.timeCallback,2)

    this.scheduleUpdate();

    return true;

  },

  timeCallback:function(dt){},

  update:function(dt){}

})

停止定时器

unschedule(callback_fn);停止指定的定时器

unscheduleAllCallbacks();停止所有的定时器

unscheduleUpdate();停止update方法

5)Action动作系统

cc.MoveTo();移动到这里

cc.MoveBy();相对于之前点再移动

cc.ScaleTo();

cc.scaleBy();

cc.RotateTo();

cc.RotateBy();

cc.JumpTo();

cc.JumpBy();

cc.FadeIn();

cc.FadeOut();

带By的方法都是支持reverse()方法的,即获取反向动作。

var move1 = new cc.MoveBy(2,cc.p(100,0));

var move2 = move1.reverse();

sp.runAction(new cc.Sequence(move1,move2));

顺序执行Sequence和并行执行Spawn

6)音频

播放(第 1个参数为音频文件,第2个参数为是否循环播放)

cc.audioEngine.playMusic(res.bg_mp3,false);播放背景音频

cc.audioEngine.playEffect(res.effect_mp3,false)播放动作音效音频

暂停

cc.audioEngine.pauseMusic();

cc.audioEngine.pauseEffect(soundId);

停止

cc.audioEngine.stopMusic();

cc.audioEngine.stopEffect(soundId);

cc.audioEngine.stopAllEffects();

恢复播放

cc.audioEngine.resumeMusic();

cc.audioEngine.resumeEffect(soundId);

cc.audioEngine.resumeAllEffects();

重新播放

cc.audioEngine.rewindMusic();

音量加减

cc.audioEngine.setMusicVolume(audioEngine.getMusicVolume()+0.1);

cc.audioEngine.setMusicVolume(audioEngine.getMusicVolume()-0.1);

cc.audioEngine.setEffectsVolume(audioEngine.getEffectsVolume()+0.1)

cc.audioEngine.setEffectsVolume(audioEngine.getEffectsVolume()-0.1)

判断背景音乐是否在播放

if(cc.audioEngine.isMusicPlaying()){

  cc.log("playing")

}else{

  cc.log("not playing")

}

7)事件

触摸事件

var listener = cc.EventListener.create({

  event:cc.EventListener.TOUCH_ONE_BY_ONE,//单次触摸事件

  swallowTouches:true,//阻止事件传递给下一层

  onTouchBegan:function(touch,event){

    var target = event.getCurrentTarget();//获取当前触发事件的对象

    var locationInNode = target.convertToNodeSpace(touch.getLocation());//基于本地坐标获取点击坐标

    var size = target.getContentSize();//获取当前节点大小

    var rect = cc.rect(0,0,size.width,size.height);//区域设定

    if(!(cc.rectContainsPoint(rect,locationInNode))){//判断触摸点是否在节点区域内

      return false;

    }

    //开始逻辑处理

    cc.log("sprite began..x="+locationInNode.x+",y="+locationInNode.y);

    target.opacity = 180;

    return true;

  },

  onTouchMoved:function(touch,event){

    var target = event.getCurrentTarget();

    var delta = touch.getDelta();//返回从前一个触摸点到当前点的距离delta

    target.x += delta.x;

    target.y += delta.y;

  },

  onTouchEnded:function(touch,event){

    var target = event.getCurrentTarget();

    target.opacity = 255;

  },

  onTouchCancelled:function(touch,event){

    cc.log("onTouchCancelled")

  }

})

重力感应事件

var Acceleration = TouchBaseLayer.extend({

  onEnter:function(){

    this._super();

    var sprite = new cc.Sprite(res.skill_png);

    this.addChild(sprite);

    sprite.setPosition(size.width/2,size.height/2);

    if('accelerometer' in cc.sys.capabilities){

      cc.inputManager.setAccelerometerEnabled(true);//开始重力加速度

      cc.inputManager.setAccelerometerInterval(1/60);//设置迭代间隔

      var listener =  cc.EventListener.create({

        event:cc.EventListener.ACCELERATION,

        callback:this.onListenerAccelerometer

      })

      cc.eventManager.addListener(listener,sprite)

    }else{

      cc.log("accelerometer not supported")

    }

  },

  onListenerAccelerometer:function(acc,event){

    var target = event.getCurrentTarget();

    var ballSize = target.getContentSize();

    var currPos = target.getPosition();

    var speed = 15;

    target.x = Acceleration.fixPos(currPos.x+acc.x*speed,ballSize.width/2,GC.w-ballSize.width/2);

    target.y = Acceleration.fixPos(currPos.y+acc.y*speed,ballSize.height/2,GC.h-ballSize.height/2);

  },

  onExit:function(){

    cc.inputManager.setAccelerometerEnabled(false);//关闭重力加速度监听

    this._super();

  },

  getEnTitle:function(){

    return "6.accelerometer";

  },

  getZhTitle:function(){

    return "重力加速计";

  }

})

1.3.4 CreateJS

CreateJS是一款基于Canvas的开发引擎,极大地简化和降低了HTML5 Canvas项目的开发难度和成本。

CreateJS主要提供5类开发引擎,分别是EaselJS(负责图形、事件、触控及滤镜等功能)、TweenJS(补间动画)、SoundJS(音频控制)、PreloadJS(文件加载)及Zoe(生成图片精灵及动画数据)。

你可能感兴趣的:(指尖上行-移动前端开发进阶之路第1章学习笔记)