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(生成图片精灵及动画数据)。