wap手机小站开发总结

近期完成的一个 wap手机小站 ,过后稍微总结一下。

思考

如今,angular/react/vue 的大热,使得 jquery 即将退去的形势变得更为明朗。思考一番,倘若如今摒弃了 jquery 、哪个框架会更合适自己目前的项目呢?
当下的这个wap手机小站,大量的ajax数据进行前后交互,这不就是 SPA 单页面应用的趋势么?结合近期正在学到的 react-router ,觉得到时有必要将该 wap手机小站 用react来重构一下,为学习探索之用。

在这之前,还是先对当下这个刚完成的wap手机小站总结一下吧:

基本目录

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
|-- html
|-- list
list1.html
list2.html
|-- detail
|-- user
index.html
//……………
|-- static
|-- dev
|-- css
|-- compoment
base.scss
//……………
|-- style
index.scss
list.scss
//……………
|-- js
|-- compoment
myCom.js
//……………
|-- dom
index.js
list.js
//……………
|-- plugins
jquery.min.js
swiper.min.js
//……………
|-- images
//……………
|-- dist
//与dev目录完全一样,.scss变成.css
//……………

gulp

构建工具gulp主要用到的模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
var gulp = require('gulp'),
sass = require("gulp-sass"), //sass预处理
cleancss = require('gulp-clean-css'), //css压缩
uglify = require('gulp-uglify'), //js的压缩
imagemin = require('gulp-imagemin'), //图片的压缩
pngquant = require('imagemin-pngquant'), //图片压缩的参数设置
cssurl = require('gulp-make-css-url-version'), //css文件里引用url加版本号
plumber = require('gulp-plumber'), //出错时gulp任务不中断,并捕获错误
sourcemaps = require('gulp-sourcemaps'), //映射到对应的sass文件,css文件是压缩
changed = require('gulp-changed'), //仅仅传递更改过的文件
cleanmap = require('gulp-clean'), //清楚生成的 .map 文件
rev = require('gulp-rev-append'); //版本号,html中的js,css路径版本号
browserSync = require('browser-sync').create(); //自动刷新浏览器

一些说明:
gulp-changed:在设置watch的task任务时,往往监视的是一个目录下的所有js/css文件;当该目录下的其中一个js/css被修改并保存后,会触发该目录下所有的js/css文件进行处理。
gulp-changed 可以实现仅仅传递更改过的文件进入pipe();
但是在sass编译的时候,.scss文件 -> .css文件,本身就已经发生了变化,因此还是会把该目录下的所有 .scss文件进行了处理。暂且只能尽量把css分类别分目录进行监视,以减少那些未改动过不必要的处理。
gulp-rev-append:当html文件中的js/css引入写法是绝对路径的时候,gulp-rev-append失效、不能即时改变url后面的版本号。如:

1
href="http://aaa.com/aaa/wap/dist/css/style/index.css?rev=@@hash" //失效,rev=@@hash没有被替换成 MD5

require.js

require.js 模块化js,js文件的模块化
js的模块化主要有两方面:

  • 外部引用的一些jquery插件功能模块(如:jquery,echo,swiper等)
  • 自身定义的常用公共组件模块( myModule 里面一般是需求所需最适合自己的自定义功能模块,如一些正则、弹窗组件、cookie、客户端判断等等)

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//模块引入
require(['jquery', 'echo', 'swiper', 'myModule'],function($, echo, swiper, myModule){
//......
}
//模块定义并return
var fn1 = function(){};
var fn2 = function(){};
var fn3 = function(){};
//......
var obj = {
data1: val1,
data2: val2,
data3: val3,
//......
};

js 面向对象

js 面向对象模块化js,js 文件里 代码段的模块化
php 后台仅是把所有数据通过ajax接口扔给web前端,如何对数据进行处理、将其呈现在页面上,都是前端 zepto/jquery 的工作了。如此以来,js的代码量大幅增加。再加上 jquery无穷回调噩梦,所带来的难题雪上加霜。
js 代码段的面向对象的小模块化可以一定程度地破解这事。如:

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
//1.全局数据
var data1 = '',
data2 = '',
isData1 = false;
var data3 = '',
data4 = '',
isData2 = false;
//2.init
var Index = {
init: function(){
Func.fn1();
Func.fn2();
}
};
//3.页面
var Func = {
fn1: function(){},
fn2: function(){},
fn3: function(){},
};
//4.工具
var Mod = {
getPic: function(){},
getToken: function(){},
countDown: function() {},
mod1: function(){},
mod2: function(){},
mod3: function(thisPhone){}
};
//5.入口
$(function(){
Index.init();
});

ajax/json/jsonp

页面数据基本全是通过 jsonp 发给前端然后呈现在页面上;大量的数据和dom处理,对于 $.ajax() 的成功回调函数 success: function(){} 将会是一个噩梦;幸亏前面的 js面向对象写法、使得js代码块有了模块化,有效梳理清晰了代码功能之间的条理。

大量的ajax,自然就有了后台提供的大量的数据接口;某天那位后台说要改个接口,那还不得大面积满js页面地一个个修改?
踩过这样的坑,后来干脆把所有接口也放在一个公共js文件中:

1
2
3
4
5
6
var port = {
port1: 'url1', //接口地址1
port2: 'url2', //接口地址2
port3: 'url3', //接口地址3
//......
};

大量的ajax数据,html的js组装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
addHtml: function(games) {
var nHtml = '';
$.each(games,function(i, li) {
var downUrl = (lw.mType() == 'IOS') ? li.ios_url: li.andriod_url;
nHtml+= '<li class="game-li j_gameLi">'
+ '<a class="game-one" href="http://aaa/game_detail/'+li.id+'.html">'
+ '<img class="game-img" src="'+li.img+'">'
+ '<h4 class="game-name">'+li.name+'</h4>'
+ '<p class="game-des">'+li.des+'</p>'
+ '</a>'
+ '<a class="game-btn j_gameBtn" href="'+downUrl+'">下载</a>'
+ '</li>';
});
//插入html
$('#id').append(nHtml);
}

sass/rem/emmet/cssrem

gulp插件 gulp-sourcemaps 将压缩过的 js/css文件 映射到对应的尚未压缩过的 js/sass 文件,在调试中快速定位代码的位置、进行高效调试。
sass 嵌套带来的一个调试问题:css/sass 的行数定位、一般是定位到元素前的,比如:

1
2
3
4
5
6
.parent{
position:relative;
.child{
width:100px;
}
}

以上代码中,假如我们要快速定位到设置 .child 的 width 值的第四行,但是 gulp-sourcemaps 为我们定位到的只是 .parent 处的第一行
当嵌套过深时,定位的偏差就会越大。适度的嵌套可以既保持css的模块、又可方便调试的快速定位;一般一个小组件为一个嵌套的css块。

移动端的自适应摒弃了百分比的方式,采用了 rem 自适应做法(移动前端适配)。
rem 与 px 的转换,写一个就自己计算一遍么?如此效率不能忍。
sublime 插件 cssrem/rem-unit均可实现 rem 与 px 自动转换。配置插件中 font-size 值为 40,然后你只管按照ui设计图的大小敲出px大小,cssrem/rem-unit 便会自动进行转换。

sublime 另一个插件 emmet,在写 html 时候会让人有飞一般的感觉。详见 emmet语法

工具

fiddler、photoshop、fastStoneCapture、apache、chrome、postman、svn、git bash、sublime plugins、phpStorm 等
fiddler:将线上的 js/css 静态文件代理为本地对应的文件,堪称一绝;
apache: 开个本机的服务器,手机代理到电脑,真机测试(nginx也行);
git bash:主要用来执行 gulp 任务。

一些坑

  • cookie、localStrage在微信浏览器的坑;
  • 移动端的静态文件的缓存,gulp插件MD5版本号在绝对路径下的失效;
  • 标签的href链接,跳转不到苹果的 appstore;
  • 图片验证码在 mac/safari 一直填写不正确;
  • 字体图标替换png;
  • 弹窗填写表单的坑处理;
  • 删除重复绑定的事件:
1
$("#id").unbind("click.id").on("click.id",function(){});
  • 移动端实时监听输入框值变化:
1
$('input').on('input propertychange',function(){});
  • require.js 的 baseUrl 路径问题;
  • 等等。