前言
笔者驽钝,最近由于工作关系才去学习了 Angular,发现在合适的项目下使用 Angular 开发真是非常畅快!MVC 框架需要一些学习成本才能上手,再加上 Angular 采用现在通行的约定优于配置(convention over configuration)理念,框架本身做了很多封装,所以实现起来需要开发人员对框架足够的熟悉。
Angular 一个典型的使用场景就是单页应用,那么如何在一个单页面中改变 URL,请与笔者一同学习。
一般来说我们的 footer 是跟着内容走的,所以当内容较少不足一屏的时候,footer 也会跟着内容往上走,导致下面一段空白。所以这里我们来探讨下当内容不足一屏时 footer 也要紧贴底部的情况,因为比较难以描述,所以干脆使用了英文标题,要实现的效果如下:
第一个和第三个为正常不处理的情况,第二个和第三个是我们要实现的情况
以前因为要兼容 ie7-,所以对结构比较有要求,实现起来也比较复杂。这里我们先讨论下 ie8+的情况,然后在来讨论下更高级的 flex 实现。
ie8+
实现思路为:设置 body 最小高度为 100%,相对定位,然后空出底部的高度,关键是要设置盒模型 box-sizing 为 border-box 或 padding-box,最后将 footer 绝对定位在底部即可。
html 代码如下:
|
1 2 3 4 5 |
<body> ... <div <span class="keyword">class</span>=<span class="string">"footer"</span>></div> </body> |
css 代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
html{ height: <span class="number">100</span>%; } body{ min-height: <span class="number">100</span>%; <span class="comment">/* 设置最小高度100% */</span> position: relative; <span class="comment">/* 设置最小高度100% */</span> box-sizing: border-box; <span class="comment">/* 设置盒模型为border-box,那样这个100%包括了下面的padding-bottom高度 */</span> padding-bottom: <span class="number">120</span>px; <span class="comment">/* 高度为footer的高度 */</span> } .footer{ position: absolute; <span class="comment">/* 将footer绝对定位在底部 */</span> left: <span class="number">0</span>; bottom: <span class="number">0</span>; width: <span class="number">100</span>%; height: <span class="number">120</span>px; } |
flex
flex 实现其实比上面的要求更严格,上面的几乎对结构没要求,而 flex 则对 footer 的兄弟元素是有要求的。
主要思路是设置 flex 的方向为垂直方向,然后设置内容占满其余的空间
html 代码如下:
|
1 2 3 4 5 6 |
<body> <div <span class="keyword">class</span>=<span class="string">"header"</span>></div> <div <span class="keyword">class</span>=<span class="string">"container"</span>></div> <div <span class="keyword">class</span>=<span class="string">"footer"</span>></div> </body> |
css 代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 |
html{ height: <span class="number">100</span>%; } body{ min-height: <span class="number">100</span>%; display: flex; <span class="comment">/* 设置flex */</span> flex-direction: column; <span class="comment">/* 方向为垂直方向 */</span> } .container{ flex: <span class="number">1</span>; <span class="comment">/* 内容占满所有剩余空间 */</span> } |
看到这个题目的时候干后端的别打我。在接触 Socket.io 之前曾经用 PHP + jQuery 写了一个低效的长轮询只有消息同步功能的小聊天室就已经耗尽心力,更不用说利用 PHP 的 Socket 接口写 WebSocket 的聊天室,那更是灾难。
刚才一口气说了一堆大家都困惑的术语,接下来等我解释一下。
React 简单介绍
先说 React 与 React Native
他们是真的亲戚,可不像 Java 和 Javascript 一样。
其实第一次看到 React 的语法我是拒绝的,因为这么丑的写法,你不能让我写我就写。
但当我发现 React Native 横空出世后,它学习一次到处运行的理念非常诱人。React Native 可以写出原生体验的 iOS/Android 应用?那不就多了一门装逼技能?所以我们调研小组试了一下,感觉 "Duang" 一下,很爽很舒服。写 React Native 需要两门基础技能:React 语法 和 iOS 基础知识。
很爽很舒服,索性就研究一下,算是入门。 了解之后发现,React 真是有另一番天地,值得学习。
接下来总结以下我对 React 的理解,分享给大家。
写在前面
在 2008 年的时候,John Resig 写了一 Class.js,使用的方式如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var Person = Class.extend({ init: function(isDancing){ this.dancing = isDancing; }, dance: function(){ return this.dancing; } }); var Ninja = Person.extend({ init: function(){ this._super( false ); }, dance: function(){ // Call the inherited version of dance() return this._super(); }, swingSword: function(){ return true; } }); |
|
1 |
<span style="font-family: sans-serif, Arial, Verdana, 'Trebuchet MS'; line-height: 1.6;">init为构造函数,通过this._super()访问</span><strong style="font-family: sans-serif, Arial, Verdana, 'Trebuchet MS'; line-height: 1.6;">父类同名方法</strong><span style="font-family: sans-serif, Arial, Verdana, 'Trebuchet MS'; line-height: 1.6;">。</span> |
这种看上去很酷很方便的继承方式,居然有一个致命的缺陷。那就是:
在敲下这个标题的时候,心里好虚。话说我一直不太喜欢发表这些看上去很假大空的文字,每个人的职业规划都是独有的,不具有太大的可复制性,把自己的经历放出去,容易误人子弟。只是最近很多师弟们(别问我为什么都是师弟,我想静静…… 也不要问我静静是谁!)问起这个,也就根据自己的经历发表一下对前端工程师的看法吧,“ 我说的都是错的”,仅供参考。另:本篇是纯文字,密集恐惧症换成勿入!
从我接收第一份前端需求开始,到现在也有五个年头了。自己也从一个愣头青变成一个快到而立之年的大叔,时间真的是哗啦哗啦的快。这五年里,其实可以分成三部分:1~2, 3~4, 5。
写在前面
AlloyRenderingEngine 是一款非常快速的渲染引擎,目前该项目已经合并至 https://github.com/AlloyTeam/AlloyGameEngine/ ,
属于 AlloyGameEngine 下的一个子项目,负责渲染。
因为游戏===复杂的 App,所有 AlloyGameEngine 不仅可以做游戏,也可以制作 App,比如: http://kmdjs.github.io/ppt-editor/
用 AlloyGameEngine 制作 App,如大炮轰蚊子。
目前非常流行自适应设计与响应式设计,而且经常让人混淆,自适应设计不应与自适应布局混为一谈,它们是完全不一样的概念。
在这先说明下这两者的异同:
自从移动终端飞速发展以来,各种各样的机型突飞猛进,很多网站的解决方法,是为不同的设备提供不同的网页,比如专门提供一个 mobile 版本,或者 iPhone/iPad 版本。这样做固然保证了效果,但是比较麻烦,同时要维护好几个版本,而且如果一个网站有多个 portal(入口),会大大增加架构设计的复杂度。
于是,很早就有人设想,能不能" 一次设计,普遍适用",让同一张网页自动适应不同大小的屏幕,根据屏幕宽度,自动调整布局(layout)?
2010 年,Ethan Marcotte 提出了" 自适应网页设计"(Responsive Web Design)这个名词,指可以自动识别屏幕宽度、并做出相应调整的网页设计。
最近在 Angular 项目中遇到关于 controller 内使用 $scope&this 暴露数据的问题,下面来分析一下:
“controller as” 是 Angular 在 1.2 版本后新增的语法,我将从引用方式,作用范围,对象对比三个方面做两者的比较:
引用方式:
1) $scope 只需要在注入中声明,后面就可以直接在附加数据对象:
controller:
|
1 2 3 |
function ACtrl($scope) { $scope.test = "一个例子"; //在$scope对象中加入test } |
html:
|
1 2 3 |
<div ng-controller="ACtrl"> {{test}} </div> |
2) this 则采用了 controller as(需要版本为 ng 1.2+) 写法:
作为
React的核心技术之一Virtual DOM,一直披着神秘的面纱。
实际上,Virtual DOM 包含:
- Javascript DOM 模型树(VTree),类似文档节点树(DOM)
- DOM 模型树转节点树方法(VTree -> DOM)
- 两个 DOM 模型树的差异算法(diff(VTree, VTree) -> PatchObject)
- 根据差异操作节点方法(patch(DOMNode, PatchObject) -> DOMNode)
接下来我们分别探讨这几个部分:
VTree
VTree 模型非常简单,基本结构如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ <span class="comment">// tag的名字</span> tagName: <span class="string">'p'</span>, <span class="comment">// 节点包含属性</span> properties: { style: { color: <span class="string">'#fff'</span> } }, <span class="comment">// 子节点</span> children: [], <span class="comment">// 该节点的唯一表示,后面会讲有啥用</span> key: <span class="number">1</span> } |
所以我们很容易写一个方法来创建这种树状结构,例如 React 是这么创建的:
|
1 2 3 4 5 6 7 8 |
<span class="comment">// 创建一个div</span> react.createElement(<span class="string">'div'</span>, <span class="keyword">null</span>, [ <span class="comment">// 子节点img</span> react.createElement(<span class="string">'img'</span>, { src: <span class="string">"avatar.png"</span>, <span class="keyword">class</span>: <span class="string">"profile"</span> }), <span class="comment">// 子节点h3</span> react.createElement(<span class="string">'h3'</span>, <span class="keyword">null</span>, [[user.firstName, user.lastName].join(<span class="string">' '</span>)]) ]); |
VTree -> DOM
这方法也不太难,我们实现一个简单的:
|
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 |
<span class="keyword">function</span> create(vds, <span class="keyword">parent</span>) { <span class="comment">// 首先看看是不是数组,如果不是数组统一成数组</span> !<span class="keyword">Array</span>.isArray(vds) && (vds = [vds]); <span class="comment">// 如果没有父元素则创建个fragment来当父元素</span> <span class="keyword">parent</span> = <span class="keyword">parent</span> || document.createDocumentFragment(); <span class="keyword">var</span> node; <span class="comment">// 遍历所有VNode</span> vds.<span class="keyword">forEach</span>(<span class="keyword">function</span> (vd) { <span class="comment">// 如果VNode是文字节点</span> <span class="keyword">if</span> (isText(vd)) { <span class="comment">// 创建文字节点</span> node = document.createTextNode(vd.text); <span class="comment">// 否则是元素</span> } <span class="keyword">else</span> { <span class="comment">// 创建元素</span> node = document.createElement(vd.tag); } <span class="comment">// 将元素塞入父容器</span> <span class="keyword">parent</span>.appendChild(node); <span class="comment">// 看看有没有子VNode,有孩子则处理孩子VNode</span> vd.children && vd.children.length && create(vd.children, node); <span class="comment">// 看看有没有属性,有则处理属性</span> vd.properties && setProps({ style: {} }, vd.properties, node); }); <span class="keyword">return</span> <span class="keyword">parent</span>; } |
diff(VTree, VTree) -> PatchObject
差异算法是 Virtual DOM 的核心,实际上该差异算法是个取巧算法(当然你不能指望用 O(n^3) 的复杂度来解决两个树的差异问题吧),不过能解决 Web 的大部分问题。
那么 React 是如何取巧的呢?
- 分层对比
如图,React 仅仅对同一层的节点尝试匹配,因为实际上,Web 中不太可能把一个 Component 在不同层中移动。
- 基于 key 来匹配
还记得之前在 VTree 中的属性有一个叫 key 的东东么?这个是一个 VNode 的唯一识别,用于对两个不同的 VTree 中的 VNode 做匹配的。
这也很好理解,因为我们经常会在 Web 遇到拥有唯一识别的 Component(例如课程卡片、用户卡片等等)的不同排列问题。
- 基于自定义元素做优化
React 提供自定义元素,所以匹配更加简单。
patch(DOMNode, PatchObject) -> DOMNode
由于 diff 操作已经找出两个 VTree 不同的地方,只要根据计算出来的结果,我们就可以对 DOM 的进行差异渲染。
扩展阅读
具体可参考下面两份代码实现:
- @Matt-Esch 实现的:virtual-dom
- 我们自己做的简版实现,用于 Mobile 页面渲染的:qvd

HTML5 梦工场
推荐使用 Coding.net