前端测试,或者 UI 测试一直是业界一大难题。最近
Q.js
使用 Karma 作为测试任务管理工具,本文在回顾前端测试方案的同时,也分析下为什么Q.js
选用 Karma 而不是其他测试框架。
像素级全站对比
曾今有一批人做过这样的 UI 测试,即最终页面图像是否符合预期,通过图片差异对比来找出可能的问题。
如图所示,所谓像素级站点对比,即利用截屏图像前后对比来找出,站点前后差异,从而发现问题。
简单来说,phantomjs 就是一个运行在 node 上的 webkit 内核,支持 DOM 渲染,css 选择器,Canvas,SVG 等,在浏览器上能做的事情,理论上,phantomjs 都能模拟做到。
phantomjs 使用场景:
页面自动化测试: 无需浏览器的情况下进行快速的 Web 测试,且支持很多测试框架,如 YUI Test、Jasmine、WebDriver、Capybara、QUnit、Mocha 等。
网页监控: 定期打开页面,检查网站是否正常加载,加载结果是否符合预期等
诚然,吉他有上千个和弦。世界上最厉害的吉他大师,也无法一眼辨识出所有的和弦。
更多时候,我们熟记几个基本的和弦,然后通过一定的计算法则,去推导其他的和弦。因而推导的逻辑就非常重要。
《吉他三月通》一书把这乐理洋洋洒洒说了一百多页,我想试着让事情简单一些。
最后,我们将逻辑实现成一个小程序,可以方便打印出想要推导的和弦。
音乐与数学的不同
在这之前,我们得谈点有趣的事情,它们都有共同的原因:
- 为什么我们会觉得某首歌很 “中国风”?
- 为什么某些日本的传统音乐听起来很 “诡异”?
- 为什么钢琴要做成黑键白键,所有键都一样不行吗?
随着 互联网的蓬勃发展,并且伴随着产品功能的越来越复杂,对于技术人员来说最大的挑战就是如何在保证业务快速发展的同时,也可保证不断复杂的业务对用户体验的影响,其中对用户来说最重要的体验指标是如何快速、稳定的访问业务网站以及产品功能,既是网站的性能。本系列文章将会从前后端性能指标定义、性能工具使用、产品业务核心性能指标、前后端性能解决方案出发对这个性能优化体系进行完整的阐述。
建议阅读人群:
前端工程师、后端工程师、产品经理
核心性能定义介绍:
由于涉及前后端的性能指标、定义非常多,本文将重点介绍对前后端影响比较大的指标,让大家对性能优化的核心指标有个整体的认识与了解
后端性能定义
CSS3 的 3D 变换
transform 属性
attr | des | css level |
---|---|---|
transform | 向元素应用 2D 或 3D 转换。 | 3 |
transform-origin | 允许你改变被转换元素的位置。 | 3 |
transform-style | 规定被嵌套元素如何在 3D 空间中显示。 | 3 |
perspective | 规定 3D 元素的透视效果。 | 3 |
perspective-origin | 规定 3D 元素的底部位置。 | 3 |
backface-visibility | 定义元素在不面对屏幕时是否可见。 | 3 |
@transfrom 兼容性
IE10,firefox 以及 Opera 支持 @keyframe,而 chrome 和 safari 需要加浅醉-webkit-,IE9 及早期 IE 版本是不支持的,所以这些功能一般是在移动端使用.
一个 demo
这个 div 会沿着 Y 轴旋转 130deg
1 2 3 4 5 |
div { transform: rotateY(130deg); } |
一个 H5 上的应用场景
实现一个旋转木马的效果,这里列出核心代码,完整的后续放在 github 上
核心是 css 代码
一个 div 作为舞台的
1 2 3 4 5 6 |
<div <span class="keyword">class</span>=<span class="string">"container"</span>> </div> .container { perspective: <span class="number">800</span>px; <span class="comment">//这里是一个视角的位置,</span> } |
perspective 800px 是一个视角的位置,表示屏幕距离 3d 变化中心点的位置,一般是这个经验值,可以设置大一点,这样你看到的动画什么的就会离你很远。。。。
一个容器
1 2 3 4 5 6 7 8 |
<div <span class="keyword">class</span>=<span class="string">"container"</span>> <ul id=<span class="string">"js-course-list-3"</span> <span class="keyword">class</span>=<span class="string">"m-courseList"</span>></ul> </div> .m-courseList { transform-style: preserve-<span class="number">3</span>d; } |
preserve-3d 是透视属性,有了这个用户看到的效果才有空间感,没有的话看到的效果就和 2d 没区别了。
所有卡片给到一个旋转的角度
用模板实现是很方便的一件事情
1 2 |
style="transform: rotateY(<%=opt.deg%>deg) translateZ(<%=opt.tz%>px);-webkit-transform: rotateY(<%=opt.deg%>deg) translateZ(<%=opt.tz%>px)" |
默认情况下上面所有的卡片效果看起来是旋转了,但是都挤到一起去了,上面的 translateZ 是让每个卡片向它们的正前方平移一个具体的,这样看来才会形成一个类似立体圆柱的效果,也就是旋转木马的效果了
要让它动起来,js 也少不了,在每次滑动结束后触发每个卡片的旋转
1 2 3 4 5 6 7 |
$.map(M.lis, <span class="keyword">function</span>(item, i) { <span class="keyword">var</span> deg = Math.floor(<span class="number">360</span>/M.max); $(item).css({ transform: <span class="string">'rotateY('</span>+ (index+i) * deg+<span class="string">'deg) translateZ('</span> + <span class="number">130</span> / Math.tan(deg /<span class="number">360</span> * Math.PI) +<span class="string">'px)'</span> }) }); |
CSS3 @keyframe 规则
属性
attr | des | css level |
---|---|---|
@keyframes | 规定动画。 | 3 |
animation | 所有动画属性的简写属性,除了 animation-play-state 属性。 | 3 |
animation-name | 规定 @keyframes 动画的名称。 | 3 |
animation-duration | 规定动画完成一个周期所花费的秒或毫秒。默认是 0。 | 3 |
animation-timing-function | 规定动画的速度曲线。默认是 "ease"。 | 3 |
animation-delay | 规定动画何时开始。默认是 0。 | 3 |
animation-iteration-count | 规定动画被播放的次数。默认是 1。 | 3 |
animation-direction | 规定动画是否在下一周期逆向地播放。默认是 "normal"。 | 3 |
animation-play-state | 规定动画是否正在运行或暂停。默认是 "running"。 | 3 |
animation-fill-mode | 规定对象动画时间之外的状态。 | 3 |
@keyframe 兼容性
IE10,firefox 以及 Opera 支持 @keyframe,而 chrome 和 safari 需要加浅醉-webkit-,IE9 及早期 IE 版本是不支持的,所以这些功能一般是在移动端使用
一个 demo
该 demo 的作用是使 div 的背景从红色变成绿色,整个动画时间是 5s
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@keyframes myfirst { from {background: red;} to {background: yellow;} } div { animation: myfirst <span class="number">5</span>s; -moz-animation: myfirst <span class="number">5</span>s; <span class="comment">/* Firefox */</span> -webkit-animation: myfirst <span class="number">5</span>s; <span class="comment">/* Safari 和 Chrome */</span> -o-animation: myfirst <span class="number">5</span>s; <span class="comment">/* Opera */</span> } |
一个 H5 上的应用场景
H5 页面分屏的时候,底部一般会有一个小三角上下移动,表示还有一页内容的。
代码如下:
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 |
.item-1::after { position: absolute; left: 50%; margin-left: -11px; bottom: 1%; content: ''; background: url(../img/arrow.png) no-repeat center top; height: 22px; width: 20px; -webkit-animation: hover1 1s ease-in-out infinite alternate; animation: hover1 1s ease-in-out infinite alternate; -webkit-background-size: contain; background-size: contain; } @-webkit-keyframes hover1{ 0% { -webkit-transform: translateY(-10px); transform: translateY(-10px); } 100% { -webkit-transform: translateY(0); transform: translateY(0px); } } @keyframes hover1{ 0% { -webkit-transform: translateY(-10px); transform: translateY(-10px); } 100% { -webkit-transform: translateY(0); transform: translateY(0); } } |
可直接套用运行
最后的最后
在经历上面一番折腾之后,其实最终实现了的是另一种效果,感兴趣的同学可以用手机访问这里,看看第二页的效果。动画没什么特别,主要是变来变去的过程中用到了一些新的东西。
现在前端圈子最热的莫过于 ReactNative。以 Web 的开发方式来开发 Native,并且仗这 facebook 这个国际互联网公司做保证,这种革命性的产品都让前端 coder 和客户端 coder 都炸开了。本文打算以 ReactNative 的 Text 标签的角度,这个最基本的标签,来带你跨入入 ReactNative 的世界的第一步。
有时候我们的代码有很多的条件判断,我们只能用 switch 语句来让代码更好看一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function getDrink(type) { if (type === 'coke') { type = 'Coke'; } else if (type === 'pepsi') { type = 'Pepsi'; } else if (type === 'mountain dew') { type = 'Mountain Dew'; } else if (type === 'lemonade') { type = 'Lemonade'; } else if (type === 'fanta') { type = 'Fanta'; } else { // acts as our "default" type = 'Unknown drink!'; } return 'You\'ve picked a ' + type; } |
像上面介样子的代码,看起来是很头疼滴。而用 switch 语句,代码会更直观简洁。
react 是 facebook 推出一个用来构建用户界面的 js 库。官方介绍的三大特性如下:
just the ui
把 react 只当作一个 ui 组件就好,等同于传统 mvc 中的 view。
virtual dom
react 在编程模型和传统 dom 之间添加了一层,称之为虚拟 dom。好处非常多,性能更好,可以在 node 环境下完成渲染(解决 seo 问题),可以更好的用于开发 native apps。
data flow
反应式的单向数据绑定,比传统数据绑定更简单,简单的使用 js 事件触发改变组件状态也可以实现双向绑定的效果。
什么是 angularjs
angularjs 是 google 推出的一个前端 js 框架,面世已有几年时间,非常成熟,目前已经有非常多的第三方模块,基本上可以解决前端工程领域的各方面的问题。网上的资料也非常多,这里就不做过多介绍。
reactjs 和 angularjs
reactjs 是非常纯粹的组件式开发,所有的页面元素均由各大小组件组合而成。再插上虚拟 dom 的翅膀,实现了一处代码多平台执行的效果,关键是这货性能还不错。但是呢,除了组件以外,这货其他什么功能也没有,你需要重新造出所有的缺失的轮子或者选择第三方的轮子。
angularjs 则是一个完整的框架,意味着不需要太多的工作,就可以使用于大部分的业务场景。
简单好用的 module 和依赖注入系统,controller 中定义的数据和事件,service 实现不同组件之间共享数据,filter 处理筛选数据,forms 支持表单和复杂的表单验证,简单的动画模块 animations,强大的 directive 实现指令和指令的嵌套,可以很轻松的实现 reactjs 的组件及组件组合功能。ui 组件有 bootstrap for angular,路由有 ui-router,还有 promise 模块 $q,还有原生的 $resource 模块直接支持标准的 restful 接口,集成的单元测试,等等,哇哇,功能好多的样子,又到但是的环节,话说很多初学者会被很多 angularjs 的名词折磨的晕头转向。。。
如果要拿 reactjs 来开发应用,你还需要做很多额外的工作。而如果使用 angularjs 的话,就可以直接开始工作了。
两者之间其实无法直接拿来比较,毕竟 react 只是 view 的解决方案,而 angularjs 是包含 mv*的完整框架。
抛开跨平台和性能因素,就功能而言,angularjs 已经包含了 reactjs 的功能,只需要一个自定义 directive 加 controller 就可以轻松实现组件效果。
如果是一个大型项目,使用 angularjs 无疑更可靠。强大的功能带来一定的学习成本,但这一切都是值得的。
而使用 react 的话,你首先需要考虑一个问题,数据怎么管理?用哪个 mvc 库?接下来还有一堆问题等着你。
如果只是一个小型项目,那就看心情吧。
再单独说下关于数据的问题,react 还搞出了一个叫做 flux 的概念。简单看了一下 react 的 flux 模型,这不就是个观察者模式嘛。而 angular 至少支持了三种数据共享方式,包括 service,事件,rootScope 直接添加一个 object,可以分别适应各种不同的场景。
我们来看看 react 和 angular 实现组件的方式有什么不一样。。
组件实现
很多人包括我刚看到 jsx 时会想一个问题,我靠,这货是什么玩意?
js 已经有了 coffeescript、typescript 等,以后还有 es6,难道还要学一个这玩意?
还好,除了 jsx 外,我们也可以直接用 js 甚至 coffee 来编写,虽然麻烦了点。
你只要记住,在 react 的世界,jsx 的语法比 js 写起来更方便更容易理解就好了,具体用什么取决于你自己。
1 2 3 4 |
注1:为了便于没有jsx基础的jser理解,本文所有react示例均使用编译后的js代码。 注2:用coffee写更爽。 |
第一个组件,hello 系列,先看 react 的实现
1 2 3 4 5 6 7 8 9 10 11 |
<span class="keyword">var</span> HelloMessage = React.createClass({displayName: <span class="string">"HelloMessage"</span>, render: <span class="keyword">function</span>() { <span class="keyword">return</span> React.createElement(<span class="string">"div"</span>, <span class="keyword">null</span>, <span class="string">"Hello "</span>, <span class="keyword">this</span>.props.name); } }); React.render( React.createElement(HelloMessage, {name: <span class="string">"John"</span>}), document.getElementById(<span class="string">'container'</span>) ); |
看一看 angular 正常的方式:
template.html
1 2 |
<div>Hello {{name}} </div> |
controller
1 2 3 4 5 |
<span class="keyword">var</span> app = angular.module(<span class="string">'app'</span>); app.controller(<span class="string">'testController'</span>,[<span class="string">"$scope"</span>,<span class="keyword">function</span>(<span class="variable">$scope</span>){ <span class="variable">$scope</span>.name = <span class="string">'John'</span>; }]); |
再看一看用 angular 式组件,使用 directive
1 2 3 4 5 6 7 8 9 10 |
<span class="keyword">var</span> app = angular.module(<span class="string">'app'</span>); app.directive(<span class="string">'myComponent'</span>,<span class="keyword">function</span>(){ <span class="keyword">return</span> { link:<span class="keyword">function</span>(scope,element,attrs){ <span class="keyword">var</span> name = attrs.name; element.text(<span class="string">'Hello '</span> + name); } } }); |
html:
1 2 |
<myComponent name="John"></myComponent> |
组件组合
react 的组件组合非常简单,使用 React.createElement
方法即可。
例如给上面定义的 HelloMessage
的外层添加一个 div
,可以这样写:
1 2 3 4 5 6 7 8 9 10 11 |
<span class="keyword">var</span> HelloMessageWithDiv = React.createClass({ displayName:<span class="string">'HelloMessageWithDiv'</span>, render:<span class="keyword">function</span>(){ <span class="keyword">return</span> React.createElement( <span class="string">'div'</span>, <span class="keyword">null</span>, React.createElement(HelloMessage, {name: <span class="string">"John"</span>}) ); } }); |
angular 也很简单,直接写 html 即可
1 2 |
<div><myComponent name="John"></myComponent></div> |
react 对 dom 的封装都在 React.DOM 命名空间下,而 coffeescipt 支持解构赋值语法,所以用 coffee 的写法也可以媲美 jsx 的语法,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{div,h1,h2,h3,h4,input,span} = React.DOM React.render( div <span class="keyword">null</span>,<span class="string">'head.'</span>, div <span class="keyword">null</span>,<span class="string">'nav'</span>, ul <span class="keyword">null</span>, li <span class="keyword">null</span>,<span class="string">'li1'</span> li <span class="keyword">null</span>,<span class="string">'li2'</span> div <span class="keyword">null</span>,<span class="string">'container'</span>, h1 <span class="keyword">null</span>,<span class="string">'title'</span> div <span class="keyword">null</span>,<span class="string">'content'</span> h2 <span class="keyword">null</span>,<span class="string">'h2'</span> ,document.getElementById <span class="string">'container'</span> ) |
为什么用 react
虽然目前 react 非常之火爆,但说实话,我也不知道在现在环境中用 react 有什么意义。
在使用 angularjs 开发几个项目之后,如果需要转向 react,只有以下几点可能会吸引我:
- 足够好的性能
- 跨平台开发的统一体验。这个还得等 react-android 出来后才知道。
- 兼容其他 js 库,在现有项目中就可以使用
而对于 angularjs,我认为目前 angularjs 已经足够好用了,除了以下几个显著的问题:
- 性能问题,目前 angularjs 在移动端的性能确实不够,因为它实在太大了。这个问题是最致命的。
- 只能在 angular 的框架下开发,第三方库要兼容 angular 都需要做一些工作。
对于 angularjs 其他所谓的缺点,其实大多可以解决,只是难易程度不同,例如 SEO/构建等都可以解决。
上手难易程度来说,angularjs 确实比 react 难很多,但这和一个工具是否好用没有关系,例如正则。
网上看到大家都在鼓吹 react 如何如何,又有很多人抛弃了 angular 投向 react 的怀抱。说实话有点吹的太过了。
react 只是让组件式开发和复用更加简单好用,外加逆天的性能,仅此而已。
最后,到底应该用什么,看你的心情吧,我要赶去改 bug 了。。