最近关于Service Workers的研究与讨论日益增多,今天就给我大家来梳理一些资源,让大家一睹为快!!

1.啥是Service workers?

我们知道原生App拥有的富离线体验,如定时静默更新,消息通知推送等功能,曾经是是web应用“羡慕嫉妒恨”的功能。有了Service Worker,Web APP也可以拥有这些功能。

简单来说,Service Workers赋予Web APP以非常好的离线体验,赋予开发者离线数据的管理能力。

欲知详情请大家移步下列资源获取更多信息:

  1. html5rocksservice workers introduction
  2. w3ctech对html5rocks introduction的翻译 Service Worker 入门
  3. W3C吴小倩的报告游戏规则改变者 Service Worker
  4. Service Workers让Web应用感觉更像是原生应用

2.Service Workers准备好了吗?

###2.1 兼容性
对于任何一个新的功能,兼容性都是不容忽视的,对吧,各位前端er。
来看下Caniuse的数据(截止2015/11/16)。
图片描述

###2.2 特性支持与polyfill
下面是来自于isServiceWorkerReady?的数据。
图片描述

3. 如何使用Service Workers?

来具体了解Service Wokers的使用方式,API文档、使用案例、样例APP。

  1. 官方文档
  2. MDN的Service Worker API
  3. MDN的Using Service Workers
  4. ServiceWorker: Revolution of the Web Platform
  5. My first Service Worker
  6. CSS-tricks的Making a Simple Site Work Offline with ServiceWorker
  7. ponyfoo.com的Making a Progressive App with ServiceWorker
  8. 一些案例ServiceWorkersDemos
  9. An Offline Experience with Service Workers

4.声明

爱前端,乐分享。FedFun希望与您共同进步。
欢迎任何形式的转载,烦请注明装载,保留本段文字。
独立博客http://whqet.github.io
新浪微博http://weibo.com/FedFun
极客头条http://geek.csdn.net/user/publishlist/whqet

今天来一起了解一个实现SVG路径描边绘制与动画的轻量级类库segment,我们从轻松上手、使用详解、资源和案例、源码解读等几个方面进行介绍。
图片描述

1. 轻松上手

html方面添加segment,定义path。

1
2
3
4
5
<script src="/dist/segment.min.js"></script>

<svg>
<path id="my-path" ...>
</svg>

JS方面利用path实例化一个segment,然后就可以使用segment的draw方法了。

1
2
3
4
var myPath = document.getElementById("my-path"),
segment = new Segment(myPath);

segment.draw("25%", "75% - 10", 1);

2. 使用详解

2.1 构造函数

Segment构造函数可以接收三个参数。

1
var segElement=new Segment(path,begin,end);
  • path: 需要绘制的路径(DOM元素)。
  • begin: 路径开始绘制的位置,可选参数,默认值为0。
  • end: 路径结束绘制的位置,可选参数,默认值为100%。

2.2 draw方法

draw方法是segment的核心方法,可以接受四个参数。

1
segElement.draw(begin, end, duration, options);
  • begin: 路径开始绘制位置,默认值为0。参数类型为string。
    • 数字
    • 百分比
    • 百分比+数字
    • 百分比-数字
  • end: 路径结束绘制的位置,默认值为100%,参数类型为string。输入写法同begin。
  • duration: 绘制持续时间,默认值为0。
  • options: 绘制参数,默认值为null,参数类型为object类型。具体参数如下。
    • delay: 延迟时间,默认值为0,单位为s。
    • easing: 绘制动画的缓动类型,默认值为linear。
    • callback: 回调函数,默认值为null。

draw方法具体案例如下。

1
2
3
4
5
6
7
8
9
function cubicIn(t) {
return t * t * t;
}

function done() {
alert("Done!");
}

segment.draw("25%", "75% - 10", 1, {delay: 0.5, easing: cubicIn, callback: done});

3. 资源和案例

  1. CodropAnimating an SVG Menu Icon with Segment
  2. 官方案例
  3. 官方教程Animating SVG path segments

4. 源码解读

通过源码阅读,学习类库的开发,svg动画的具体实现。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* segment - A little JavaScript class (without dependencies) to draw and animate SVG path strokes
* @version v0.0.4
* @link https://github.com/lmgonzalves/segment
* @license MIT
*/


function Segment(path, begin, end) {
this.path = path;
this.length = path.getTotalLength();
this.path.style.strokeDashoffset = this.length * 2;
this.begin = typeof begin !== 'undefined' ? this.valueOf(begin) : 0;
this.end = typeof end !== 'undefined' ? this.valueOf(end) : this.length;
this.timer = null;
this.draw(this.begin, this.end);
}

Segment.prototype = {
draw : function(begin, end, duration, options){
if(duration){
var delay = options && options.hasOwnProperty('delay') ? parseFloat(options.delay) * 1000 : 0,
easing = options && options.hasOwnProperty('easing') ? options.easing : null,
callback = options && options.hasOwnProperty('callback') ? options.callback : null,
that = this;

this.stop();
if(delay) {
delete options.delay;
this.timer = setTimeout(function () {
that.draw(begin, end, duration, options);
}, delay);
return this.timer;
}

var startTime = new Date(),
rate = 1000/60,
initBegin = this.begin,
initEnd = this.end,
finalBegin = this.valueOf(begin),
finalEnd = this.valueOf(end);

(function calc(){
var now = new Date(),
elapsed = (now-startTime)/1000,
time = (elapsed/parseFloat(duration)),
t = time;

if(typeof easing === 'function') {
t = easing(t);
}

if(time > 1){
that.stop();
t = 1;
}else{
that.timer = setTimeout(calc, rate);
}

that.begin = initBegin + (finalBegin - initBegin) * t;
that.end = initEnd + (finalEnd - initEnd) * t;

if(that.begin < 0) {
that.begin = 0;
}

if(that.end > that.length) {
that.end = that.length;
}

if(that.begin < that.end) {
that.draw(that.begin, that.end);
}else{
that.draw(that.begin + (that.end - that.begin), that.end - (that.end - that.begin));
}

if(time > 1 && typeof callback === 'function'){
return callback.call(that.context);
}
})();
}else{
this.path.style.strokeDasharray = this.strokeDasharray(begin, end);
}
},

strokeDasharray : function(begin, end){
this.begin = this.valueOf(begin);
this.end = this.valueOf(end);
return [this.length, this.length + this.begin, this.end - this.begin].join(' ');
},

valueOf: function(input){
var val = parseFloat(input);
if(typeof input === 'string' || input instanceof String){
if(~input.indexOf('%')){
var arr;
if(~input.indexOf('+')){
arr = input.split('+');
val = this.percent(arr[0]) + parseFloat(arr[1]);
}else if(~input.indexOf('-')){
arr = input.split('-');
val = this.percent(arr[0]) - parseFloat(arr[1]);
}else{
val = this.percent(input);
}
}
}
return val;
},

stop : function(){
clearTimeout(this.timer);
this.timer = null;
},

percent : function(value){
return parseFloat(value) / 100 * this.length;
}
};

5. 声明

本文首发于极客头条。爱前端,乐分享。FedFun希望与您共同进步。
欢迎任何形式的转载,烦请注明装载,保留本段文字。
独立博客http://whqet.github.io
新浪微博http://weibo.com/FedFun
极客头条http://geek.csdn.net/user/publishlist/whqet

1. 引言

resize属性是CSS3 UI中的一个属性,允许用户调整元素的尺寸。今天通过一个图像对比案例来简要学习下。
您可以到Codepen–预览案例–,–玩弄代码–。
建议阅读时间6分钟。

2. 详览

resize是CSS3 UI的一部分,目前CSS3 UI处于CR(Candidate Recommendation,候选标准)阶段,box-sizing属性,outline属性,text-overflow属性和cursor属性都属于该CSS3 UI的定义范围。

##2.1 兼容性
来自caniuse的兼容性表格如下,可以看出Firefox、Chrome、Safari、Opera等现代浏览器支持情况良好,遗憾的是IE和Edge不支持该属性。
resize属性兼容表

##2.2 语法
resize属性主要用来控制元素是否以及如何支持用户调整尺寸。

属性名 属性值
属性名Name resize,允许用户控制元素大小
属性值Value none 或 both 或 horizontal 或 vertical
默认值Initial none
适用范围Applies to 设置过overflow属性且值不是visible的元素
继承性Inherited no
百分比Percentages N/A
媒体类型Media visual
计算值Computed value 指定值specified value
动画性Animatable 不支持

在可以接受的值中,不同的属性值有不同的含义
| 属性值| 属性值含义|
|:——–|:——–|
|none|不允许用户控制元素大小|
|both|允许用户控制元素的宽和高 |
|horizontal| 允许用户控制元素的宽 |
|vertical| 允许用户控制元素的高 |

注意:目前resize属性不适用于生成元素(伪对象生成元素)。

##2.3 表现
在不同的浏览下,设置过resize属性的元素的表现稍有不同。在firefox下表现如左图所示,在chrome、opera、safari下表现如右图所示。
firefox 这里写图片描述 其他浏览器这里写图片描述

3. 案例

接下来通过一个图片对比的案例来演示resize属性的使用,案例效果如下。
这里写图片描述

在本案例中,我们用figure和div#divisor分别设置背景图像,显示两幅图像,然后通过调整div#divisor元素的宽度实现图像对比效果。

html代码如下,

1
2
3
4
5
<div id="comparison">
<figure>
<div id="divisor"></div>
</figure>
</div>

css代码

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
37
38
39
40
41
42
43
44
div#comparison {
width: 60vw;
height: 60vw;
max-width: 600px;
max-height: 600px;
overflow: hidden;
}


div#comparison figure {
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/photoshop-face-before.jpg);
background-size: cover;
position: relative;
font-size: 0;
width: 100%;
height: 100%;
margin: 0;
}


div#comparison figure #divisor {
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/photoshop-face-after.jpg);
background-size: cover;
position: absolute;
min-width: 10%;
max-width: 100%;
box-shadow: 0 5px 10px -2px rgba(0, 0, 0, 1);
overflow: hidden;
bottom: 0;
height: 100%;
/*设置resize属性,使之可以横向改变大小*/
resize: horizontal;
}

/*覆盖resize元素的默认样式*/
div#comparison figure #divisor::after {
content: "";
width: 20px;
height: 30px;
position: absolute;
right: 1px;
bottom: 1px;
background: linear-gradient(-60deg, white 50%, transparent 0);
cursor: ew-resize;
-webkit-filter: drop-shadow(0 0 2px black);
filter: drop-shadow(0 0 2px black);
}

4. 声明

爱前端乐分享的FedFun,csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接http://blog.csdn.net/whqet/article/details/49736187
独立博客http://whqet.github.io
新浪微博http://weibo.com/FedFun
极客头条http://geek.csdn.net/user/publishlist/whqet

1. 引言

原文:bitsofcodeHOW POSITIONING CSS PROPERTIES INTERACT
译者:爱前端,乐分享的FedFun,前端痴王海庆的博客。
译言:来看下CSS标布局情况下,定位相关属性之间的相互作用,意译为主,不当之处敬请指正。
阅读建议5分钟。

2. 正文

在定位元素时,我们经常用到四个属性displaypositionfloat和偏移属性top right bottom left等。但不是在每个元素上都可以同时应用这四个属性,一些特殊的值组合会覆盖其他属性的应用,这些组合有:

  • display: none
  • position: absoluteposition: fixed
  • float: leftfloat: right
  • position: static

接下来,我们就一起来研究这些组合之间如何相互作用。

2.1 DISPLAY: NONE

display设置成none时,其它定位属性统统失效,因为没有产生盒模型(the box model)。

1
2
3
4
5
6
7
8
.foo {
display: none;

/* None of these apply,以下这些将不会应用 */
position: absolute;
float: left;
top: 10px;
}

2.2 POSITION: ABSOLUTE (OR FIXED)

如果将position属性设置为absolutefixed时,将会产生以下作用:

Float

float属性设置的任何值都会被覆盖,float属性的计算值(the computed value)自动设置为none

1
2
3
4
.foo {
position: absolute;
float: left; /* 被忽略, 计算值为none */
}

DISPLAY

随着display属性值的不同,计算值可能会被覆盖,如下表所示。
| 指定值 | 计算值 |
| ————- |:————-:|
| inline, inline-block, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption | block |
| inline-table | table |
| 其他值 | 跟指定值相同 |

下面的代码中,.foo.bar表现上没有区别。

1
2
3
4
5
6
7
8
.foo {
position: fixed;
display: inline-block; /* ignored, computed value is block */
}

.bar {
position: fixed;
display: block;
}

2.3 FLOAT: LEFT (OR RIGHT)

除了上面两种情况,当我们把float属性设置为leftright时,相互作用如下:

DISPLAY

跟上面绝对定位、固定定位类似,元素浮动后display属性变换如上表所示。
下面代码中,.foo.bar的表现效果也一样。

1
2
3
4
5
6
7
8
.foo {
float: left;
display: inline-block; /* ignored, computed value is block */
}

.bar {
float: left;
display: block;
}

2.4 POSITION: STATIC

除了上面的变化,当position属性值为static时,相互作用如下:

偏移值

当元素静态定位时,偏移属性将失效,如下代码所示。

1
2
3
4
.foo {
position: static;
top: 50px; /* does not apply */
}

3. 声明

爱前端乐分享的FedFun,csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接http://blog.csdn.net/whqet/article/details/49464099
独立博客http://whqet.github.io
新浪微博http://weibo.com/FedFun
极客头条http://geek.csdn.net/user/publishlist/whqet

1. 前言

AngularJS是为了克服HTML在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了,所以AngularJS做了一些工作来来解决静态网页技术在构建动态应用上的不足。

AngularJS的初衷是为了简化web APP开发,精髓是简单。但是国内外有很多AngularJS的教程,都着重讲AngularJS的强大之处,从而增加了AngularJS学习的难度,本教程试图用通俗的语言讲解最为基础最为实用的内容,简化学习进程、降低学习难度是本教程的初衷。

本系列教程以翻译Chris SmithAngualr Basics为梗概,融合博主自己的理解,为大家提供一个简单明了的学习教程。本文为系列教程第2篇引言,翻译自Introduction

  1. 引言-Introduction
  2. 基础-Basics
  3. 控制器-Controllers
  4. 作用域-Scopes
  5. 集合-Collections
  6. 模块-Modules
  7. 依赖注入-Dependency Injection
  8. 服务-Services
  9. 过滤器-Filters
  10. 指令-Directives
  11. 指令作用域-Directive Scopes
  12. 路由-Routing
  13. 通信-HTTP
  14. 结论

2.正文

这是一本袖珍书,灵感来自于其他免费、简短、友好的编程书,例如Alex MacCaw的《The Little Book on CoffeeScript》。我写这本书的目的是像我学习AugularJS那样介绍它,关注典型环境的快速web开发中如何应用AngularJS。依据帕累托原则Pareto principle), 优先讲简单、实用的功能,课程结束之后,您可能只了解AngularJS的一部分,却可以利用该框架轻松创建强大的前端应用。本书是一个动态网站,所有案例使用最新版的AngularJS(Angular 1.3.14),如果您倾向于交互学习,那么修改代码指令,您可以实时的看到运行效果,鼓励大家进行探究性、实验性学习。

如果您想了解更多我为什么写这本书,了解AngularJS的历史,AngularJS是否适合您的项目,请继续阅读本文,如果您非常确定您为什么阅读本文,急于学习AngularJS请移步系列教程第03篇基础。

##2.1 AngularJS 难或易?
我有近十年的web MVC的工作经验,从 Struts 到Spring MVC到Ruby on Rails到Backbone,我甚至还写了一本Backbone and CoffeeScript方面的书,因此我自认为学习AngularJS起来肯定非常简单。但是,当我沉浸在API和文档中时,我发现各种各样不熟悉的名词和术语(transclusion, directive, and isolate scope)阻碍了学习进程,当我阅读官方文档和教程时,所谓的简单易学好像没有出现,反而是一头雾水,比如说下面这段折磨人的文字。

The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope. In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope.

现在官方文档里面已经没有这段文字了,通过AngularJS官方团队的不懈努力,官方文档的可读性进一步增强了很多。但是,当我第一次阅读时,这段文字让我感觉非常无知,好像走进了一个新的领域,我感觉到AngularJS是一个复杂的技术(没有开玩笑), AngularJS的各种细节在广泛的被讨论,难以调试、怪癖、陷阱等。

像任何自尊自爱的程序猿一样,我撸起袖子奋战到底,慢慢地我熟悉了那些名词和术语,以为学习必然有点陡。直到有一天,我看到AngularJS的创始人Miško Hevery的视频采访,根据Hevery的解释,我发现了一个简单而又重要的事实:

使用简单是AngularJS的初衷

Hevery解释道,当他构思AngularJS时,把它作为非编程人员仅仅使用预定义的标签就能创建动态web应用的工具。我才意识到,我卷入了太多的AngularJS的细节而没有获得相应的收益。Angular项目及相关社区在相互协作方面投入太多精力,增加了Angular的复杂性和学习的难度,我们需要探索更好的使用方式以趋近于Angular的开发初衷,去除大量的精巧设计的控制,不考虑微弱的内部安全隐患,直接向前。

对我来说这个方法是正确的,尽管Angular不是我唯一的web开发语言,但绝对是最闪耀的那个。

2.2 您需要Angular吗?

虽然类似于Angular的客户端js工具让创建单页面应用变得如此简单,但是不少web项目仍然使用传统的架构,服务端渲染、jQuery实现交互。坦率的讲,您需要考虑您的项目是否需要在客户端管理数据、渲染html,您是否有足够的理由开始尝试一项新的技术。

当然,Angular是一个明显的、固执己见的选择(Angular is a broad, opinionated solution)。虽然通常被认作一个库,但是Angular内置的对模块化、依赖注入的支持,将会改变您的项目管理方式。如果你想找一个Angular的替代方案,或许更加成熟的,或许最佳的,但是这些都不可能完全替代Angular。除非您的项目肯定能达到Google工程师认为的经典的水准,你可能不需要达到Angular核心团队认定的组织支持的水平。依赖注入尽管可以用在单元测试方面,但还是太过复杂,大家可以到Dependency Injection 看看实在的案例。

当您需要引入非Angular代码和Angular的数据绑定和渲染机制协同工作的话,将会产生另一个问题,您需要非常深入这些神秘的细节。相对来说,Backbone基于jQuery,更加简单、更加易于理解,如果您的项目深度依赖jQuery,利用Backbone实现渐进增强也是一个不错的选择。

另外,Angular在UI组件和模型对象之间的双向绑定,也会增加应用的复杂性。Facebook的开发者分享了双向数据绑定中的挫败感:

我们发现双向数据绑定容易导致级联更新: 一个对象的改变导致另一个对象的改变,甚至更多对象的改变。随着应用的增长,由用户行为导致的级联更新将会很难预测。

相对于Angular来说,尽管Facebook的 React不重在关注渲染,但是基于React的客户端技术也值得一试。

2.3 使用Angular的理由

Angular可能是当今最流行的Javascript MV*解决方案,github得到了36722个star,当然阅读本文时可能更多。它迅速从同类的解决方案中脱颖而出,成为顶级解决方案,大家可以到TodoMVC project比较诸多MV*方案。让我们来看看Angular成功的原因。

  • 快速成型(Immediate productivity)
    如果您的项目需要用户界面实现数据的增删改查操作,Angular可以非常漂亮地兑现快速成型的承诺。仅仅需要在普通的html添加几个属性,使用少量的几行javascript代码你就可以实现普通类库需要大量技能、大量努力才能实现的功能。
  • 熟悉度
    Angular包含开发人员熟知的原生JS和几乎普通的HTML,用几乎这个词主要是因为Angular引入了一些新增的html元素,属性和一些可能看起来恐怖的行内代码。相对于其他模板系统,Angular已经非常接近html了,大部分开发人员都能够轻松理解。
  • 适应性
    Angular可以很好支持当前的UI核心的JS类库,如果想使用类似于Bootstrap这样的流行类库的话,您可以有效利用AngularUI这样的第三方项目实现简单整合。所以,无论你想为传统文档中心网站增加交互性,还是开发一个炫彩的单页面应用,Angular都可以是一个不错的选择。
  • 未来标准
    尽管我不能确定Angualr能达到什么高度,Angular母公司Google会如何创造未来,有一点非常明确,Angular的使用方式非常接近目前提出的标准 Web Components,另外,Angular接近于下个版本Javascript的特征(例如Object.observe)它的基础原则将会被维持而不会弃用。
  • 社区
    当然,一个非常重要的原因是它非常流行,应用于大量的超负荷网站中,Google的定力支持,大量的插件和学习资源。当然大部分人的正确选择不一定是每个人的正确选择,你还需要谨慎考虑Angular是否真的适合您。

2.4 关于本书

很多年前当我在My MacBook Air上阅读一本JS编程书时,已经有了脚本书( ScriptyBooks)的点子。需要运行书中的一个案例时,我们从网站中下载案例,着急于如何打开它,从大量的文件中找到需要的文件,费劲九牛二虎之力找到正确的文件,打开它,修改它,但是很可能你还是不能运行,你可能需要安装支持环境。

为什么我们在讲解一个前端技术时,还需要耗费诸多努力才能运行一个案例,如果能够可以在书中展示代码,允许您进行修改,并且实时展示代码呈现结果,那就很美妙了。

本书采用这样的方式。所有代码均可以动态修改,并实时展示代码运行结果。如下所示。

1
<strong>The lucky number {{3 + 5}}.</strong>

The lucky number 8.

我利用 CodeMirror 和Angular实现动态交互功能,如果还是angular菜鸟,不妨修改下上面的代码,看看会发生什么(博客支持技术有限,本教程没有提供动态修改代码功能,望见谅。请阅读原教程代码)。

2.5 接下来

接下来,准备讲解客户端模板(client-side templating)和双向绑定(two-way bindings),向您展示Angular的基础。尽管大部分代码非常简单,一眼看过去就可以理解,但相信哪怕有经验的Angular开发人员也可以有所收获。

3.声明

前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接,http://blog.csdn.net/whqet/article/details/44596577
欢迎大家访问独立博客http://whqet.github.io

1. 前言

AngularJS是为了克服HTML在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了,所以AngularJS做了一些工作来来解决静态网页技术在构建动态应用上的不足。

AngularJS的初衷是为了简化web APP开发,精髓是简单。但是国内外有很多AngularJS的教程,都着重讲AngularJS的强大之处,从而增加了AngularJS学习的难度,本教程试图用通俗的语言讲解最为基础最为实用的内容,简化学习进程、降低学习难度是本教程的初衷。

欢迎大家批评指正

2. AngularJS?

AngularJS主要用于构建单页面Web应用,同其他历史悠久的Web技术(HTML、CSS和JavaScript)配合使用,使构建交互式的现代Web应用变得更加简单。

AngularJS提供了开发者在现代Web应用中经常要用到的一系列高级功能,例如解耦应用逻辑、数据模型和视图,Ajax服务,双向绑定、依赖注入、测试等功能,通过原生的Model-View-Controller(MVC,模型视图控制器)功能增强了HTML,从而降低构建复杂应用的难度。

3. 系列教程目录

  1. 引言-Introduction
  2. 基础-Basics
  3. 控制器-Controllers
  4. 作用域-Scopes
  5. 集合-Collections
  6. 模块-Modules
  7. 依赖注入-Dependency Injection
  8. 服务-Services
  9. 过滤器-Filters
  10. 指令-Directives
  11. 指令作用域-Directive Scopes
  12. 路由-Routing
  13. 通信-HTTP
  14. 结论

4. 学习资源

  1. ANGULAR BASICS
  2. 官方网站–墙外,大家懂的,可以访问官方github
  3. angularjs中文社区
  4. AngularJS Nice Things–爱好者聚集地
  5. AngularJS中文网
  6. AngularJS手册中文手册
  7. 七步从Angular.JS菜鸟到专家

    5.声明

    前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
    欢迎任何形式的转载,烦请注明装载,保留本段文字。
    本文原文链接,http://blog.csdn.net/whqet/article/details/44586849
    欢迎大家访问独立博客http://whqet.github.io

0.前言

HTML5 Page Visibility API是一个非常有用的特性,当页面对用户不可见时,暂停播放页面中的视频、动画、声音、以及其他耗费内存的操作,等用户回来时,再继续这些操作。当然,最好提醒下用户可以继续回到本页面上来,本文研究利用改变页面tab(title)实现提醒。

[toc]

效果预览

代码解析

实现过程

实现过程非常简单,侦听visibilitychange事件,然后改变页面标题。

1
2
3
4
5
var title = document.title,
newTitle = "记得回来哟 " + title;
document.addEventListener("visibilitychange", function() {
document.title = ((document.hidden) ? newTitle : title);
});

兼容性分析

来自caniuse的数据,Page Visibility在现代浏览器中兼容性不错,如下图所示。
page visibility兼容表

学习资源

  1. Page Visibility参考手册
  2. Page Visibility兼容性表格
  3. Creating Well-Behaved Sites With The Page Visibility API
  4. Page Visibility(页面可见性) API介绍、微拓展
  5. Page Visibility API
  6. Using the Page Visibility API

#声明
前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接,http://blog.csdn.net/whqet/article/details/44511735
欢迎大家访问独立博客http://whqet.github.io

前端开发规范系列文章之Javascript Tips and Tricks,本意是写成常用代码收集、常用技巧整理的文章,感觉“常用代码大全”太土、“实用代码整理”有失偏颇,“提示与技巧”不够稳重,所以使用常用的英语说法,相信广大程序员都懂得。

##妙味
Javascript美妙之处,需要我们静静体会,慢慢吸收,然后让代码在您指下曼舞。整理的这些代码我们称之为妙味,请大家细品。
博主会不断更新本文,方便大家阅读起见,我们采用倒序更新的方式,把最新更新的放最上方

事件处理

我们知道IE和标准浏览器在事件处理方面有很大不同,所以我们在使用的时候需要首先进行统一化处理,统一处理时有两种方式,shim和polyfill。
shim将新的api引入新的环境中,例如下面的代码使用addEvent和removeEvent来添加删除事件。

1
// Shim for DOM Events for IE7-
// http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
// Use addEvent(object, event, handler) instead of object.addEventListener(event, handler)
window.addEvent = function(obj, type, fn) {
	if (obj.addEventListener) {
		obj.addEventListener(type, fn, false);
	} else if (obj.attachEvent) {
		obj["e" + type + fn] = fn;
		obj[type + fn] = function() {
			var e = window.event;
			e.currentTarget = obj;
			e.preventDefault = function() {
				e.returnValue = false;
			};
			e.stopPropagation = function() {
				e.cancelBubble = true;
			};
			e.target = e.srcElement;
			e.timeStamp = Date.now();
			obj["e" + type + fn].call(this, e);
		};
		obj.attachEvent("on" + type, obj[type + fn]);
	}
};

window.removeEvent = function(obj, type, fn) {
	if (obj.removeEventListener) {
		obj.removeEventListener(type, fn, false);
	} else if (obj.detachEvent) {
		obj.detachEvent("on" + type, obj[type + fn]);
		obj[type + fn] = null;
		obj["e" + type + fn] = null;
	}
};

polyfill让旧浏览器支持新功能,使用方式和标准浏览器一样,例如下面的EventListener polyfill在IE9-浏览器上实现addEventListener、removeEventListener、dispatchEvent和customEvent等。

1
//
this.Element && Element.prototype.attachEvent && !Element.prototype.addEventListener && (function () {
	function addToPrototype(name, method) {
		Window.prototype[name] = HTMLDocument.prototype[name] = Element.prototype[name] = method;
	}
	// add
	addToPrototype("addEventListener", function (type, listener) {
		var
		target = this,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		// if no events exist, attach the listener
		if (!typeListeners.length) {
			target.attachEvent("on" + type, typeListeners.event = function (event) {
				var documentElement = target.document && target.document.documentElement || target.documentElement || { scrollLeft: 0, scrollTop: 0 };

				// polyfill w3c properties and methods
				event.currentTarget = target;
				event.pageX = event.clientX + documentElement.scrollLeft;
				event.pageY = event.clientY + documentElement.scrollTop;
				event.preventDefault = function () { event.returnValue = false };
				event.relatedTarget = event.fromElement || null;
				event.stopImmediatePropagation = function () { immediatePropagation = false; event.cancelBubble = true };
				event.stopPropagation = function () { event.cancelBubble = true };
				event.target = event.srcElement || target;
				event.timeStamp = +new Date;

				// create an cached list of the master events list (to protect this loop from breaking when an event is removed)
				for (var i = 0, typeListenersCache = [].concat(typeListeners), typeListenerCache, immediatePropagation = true; immediatePropagation && (typeListenerCache = typeListenersCache[i]); ++i) {
					// check to see if the cached event still exists in the master events list
					for (var ii = 0, typeListener; typeListener = typeListeners[ii]; ++ii) {
						if (typeListener == typeListenerCache) {
							typeListener.call(target, event);

							break;
						}
					}
				}
			});
		}

		// add the event to the master event list
		typeListeners.push(listener);
	});

	// remove
	addToPrototype("removeEventListener", function (type, listener) {
		var
		target = this,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		// remove the newest matching event from the master event list
		for (var i = typeListeners.length - 1, typeListener; typeListener = typeListeners[i]; --i) {
			if (typeListener == listener) {
				typeListeners.splice(i, 1);

				break;
			}
		}

		// if no events exist, detach the listener
		if (!typeListeners.length && typeListeners.event) {
			target.detachEvent("on" + type, typeListeners.event);
		}
	});

	// dispatch
	addToPrototype("dispatchEvent", function (eventObject) {
		var
		target = this,
		type = eventObject.type,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		try {
			return target.fireEvent("on" + type, eventObject);
		} catch (error) {
			if (typeListeners.event) {
				typeListeners.event(eventObject);
			}

			return;
		}
	});

	// CustomEvent
	Object.defineProperty(Window.prototype, "CustomEvent", {
		get: function () {
			var self = this;

			return function CustomEvent(type, eventInitDict) {
				var event = self.document.createEventObject(), key;

				event.type = type;
				for (key in eventInitDict) {
					if (key == 'cancelable'){
						event.returnValue = !eventInitDict.cancelable;
					} else if (key == 'bubbles'){
						event.cancelBubble = !eventInitDict.bubbles;
					} else if (key == 'detail'){
						event.detail = eventInitDict.detail;
					}
				}
				return event;
			};
		}
	});

	// ready
	function ready(event) {
		if (ready.interval && document.body) {
			ready.interval = clearInterval(ready.interval);

			document.dispatchEvent(new CustomEvent("DOMContentLoaded"));
		}
	}

	ready.interval = setInterval(ready, 1);

	window.addEventListener("load", ready);
})();

!this.CustomEvent && (function() {
	// CustomEvent for browsers which don't natively support the Constructor method
	window.CustomEvent = function CustomEvent(type, eventInitDict) {
		var event;
		eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined};

		try {
			event = document.createEvent('CustomEvent');
			event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail);
		} catch (error) {
			// for browsers which don't support CustomEvent at all, we use a regular event instead
			event = document.createEvent('Event');
			event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
			event.detail = eventInitDict.detail;
		}

		return event;
	};
})();

置乱数组

Javascript中置乱数组的一种方式,sort方法可以接受一个 函数为参数,当函数返回值为1的时候就交换两个数组项的顺序,否则就不交换。如下代码所示。

1
yourArray.sort(function() { return 0.5 - Math.random() });

但是这种方式执行效率比较低,我还需探索更为高效的置乱方式。

1
2
3
4
5
/* 添加原型方法的方式 */
Array.prototype.shuffle = Array.prototype.shuffle || function(){
for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
return this;
};

这种方式已经比较高效,但是可控性不强,不能指定随机方法,我们又进行了改进。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 带参数的置乱数组原型方法
* copy默认值为false,copy为true时 ,返回置乱的数组,不影响数组本身
* rng为置乱函数,默认为Math.random
* */

Array.prototype.shuffle = Array.prototype.shuffle || function(copy, rng){
var that = this, //保证原数组不受影响
i = this.length, //循环指针,初始值为数组长度
r, //随机数
t; //交换时的临时变量

copy = copy || false; //参数默认值
rng = rng || Math.random;
copy&&(that=this.slice()); //copy为true时,生成新的数组that
while(i){
r = Math.floor(rng() * i); //生成随机数
t=that[--i]; //交换数值
that[i]=that[r];
that[r]=t;
}
return that; //返回置乱后数组
}

删除字符串中的空格(Trim String)

es5中具有删除空格的原生方法String.trimLeft()、 String.trimRight()和 String.trim(),这些方法在标准浏览器中兼容性良好,trim方法在ie 9+兼容良好,trimLeft和trimRight在IE中不兼容,不兼容的浏览器我们需要使用polyfill。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* e5中trim方法的polyfill */
String.prototype.trim = String.prototype.trim || function () {
return this.replace(/^\s+|\s+$/g, "");
};
String.prototype.trimLeft = String.prototype.trimLeft || function () {
return this.replace(/^\s+/, "");
};
String.prototype.trimRight = String.prototype.trimRight || function () {
return this.replace(/\s+$/, "");
};
String.prototype.trimFull = String.prototype.trimFull || function () {
return this.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g, "").replace(/\s+/g, " ");
};

//使用
" hello world ".trimRight(); //" hello world"
" hello world ".trimLeft(); //"hello world "
" hello world ".trim(); //"hello world"
" hello world ".trimFull(); //"hello world"

检测html标签属性

有的时候我们想知道某个元素是否具备某属性,我们可以使用该函数检测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//检测属性
function elementSupportsAttribute(element, attribute) {
var test = document.createElement(element);
if (attribute in test) {
return true;
} else {
return false;
}
}
//简化版检测属性
function elementSupportsAttribute(element, attribute) {
return !!(attribute in document.createElement(element));
};
//使用,检测textarea元素的placeholder属性
elementSupportsAttribute("textarea", "placeholder")?alert("ok"):alert("not");

尽量使用“===”

在javascript中,==和===都表示相等,但是==会在需要的时候进行类型转换,而===则不会进行类型转换,会比较数据类型和数据数值,比==执行速度快。

1
[10] === 10    // is false
[10] ==  10    // is true
'10' === 10    // is false
'10' ==  10    // is true
 []  === 0     // is false
 []  ==  0     // is true
 ''  === false // is false 
 ''  ==  false // is true but true == "a" is false

悬挂(Hoisting)

首先来看段代码,大家先猜下运行结果。

1
2
3
4
5
6
var a = 1;
function go(){
console.log(a);
var a = 2;
}
go();

运行结果为: undefined,你猜对了吗?我们接下来看看为啥?
悬挂,也即所有函数体内的变量声明(注意,仅仅是声明)都将被提到函数体开头进行。所以上面这段代码实际上是这样执行的。

1
2
3
4
5
6
7
8
var a;
a = 1;
function go(){
var a;
console.log(a);
a = 2;
}
go();

立即调用函数表达式(IIFE)

立即调用函数表达式(IIFE, Immediately Invoked Function Expressions)是Javascript里面常用特性,我们可以利用它“避免污染全局变量”、“解决闭包冲突”、“只执行一次的函数”、“减少重复创建比较大的对象的开销(常见在一些工具函数内部,保存正则对象,数组,长字符串等对象”等。

1
2
3
4
/*简化版的IIFE*/
(function(){
//您的代码
})();

模拟块作用域,避免污染全局变量,常见的插件即是如此。

1
2
3
4
/* jquery1.9.0的写法 */
(function( window, undefined ) {
//非常长的代码
})( window );

解决闭包冲突,我们知道闭包可以让“函数内部所定义的函数持有外层函数的执行环境”,然而也有可能有些问题,例如下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var f1 = function() {
var res = [];
var fun = null;
for(var i = 0; i < 10; i++) {
fun = function() { console.log(i);};//产生闭包
res.push(fun);
}

return res;
}
// 会输出10个10,而不是预期的0 1 2 3 4 5 6 7 8 9
var res = f1();
for(var i = 0; i < res.length; i++) {
res[i]();
}

我们可以使用IIFE解决这个问题,修正过的代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var f1 = function() {
var res = [];
for(var i = 0; i < 10; i++) {
// 添加一个IIFE,立即执行
(function(index) {
fun = function() {console.log(index);};
res.push(fun);
})(i);
}

return res;
}

// 输出结果为0 1 2 3 4 5 6 7 8 9
var res = f1();
for(var i = 0; i < res.length; i++) {
res[i]();
}

模拟单例,javascript中我们可以使用IIFE实现OOP。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
}());

counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5

配合逻辑运算符使用,例如addEventListener的polyfill可以这么写。

1
2
3
4
5
6
/*把IIFE和逻辑运算符配合使用,检测是否需要运行polyfill*/
this.Element &&
Element.prototype.attachEvent && !Element.prototype.addEventListener &&
(function () {
//polyfill
}

逻辑运算符妙用

使用&&和||条件运算符,我们可以达到简化操作的目的,来看下面代码。

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
37
38
39
40
41
/* code one */
if (!theTitle) {
theTitle = "Untitled Document";
}
//使用||
theTitle = theTitle || "Untitled Document";

/* code two */
function isAdult(age) {
if (age && age > 17) {
return true;
}
else {
return false;
}
}
//使用 &&
function isAdult(age) {
return age && age > 17 ;
}

/* code three*/
if (userName) {
logIn (userName);
}
else {
signUp ();
}
//混合使用&&、||
userName && logIn (userName) || signUp ();

/*code four*/
var userID;
if (userName && userName.loggedIn) {
userID = userName.id;
}
else {
userID = null;
}
//使用&&、||
var userID = userName && userName.loggedIn && userName.id

##深入
本文的写作过程大量参考了以下文章,大家可以仔细阅读下面文章获得更深的体会。

##声明
前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接,http://blog.csdn.net/whqet/article/details/43865127
欢迎大家访问独立博客http://whqet.github.io

作为一个CSS预处理器,Sass正受到越来越多的青睐,诸如Github、Codepen、CSS-Tricks、SitePoint、w3cplus等网站采用Sass组织、管理CSS文件,Sass正在逐渐成为事实上的CSS预处理器行业标准。接下来几篇文章,我们来研读下Sass中的关键功能,今天来看map,大家不妨一坐,精彩内容马上呈现。
这里写图片描述

map简介

在Sass中,maps代表一种数据类型,可以包含若干键值对的对象类型,使用()包围一个map,里面的键值对用逗号隔开,键和值可以是任何的Sass数据类型,尽管一个值可以用在多个键上,但是通过一个键我们必须只能找到一个值。map不能直接在css中使用,如果你把一个map赋值给一个元素将会报错。下面的代码示例一个经典的map。

1
2
3
4
5
$map: (
key1: value1,
key2: value2,
key3: value3
);

map使用

我们可以使用一系列的函数操作map,可以使用循环指令遍历map。
map相关的函数有map-keys()、map-values()、map-get()、map-has-key()、map-merge()、map-remove()、keywords()等,函数功能如下表所示。

函数 功能 示例
map-keys(map) 返回map里面所有的key(list) map-keys((“foo”: 1, “bar”: 2)) => “foo”, “bar”
map-values(map) 返回map里面所有的value(list) map-values((“foo”: 1, “bar”: 2)) => 1, 2
map-get(map,key) 返回map里面指定可以的value map-get((“foo”: 1, “bar”: 2), “foo”) => 1
map-has-key(map,key) 返回map里面是否含有指定的key map-has-key((“foo”: 1, “bar”: 2), “foo”) => true
map-merge(map1,map2) 合并map(map) map-merge((“foo”: 1), (“bar”: 2)) => (“foo”: 1, “bar”: 2)
map-remove(map,keys) 删除指定map中的指定key(map) map-remove((“foo”: 1, “bar”: 2), “bar”) => (“foo”: 1)
keywords(args) 返回一个函数参数组成的map(map) @mixin foo(args…){@debug keywords($args); //=> (arg1: val, arg2: val)}

我们可以使用@each指令遍历map,如下所示。

1
2
3
4
5
6
7
8
9
10
11
$map: (
key1: value1,
key2: value2,
key3: value3
);

/* 遍历map */
@each $key, $value in $map {
.element--#{$key} {
background: $value;
}
}

map案例

map在Sass中应用广泛,有很多场合可以用到map,下面列举一二。

###指定多值
css里有很多属性可以指定多个值,例如transition、box-shadow等,这个时候我们可以使用map来定义不同的值,然后可以统一使用。例如

1
2
3
4
5
6
7
8
9
10
/* 使用map定义不同的值 */
$card_transition_map: (
trans1: 200ms transform ease-in-out,
trans2: 400ms background ease-in,
trans3: 600ms color linear
);

/* map-values统一使用 */
.card {
transition: map-values($card_transition_map);
}

编译之后输出

1
2
3
4
5
.card {
transition: 200ms transform ease-in-out,
400ms background ease-in,
600ms color linear
;

}

压缩多值

我们可以使用zip函数来压缩多值,例如操作animate时:

1
$animation_config: (
  name: none,
  duration: 0s,
  timing: ease,
  delay: 0s,
  iteration: 1, // infinite
  direction: normal, // reverse, alternate, alternate-reverse
  fill-mode: none, // forwards, backwards, both
  play-state: running
);

@function sh-setup($config) {
  @return zip(map-values($config)...);
}
 
.object {
  animation: sh-setup($animation_config);
}

编译之后输出结果为

1
.object {
  animation: none 0s ease 0s 1 normal none running;
}

指定皮肤

我们可以使用一个循环来遍历不同的map,达到指定不同皮肤的功效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$background_color: (
jeremy: #0989cb,
beth: #8666ae,
matt: #02bba7,
ryan: #ff8178
);

$font: (
jeremy: Helvetica,
beth: Verdana,
matt: Times,
ryan: Arial
);

@each $key, $value in $background_color {
.#{$key} {
background: $value;
font-family: map-get($font, $key);
}
}

编译之后输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.jeremy {
background: #0989cb;
font-family: Helvetica;
}

.beth {
background: #8666ae;
font-family: Verdana;
}

.matt {
background: #02bba7;
font-family: Times;
}

.ryan {
background: #ff8178;
font-family: Arial;
}

配置文件

使用Sass的一个最大的优点在于,我们可以对css文件进行统一的组织与管理,使用配置文件是达到目的的主要手段,例如我们把网页中所有层的z-index放配置文件里,在需要的地方进行调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*定义配置文件*/
$z-index: (
modal : 200,
navigation : 100,
footer : 90,
triangle : 60,
navigation-rainbow : 50,
share-type : 41,
share : 40,
);

/*在合适的时机调用*/
.navigation {
z-index: map-get($z-index, navigation);
}

编译之后输出

1
.navigation {
  z-index: 100;
}

上面案例调用的时候还用到map-get函数,还是比较麻烦,我们继续简化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$z-index: (
modal : 200,
navigation : 100,
footer : 90,
triangle : 60,
navigation-rainbow : 50,
share-type : 41,
share : 40,
);

@function z-index($key) {
@return map-get($z-index, $key);
}
@mixin z-index($key) {
z-index: z-index($key);
}
/*调用时*/
.navigation {
@include z-index(navigation);
}

断点管理

下面代码演示如何在项目管理中如何进行断点管理。

1
// _config.scss
$breakpoints: (
  small: 767px,
  medium: 992px,
  large: 1200px
);
 
// _mixins.scss
@mixin respond-to($breakpoint) { 
  @if map-has-key($breakpoints, $breakpoint) {
    @media (min-width: #{map-get($breakpoints, $breakpoint)}) {
      @content;
    }
  }
 
  @else {
    @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
  }
}
 
// _component.scss
.element {
  color: hotpink;
 
  @include respond-to(small) {
    color: tomato;
  }
}

编译之后输出结果为

1
.element {
  color: hotpink;
}

@media (min-width: 767px) {
  .element {
    color: tomato;
  }
}

处理前缀

下面我们来看map在处理前缀mixin中的应用,两个参数类型分别为map和list,使用需要注意。

1
/*定义*/
/// Mixin to prefix several properties at once
/// @author Hugo Giraudel
/// @param {Map} $declarations - Declarations to prefix
/// @param {List} $prefixes (()) - List of prefixes to print
@mixin prefix($declarations, $prefixes: ()) {
  @each $property, $value in $declarations {
    @each $prefix in $prefixes {
      #{'-' + $prefix + '-' + $property}: $value;
    }

    // Output standard non-prefixed declaration
    #{$property}: $value;
  }
}
/*使用*/
.selector {
  @include prefix((
    column-count: 3,
    column-gap: 1.5em,
    column-rule: 2px solid hotpink
  ), webkit moz);
}

编译之后输出为

1
.selector {
  -webkit-column-count: 3;
  -moz-column-count: 3;
  column-count: 3;
  -webkit-column-gap: 1.5em;
  -moz-column-gap: 1.5em;
  column-gap: 1.5em;
  -webkit-column-rule: 2px solid hotpink;
  -moz-column-rule: 2px solid hotpink;
  column-rule: 2px solid hotpink;
}

反向函数

Hugo Giraudel大牛定义的反向函数。

1
/*定义*/
/// Returns the opposite direction of each direction in a list
/// @author Hugo Giraudel
/// @param {List} $directions - List of initial directions
/// @return {List} - List of opposite directions
@function opposite-direction($directions) {
  $opposite-directions: ();
  $direction-map: (
    'top':    'bottom',
    'right':  'left',
    'bottom': 'top',
    'left':   'right',
    'center': 'center',
    'ltr':    'rtl',
    'rtl':    'ltr'
  );
 
  @each $direction in $directions {
    $direction: to-lower-case($direction);
    
    @if map-has-key($direction-map, $direction) { 
      $opposite-directions: append($opposite-directions, unquote(map-get($direction-map, $direction)));
    } @else {
      @warn "No opposite direction can be found for `#{$direction}`. Direction omitted.";
    }
  }
 
  @return $opposite-directions;
}
/*使用*/
.selector {
  background-position: opposite-direction(top right);
}

编译之后输出结果为

1
.selector {
  background-position: bottom left;
}

深入阅读

本文的写作过程大量参考了以下文章,大家可以仔细阅读下面文章获得更深的体会。

声明

前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助。
本文原文链接,http://whqet.github.io/2015/02/15/Sass%20map%E8%AF%A6%E8%A7%A3/
欢迎大家访问CSDN博客,http://blog.csdn.net/whqet/

刚刚写了篇《CSS变量试玩儿》,我们了解到可以使用原生的CSS来定义使用变量,简化CSS书写、优化代码的组织与维护,但可怕的兼容性问题,又让我们望而却步、一笑了之。
但是有这么一个CSS变量currentColor,兼容良好、功能强大,接下来我们来一探究竟。

##简介
CSS里已经有一个长期存在的兼容性良好的变量currentColor,表示对当前元素颜色的引用,可以应用在当前元素的其他属性和后代元素上。

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
37
38
39
40
41
42
43
h1 { 
color: hsl(0,0%,44%);
padding: 1rem;
/* 这里调用默认颜色 */
border-bottom: 4px solid;
}

/* 使用currentColor,用在其他属性上 */
h1 {
color: hsl(0,0%,44%);
padding: 1rem;
/* 这里调用默认颜色 */
border-bottom: currentColor 4px solid;
}

/* 使用currentColor,用在后代元素上 */
a.blog{
text-decoration: none;
font-weight:bold;
}

/*设置不同状态颜色*/
a.blog { color: #900; }
a.blog:hover,
a.blog:focus { color: #990; }
a.blog:active { color: #999; }
/*设置箭头*/
a.blog:after{
width: 0;
height: 0;
border: 0.4em solid transparent;
border-right: none;
content: '';
display: inline-block;
position:relative;
top:1px;
left:2px;
}

/*设置箭头继承父对象颜色*/
a.blog::after,
a.blog:hover::after,
a.blog:focus::after,
a.blog:active::after
{
border-left-color: currentColor;
}

我们可以发现,使用currentColor能够大大简化代码书写,优化代码的组织与维护。

##实例
为了演示currentColor的应用,我们造了一个案例,参见codepen,大家可以-在线编辑-,-下载收藏-。我们在案例里尝试了currentColor和渐变的结合,和动画的结合,和伪对象元素的结合。
案例演示
html文件放上来,顺便弄点广告哈。
html文件

1
2
<h2 class="icon">Let's go to whqet's blog</h2>
<p>前端开发whqet,<a class="blog" href="http://blog.csdn.net/whqet/">王海庆的技术博客</a>,关注前端开发,分享相关资源,希望可以对您有所帮助。csdn专家博客http://blog.csdn.net/whqet和个人独立博客http://whqet.github.io同步更新,希望可以得到您的支持与肯定,您的支持是我最大的动力!王海庆,浙江邮电职业技术学院软件技术青椒一枚,其貌不扬、其名不翔,关心技术、热爱生活,我爱<a class="link" href="#">怒放的生命</a></p>

然后在CSS中,我们使用-prefix free不再用考虑复杂的浏览器厂商前缀。
这里使用本博文章《苹果风格的下划线》所述效果,利用渐变划线,然后利用text-shadow隔离线条,在渐变里面使用了currentColor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*使用googlefont*/
@import url(//fonts.googleapis.com/css?family=Cedarville+Cursive);
/*使用渐变划线,利用text-shadow隔离线条*/
h2.icon{
margin:10px 0;
display: inline-block;
font-size:3em;
width:auto;
font-family:Cedarville Cursive;
text-shadow: 2px 0 0 #fff, -2px 0 0 #fff;
color: #000;
background-image: linear-gradient( to right, currentColor 0%, #fff 120% );
background-repeat: repeat-x;
background-position: 0 75%;
background-size: 100% 3px;
}

然后,我们探索将currentColor应用到:after元素中去,实现链接装饰元素的颜色与链接元素的绑定。

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
p{
text-indent: 2em;
line-height: 1.5em;
}

a.blog,a.link{
text-decoration: none;
font-weight:bold;
position: relative;
margin-right:4px;
}

/*应用到后代伪类元素*/
a.blog { color: #900; }
a.blog:hover,
a.blog:focus { color: #990; }
a.blog:active { color: #999; }

a.blog::after{
width: 0;
height: 0;
border: 0.4em solid transparent;
border-right: none;
content: '';
position:absolute;
right:-6px;
top:2px;
}


a.blog::after,
a.blog:hover::after,
a.blog:focus::after,
a.blog:active::after
{
border-left-color: currentColor;
}

应用到动画元素上的尝试。

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
/* 结合动画应用 */
a.link{
color: #900;
animation:go 2s infinite;
}

a.link::before,
a.link::after{
content: '';
width:100%;
height: 2px;
background-color: currentColor;
position:absolute;
left:0;
}

a.link::before{
top:-4px;
}

a.link::after{
bottom:-4px;
}

@keyframes go{
0% {color:#900}
33%{color:#090}
66%{color:#009}
}

##深入
本文的写作过程大量参考了以下文章,大家可以仔细阅读下面文章获得更深的体会。

##致谢
前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助。
本文原文链接,http://whqet.github.io/2015/02/12/CSS%20currentColor%E7%A0%94%E7%A9%B6/
欢迎大家访问独立博客http://whqet.github.io