---
layout: post
title: "Web App 相关技术"
date: 2015-06-17 14:06:05
categories: JavaScript
tags: JavaScript HTML CSS Sass 移动端 XSS AMD requireJS CommonJS 性能优化 WebApp
---
* content
{:toc}
> 往前推2到3年,前端工程师还在忧心忡忡地想,移动互联网时代下,前端是不是没有生存空间了。但今天一看,在我们团队,前端工程师超过一半的工作都是在做移动端的Web或者APP的开发。移动Web或者APP在技术本质上是和做桌面端Web没有本质区别,但是移动端的坑那是非常的多,通过学习这部分内容,让你成为一名桌面移动通吃的前端开发工程师。
## 概念
* 参考: [移动 Web 开发入门](http://junmer.github.io/mobile-dev-get-started/)
上面这个 slide 资料讲的非常好,算是一个入门的介绍吧。带我们建立基本的移动 web 开发知识体系和常见问题的实践。包含以下几个方面:
* 基本概念
* Native
本地应用 使用 Java \ Objective-C \ Swift 开发
* WebApp
网页应用 html5 开发
* Hybrid
混合应用 ooxx(native, web)
* 对比
* 视觉
* 设备的像素
* 文字单位使用 rem
* viewport 属性
* 横屏竖屏
* Flex 伸缩布局
* 响应式设计
* 软键盘
* 隐藏地址栏
* 苹果设备添加到主屏图标
* 交互
* Touch
* click 延迟
* Scroll
* Gestures(hammer --A javascript library for multi-touch gestures)
* 手指友好设计
* HTML5 APIS(图像,摇动,声音等)
* 实践
* 屏蔽点击元素时的阴影
* 图像(像素、矢量图标、base64 减少请求、lazyload)
* CSS3(合理使用渐变/圆角/阴影、代替 js 动画、translate3d、解决动画闪烁)
* localStorage
* 避免(iframe、fixed + input)
* SPA 或 Multi page
* can I use
* 压缩合并
* @G/3G 下建立连接时间
* 调试
* 浏览器自己的调试工具,模拟手机设备
* weinre
关于 weinre 我写了一篇博客介绍它。[Weinre --WebApp 调试工具](http://gaohaoyang.github.io/2015/06/18/weinre/)
---
## head 标签
参考:
* [移动前端不得不了解的html5 head 头标签](http://www.css88.com/archives/5480)
上面的链接详细的讲解了:
* DOCTYPE
* charset
* lang属性
* 优先使用 IE 最新版本和 Chrome
* 360 使用Google Chrome Frame
* SEO 优化部分:页面标题
标签(head 头部必须),页面关键词 keywords,页面描述内容 description,定义网页作者 author,网页搜索引擎索引方式
* 为移动设备添加 viewport
`viewport` 可以让布局在移动浏览器上显示的更好。 通常会写
```html
```
* content 参数:
* width viewport 宽度(数值/device-width)
* height viewport 高度(数值/device-height)
* initial-scale 初始缩放比例
* maximum-scale 最大缩放比例
* minimum-scale 最小缩放比例
* user-scalable 是否允许用户缩放(yes/no)
* ios 设备,iOS 图标,Android,Windows 8
**总结:**
```html
标题
```
## 页面切换动画
* [移动端重构系列13——页面切换](http://www.w3cplus.com/mobile/mobile-terminal-refactoring-slider.html)
* [CSS3 3D Transform](http://www.w3cplus.com/css3/css3-3d-transform.html)
关于 HammerJS 的一个中文文档
* [Hammer.js](http://www.cnblogs.com/iamlilinfeng/p/4239957.html)
---
## CSS Processing
> CSS语言由于其自身语言设计的问题,加上一些浏览器兼容性问题,往往会使得我们在写它的时候,要写很多冗余代码,或者为了兼容性对同一个样式设定写好几遍。针对这些问题,诞生了CSS预处理和后处理的概念及相关方法、工具。
>
> 这些工具和方法帮助我们能够更加高效地书写可维护性更强的CSS代码。
这里我尝试使用了 Sass,果然很好用。下面记录几个 sass 教程。
* [Sass入门-w3cplus](http://www.w3cplus.com/sassguide/)
* [SASS用法指南-阮一峰](http://www.ruanyifeng.com/blog/2012/06/sass.html)
### 安装
首先要有 ruby 环境。
由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败。这时候我们可以通过gem sources命令来配置源,先移除默认的 https://rubygems.org 源,然后添加淘宝的源 https://ruby.taobao.org/,然后查看下当前使用的源是哪个,如果是淘宝的,则表示可以输入 sass 安装命令 `gem install sass` 了。
$ gem sources --remove https://rubygems.org/
$ gem sources -a https://ruby.taobao.org/
$ gem sources -l
*** CURRENT SOURCES ***
https://ruby.taobao.org
# 请确保只有 ruby.taobao.org
$ gem install sass
### 编译
sass --watch style.scss:style.css --style expanded
---
### 补充
**`rem`**
字体单位使用 rem,用户在手机上设置了字体大小时,不会打破布局,造成混乱。
* [CSS3的REM设置字体大小-w3cplus](http://www.w3cplus.com/css3/define-font-size-with-css3-rem)
* [响应式十日谈第一日:使用 rem 设置文字大小-一丝](http://www.iyunlu.com/view/css-xhtml/76.html)
---
## 安全
> 安全是大家经常容易忽视,但其实一旦出现影响会非常大的问题,尤其对于没有经历过企业开发,或者没有踩过坑的同学,如果等到公司工作,做实际项目后非常容易发生安全问题。
### 分类
WEB基本攻击大致可以分为三大类:“资源枚举”、“参数操纵” 和 “其它攻击”
* 资源枚举
* 参数操纵
* SQL注入
* XPath注入
* cgi命令执行
* XXS(cross-site scripting跨域脚本攻击)其重点是“跨域”和“客户端执行”
* Reflected XSS ——基于反射的XSS攻击。主要依靠站点服务端返回脚本,在客户端触发执行从而发起WEB攻击。
* DOM-based or local XSS——基于DOM或本地的XSS攻击
* Stored XSS——基于存储的XSS攻击
* 会话劫持
* 其它攻击
* CSRF(cross-site request forgery)跨站请求伪造
* 钓鱼攻击指的是网站的伪造,比如ta0bao.com,然后在其中应用XSS等方式发起攻击。
* 拒绝服务(DoS)指的是向网站发起洪水一样的请求(Traffic Floor),导致服务器超负荷并关闭,处理方法常规是采用QoS(Quality of Service)的软硬件解决方案。
### 关于 XSS
> **跨网站脚本**(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
>
> XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
>
> ——维基百科
### XSS 防护
1. 浏览器解析顺序:
HTML Parser >> CSS Parser >> JavaScript Parser
2. 浏览器解码顺序:
HTML Decoding >> URL Decoding >> JavaScript Decoding
3. 具体的防护方式:
* 验证输入并且基于语境和按照正确的顺序转义不可信数据
* HTML 中的字符串
* HTML 属性中的字符串
* 事件句柄属性和 JavaScript 中的字符串
* HTML 属性中的 URL 路径
* HTML 风格属性和 CSS 中的字符串
* JavaScript 中的 HTML
* 始终遵循白名单优于黑名单的做法
* 使用 UTF-8 为默认的字符编码以及设置 content 为 text/html
* 不要将用户可以控制的文本放在标签前。通过使用不同的字符集注射可以导致 XSS。
* 使用
* 使用推荐的 HTTP 响应头进行 XSS 防护
* 防止 CRLF 注入/HTTP 响应拆分
* 禁止 TRACE 和其他非必要方法
对于 innerHTML 的方式输出的,我们可以采用如下的方式转码
```js
/**
* 转码 XSS 防护
* @param {String} str 用户输入的字符串
* @return {String} 转码后的字符串
*/
function changeCode(str) {
str = str.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/\//g, "/");
return str;
}
```
---
参考:
* [浅谈WEB安全性(前端向)](http://www.cnblogs.com/vajoy/p/4176908.html)
* [XSS的原理分析与解剖](http://www.freebuf.com/articles/web/40520.html)
* [原创翻译:给开发者的终极XSS防护备忘录](http://www.fooying.com/chinese-translationthe-ultimate-xss-protection-cheatsheet-for-developers/)
---
## 性能优化
> 在自己做一些小项目时,可能是学校的一些网站项目,流量可能日均都不超过500,而且大多是校园局域网内访问;或者是开发一些实验室的MIS系统,这辈子你都不会去使用你开发的这个系统。在这样一些项目中,性能优化往往会被你忽略。
>
> 但是如果你是做一个日均PV数万、数十万、甚至更大的量级,开发的页面会被全国各地,不同网络条件的用户来进行访问。这个时候,性能问题就无法忽视了。在当今的网络条件下,如果你的页面3秒都无法完成首屏渲染,一定会让你的网站流失很多用户。
>
> 整个网站的性能优化有很多的环节和工作,大多数时候,不是前端工程师单独就能完成的,尤其在职能划分明确的公司中,往往需要前后端、运维、DBA等多个职位协同完成。所以,在我们的课程中,主要让你了解整个性能优化都涉及哪些方面的工作,同时,我们会专注介绍一些在前端领域可以重点关注的技术点。
这里就是网页的打开速度,如果你的网页打开速度很慢,那么一定会有用户的流失。所以性能优化很重要。
* 网页内容
* 减少http请求次数
* 减少DNS查询次数
* 避免页面跳转
* 缓存Ajax
* 延迟加载
* 提前加载
* 减少DOM元素数量
* 根据域名划分内容
* 减少iframe数量
* 避免404
* 服务器
* 使用CDN
* 添加Expires 或Cache-Control报文头
* Gzip压缩传输文件
* 配置ETags
* 尽早flush输出
* 使用GET Ajax请求
* 避免空的图片src
* Cookie
* 减少Cookie大小
* 页面内容使用无cookie域名
* CSS
* 将样式表置顶
* 避免CSS表达式
* 用\代替@import
* 避免使用Filters
* Javascript
* 将脚本置底
* 使用外部Javascirpt和CSS文件
* 精简Javascript和CSS
* 去除重复脚本
* 减少DOM访问
* 使用智能事件处理
* 图片
* 优化图像
* 优化CSS Sprite
* 不要在HTML中缩放图片
* 使用小且可缓存的favicon.ico
* 移动客户端
* 保持单个内容小于25KB
* 打包组建成符合文档
具体细节参考文章:
* [毫秒必争,前端网页性能最佳实践](http://www.cnblogs.com/developersupport/p/webpage-performance-best-practices.html)
我在 ToDo 这个任务中主要使用了 CDN 来加载静态资源。比如我使用了 [百度静态资源公共库](http://cdn.code.baidu.com/)。引用了里面的 fontawesome,速度果然比在 GitHub 仓库里快很多。下一步是压缩我自己写的静态资源。
其他参考资料:
* [给网页设计师和前端开发者看的前端性能优化](http://www.oschina.net/translate/front-end-performance-for-web-designers-and-front-end-developers#section:maximising-parallelisation)
* [梳理:提高前端性能方面的处理以及不足](http://www.zhangxinxu.com/wordpress/?p=3152)
* [css sprite原理优缺点及使用](http://www.cnblogs.com/mofish/archive/2010/10/12/1849062.html)
* [CSS Sprites:鱼翅还是三鹿?](http://www.qianduan.net/css-sprites-useful-technique-or-potential-nuisance/)
* [大型网站的灵魂——性能](http://www.cnblogs.com/leefreeman/p/3998757.html)
* [编写高效的 CSS 选择器](http://web.jobbole.com/35339/)
---
## 模块化
> 对于一个复杂项目,特别是多人协作的复杂项目,如何合理划分模块,如何更加方便地进行模块加载,如何管理模块之间的依赖,是一个项目团队都会面临的问题,目前业界已经有了一些较为普遍的解决方案,如AMD。这个部分希望你能够通过学习JavaScript的模块化,学习如何合理地规划项目模块,合理使用模块化工具来优化你的项目代码结构。
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,否则就都乱套了。
根据AMD规范,我们可以使用 `define` 定义模块,使用 `require` 调用模块。
目前,通行的 js 模块规范主要有两种:`CommonJS` 和 `AMD`。
### AMD规范
AMD 即 Asynchronous Module Definition,中文名是“异步模块定义”的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是 CommonJS
模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。
AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。
详细 API 如下:
* [AMD(中文版)](https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88))
---
### CommonJS规范
CommonJS 是服务器端模块的规范,Node.js 采用了这个规范。Node.JS 首先采用了 js 模块化的概念。
根据 CommonJS 规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为 global 对象的属性。
输出模块变量的最好方法是使用 module.exports 对象。
---
### 为什么要用 requireJS
试想一下,如果一个网页有很多的js文件,那么浏览器在下载该页面的时候会先加载js文件,从而停止了网页的渲染,如果文件越多,浏览器可能失去响应。其次,要保证js文件的依赖性,依赖性最大的模块(文件)要放在最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
RequireJS就是为了解决这两个问题而诞生的:
> (1)实现js文件的异步加载,避免网页失去响应;
> (2)管理模块之间的依赖性,便于代码的编写和维护。
#### requireJS
* [requireJS 官网](http://requirejs.org/)
* [requireJS 中文网](http://www.requirejs.cn/)
---
### AMD和CMD
CMD(Common Module Definition) 通用模块定义。该规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。AMD是依赖关系前置,CMD是按需加载。
> AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
> CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
* [CMD 模块定义规范](https://github.com/seajs/seajs/issues/242)
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
> AMD:提前执行(异步加载:依赖先执行)+延迟执行
> CMD:延迟执行(运行到需加载,根据顺序执行)
---
### 参考
* [Javascript模块化编程(一):模块的写法--阮一峰](http://www.ruanyifeng.com/blog/2012/10/javascript_module.html)
* [Javascript模块化编程(二):AMD规范](http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_definition.html)
* [Javascript模块化编程(三):require.js的用法](http://www.ruanyifeng.com/blog/2012/11/require_js.html)
* [详解 JavaScript 模块开发](http://segmentfault.com/a/1190000000733959)
* [浅谈模块化的JavaScript](http://www.cnblogs.com/jinguangguo/archive/2013/04/06/3002515.html?utm_source=tuicool)
* [再谈 SeaJS 与 RequireJS 的差异](http://div.io/topic/430)
* 玩转AMD系列 by erik@EFE
* [玩转AMD - 写在前面](http://efe.baidu.com/blog/dissecting-amd-preface/)
* [玩转AMD - 设计思路](http://efe.baidu.com/blog/dissecting-amd-what/)
* [玩转AMD - 应用实践](http://efe.baidu.com/blog/dissecting-amd-how/)
* [玩转AMD - Loader](http://efe.baidu.com/blog/dissecting-amd-loader/)
---
## 前端工程化
> 业界目前有非常多的前端开发工具,完成一些开发过程中可以自动化完成的工作,提高研发效率,并且可以提高多人协作时的开发过程一致性,提高整个项目的运维效率。
>
> 在EFE日常工作中,我们是基于EDP,完成项目开发过程中的项目构建、包管理、调试、单测、静态检测、打包、压缩、优化、项目部署等一系列所有工作。
注:
如果网络不好,可以使用 [淘宝 NPM 镜像](http://npm.taobao.org/)。
### 参考
* [前端工程与模块化框架](http://div.io/topic/439)
* [手机百度前端工程化之路](http://mweb.baidu.com/p/baidusearch-front-end-road.html)
* [对话百度前端工程师张云龙:F.I.S与前端工业化](http://www.infoq.com/cn/articles/yunlong-on-fis)
* [EDP](https://github.com/ecomfe/edp)
* [Grunt教程——初涉Grunt](http://www.w3cplus.com/tools/grunt-tutorial-start-grunt.html)
* [gulp入门指南](http://www.open-open.com/lib/view/open1417068223049.html)
* [Gulp开发教程(翻译)](http://www.w3ctech.com/topic/134)
* [Gulp 中文网](http://www.gulpjs.com.cn/)
* [npm的package.json中文文档](https://github.com/ericdum/mujiang.info/issues/6)
---
## 最终作品
在任务三中,做了一个 PC 端的 ToDo 应用。任务四是将它优化,以适应移动端设备。
### ToDo WebApp Version
* [任务四要求](https://github.com/baidu-ife/ife/tree/master/task/task0004)
* [源代码](https://github.com/Gaohaoyang/ToDo-WebApp)
* [在线 demo](http://gaohaoyang.github.io/ToDo-WebApp/)
* 手机查看 ↓ 二维码 ↓
![todoWebApp](http://7q5cdt.com1.z0.glb.clouddn.com/task4-code-todoWebApp.png)
* [我的博客 HyG](http://gaohaoyang.github.io)
### Details
* **数据存储**
以 JSON 模拟数据表的形式存储于 LocalStorage 中
使用数据库的思想,构建3张表。
cateJson 分类
childCateJson 子分类
taskJson 任务
分类表 cate
----------------------
id* | name | child(FK)
----------------------
子分类表 childCate
--------------------------------
id* | pid(FK) | name | child(FK)
--------------------------------
任务表 task
----------------------------------------------
id* | pid(FK) | finish | name | date | content
----------------------------------------------
* **使用 `Sass` 重构了 CSS 代码**
使用分块、继承等方式,使得代码更加清晰明了。
* **响应式布局**
针对手机端细节做了很多调整,更符合手机上的视觉交互习惯。
* **加入页面切换效果**
使用 `translate3d()`,纯 CSS3 切换动画效果。
* **处理了 XSS 防护**
对可能造成破坏的字符进行转码。
* **性能优化**
使用 CDN 处理静态资源 fontAwesome,压缩静态资源等
* **模块化**
使用 requireJS 模块化 JavaScript 代码。重构 JavaScript 代码。优化之前写的耦合性高的绑定事件,重新绑定事件,降低耦合性。期间根据具体需求重写了事件代理的代码。
* **前端工程化**
使用 gulp,自动编译 Sass,压缩 CSS 和 JavaScript 代码。并且配置了自动流程。
---
## 其他
### `-webkit-tap-highlight-color` 属性
感谢 [fiona](https://github.com/fiona23) 指出。
safari移动端点击的时候会闪一下加上 `-webkit-tap-highlight-color: transparent;` 就不会闪了。
参考:
* [`-webkit-tap-highlight-color` css88](http://www.css88.com/webkit/-webkit-tap-highlight-color/)
* [`-webkit-tap-highlight-color` 属性](http://ued.ctrip.com/webkitcss/prop/tap-highlight-color.html)
---
### textarea 标签 disabled 颜色
* 为什么用 disabled 属性?
因为我发现仅仅使用 readonly 属性,在 IE 下是显示光标的。于是使用 disabled。
* 出现的问题
各家浏览器对于 disabled 属性有自己的样式设定,比如 IE 下是灰色的。苹果设备下也是。改变这些样式的方法也不是统一的。如果要兼容 Safari 必须加上
```
background: #fff;
-webkit-text-fill-color: rgba(0, 0, 0, 1);
-webkit-opacity: 1;
```
于是最终代码如下:
```css
textarea:disabled {
color:#000;
background: #fff;
-webkit-text-fill-color: rgba(0, 0, 0, 1);
-webkit-opacity: 1;
}
```
* 参考:[Disabled input text color 中的评论](http://stackoverflow.com/a/4648315)