clip用法

clip 属性剪裁绝对定位元素。所有的主流浏览器都支持该元素。

这个属性用于定义一个剪裁矩形。对于一个绝对定义元素,在这个矩形内的内容才可见。出了这个剪裁区域的内容会根据 overflow 的值来处理。剪裁区域可能比元素的内容区大,也可能比内容区小。

基本语法


用法

clip: rect(10px  350px  170px  0); /* IE4 to IE7 */
clip: rect(10px, 350px, 170px, 0); /* IE8+ & other browsers */

示例

<style>
    .demo-clip {
        background: rgb(168, 231, 168);
        width: 100px; 
        height: 100px;
        position: absolute;
        clip: rect(5px 75px 75px 5px);
        clip: rect(5px, 75px, 75px, 5px);
    }
</style>
<div class="demo-clip">
</div>


可以看到rect(top, right, bottom, left)四个值指的是相对左上角(0, 0)的偏移数值。

有趣的实现

炫彩文字

<style>
.demo-color-text {
    position: relative;
    font-size: 26px;
    background: #f6f6f6;
    height: 3em;
    width: 10em;
}
.demo-text-top {
    position: absolute;
    color: #CC0000;
    left: 2em;
    top: 1em;
    clip: rect(0 auto 13px 0);
    clip: rect(0, auto, 13px, 0);
}
.demo-text-bottom {
    position: absolute;
    color: #333333;
    left: 2em;
    top: 1em;
    clip: rect(13px, auto, auto, auto);
}
</style>
<div class="demo-color-text">
    <div class="demo-text-top">colorful text</div>
    <div class="demo-text-bottom">colorful text</div>
</div>

hover控制图片的显示

<style type="text/css">
.demo-show-hide {
    position: relative;
    background: #f6f6f6;
    margin: 10px 0;
    width: 15em;
    height: 10em;
    padding: 10px;
}
.demo-hover-btn {
    background: #CC0000;
    display: block;
    padding: 3px;
    width: 5em;
    margin: 3px 0;
    color: #fff;
    cursor: pointer;
    text-align: center;
}
.demo-hover-btn:hover {
    background: #333;
}
.demo-hover-img {
    position: absolute;
    display: block;
    top: 45px;
    left: 10px;
    clip: rect(120px 0 0 160px);
    clip: rect(120px, 0, 0, 160px);
    -webkit-transition: all 0.5s linear;
    -moz-transition: all 0.5s linear;
    transition: all 0.5s linear;
}
.demo-hover-btn:hover ~ .demo-hover-img {
    clip: rect(0 160px 120px 0);
    clip: rect(0, 160px, 120px, 0);
}
</style>
<div class="demo-show-hide">
    <span class="demo-hover-btn">
        hover me
    </span>
    <img class="demo-hover-img" src="http://img3.douban.com/icon/ul29163290-16.jpg">
</div>

css选择器

css选择器分类

  • id选择器 #id-name {}
  • 类选择器 .class-name {}
  • 标签选择器 div {} h1 {} p {}
  • 相邻选择器 div + p {}
  • 子选择器 ul < li {}
  • 后代选择器 ul li {}
  • 通配符选择器 * {}
  • 属性选择器
1
h1[class] { //所有带有class属性的h1}
1
[foo^='bar'] foo属性以'bar'开头的所有元素
1
[foo$='bar'] foo属性以'bar'结尾的所有元素
1
[foo*='bar'] foo属性包含'bar'的所有元素
**一般有一种场景:比如想对包含某个网站链接的a标签应用某种特殊样式**
1
a[href*='taobao.com'] {}
  • 伪类选择器/伪元素选择器
    • 伪类:a:link {} a:hover {} 一般建议申明的顺序为:link visited focus hover active
    • 伪元素:a:after {} a:before {}

权重

  • 通配选择器:0,0,0,0
  • 标签、类、属性、伪元素选择器:0,0,0,1
  • 伪类选择器:0,0,1,0
  • id选择器:0,1,0,0

当我们在使用规则时,计算权重,就是把各选择器的权值加到一起如:

1
2
3
4
5
h1 {} // 0001
h1 a {} //0002
h1 a.node {} //0012
#node {} //0100
div#sidebar *[href] {} //0111

计算出了权值,怎么来比较呢?需要注意的是,这个权值是从左到右按位进行比较的,1000大于任何0xxx,01xx大于任何00xx,以此类推。

简单来说,样式优先级可以总结为:
important>内联>id>class>标签/伪类/属性选择>伪元素>通配符>继承

但是实际编码中,样式的优先级还跟样式定义的顺序有关系,在样式的定义时不仅需要注意优先级也需要关注尽量减少css的重复定义和代码冗余

css选择器执行效率

首先应该了解,对于h1 a {}这样的样式,系统是怎么处理的呢?系统对样式选择器的匹配顺序是从右到左的,也就是会先找到所有的a标签,然后继续向左匹配,查找父辈元素中是否有h1元素,如果都能匹配到,则找到。

那么怎么编写简洁高效的css呢?有几条很简单的原则

  • 不要在id选择器前再加其他的选择器,因为id本身是唯一的
1
2
//bad: div#id-name {}
#id-name {}
  • 不要在class选择器前再加标签选择器
1
2
//bad: div.class-name {}
.class-name {}
  • 尽量在dom中增加class的方式来标记而不是通过属性选择或者层级的方式来定义样式
1
2
//bad: a img[src="xxx"] {}
.xx-img {}
  • 尽量少定义层级关系,因为这会增加查找开销

记住一点,如果直接可以定位到的元素,不要增加不必要的层级或者限制条件

skills

前端开发中小技巧和注意事项

1、浏览器地址栏中执行js代码

1
javascript:alert('hello,amo!');

这里需要注意的是:
如果是拷贝一段脚本到浏览器地址栏中,如果是IE或者Chrome会自动过滤掉javascript:部分,如果要保证能被正确执行请手动添加。但是对于Firefox不会。

2、浏览器地址栏中执行html代码

1
data:text/html,<h1>hello,amo!</h1>

这里需要注意的是:
只有在非IE内核的浏览器中才能正确显示。

3、把浏览器当编辑器

1
data:text/html, <html contenteditable>

这样浏览器就变成一个编辑器了。为什么可以实现呢?这是因为H5中新加了contenteditable属性,当元素指定了该属性,内容就变得可以编辑了。

如果对于一个现有的页面,想要将它变成编辑器模式怎么做呢?
可以在控制台中输入:

1
document.body.contenteditable = true;

4、清除浮动常用方法

在网页的布局上或多或少都会使用到浮动。但是浮动往往也会产生一些副作用,最常见的便是会影响兄弟元素和父元素。所以一定要记得清除浮动。我一般用以下两种方法:

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
.con {
border: 1px solid #ddd;
color: gray;
margin: 10px auto;
width: 500px;
}
.c-float {
float: left;
}
.c-margin {
margin-top: 50px;
}
.c-background {
background-color: #ccc;
}
.clear {
clear: both;
}
.clearfix:before, .clearfix:after {
content: "";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
*zoom: 1;
}
1
2
3
4
5
6
<!-- 被浮动影响,父元素高度塌陷 -->
<div class="con">
<div class="c-float c-background">
我设置了浮动
</div>
</div>
1
2
3
4
5
6
7
8
9
<!-- 加入一个空的div,并设置清除浮动 -->
<div class="c-margin con">
<div class="c-float c-background">
我设置了浮动
</div>
<div class="clear">
我清除浮动
</div>
</div>
1
2
3
4
5
6
<!-- 利用:after伪元素 -->
<div class="c-margin con clearfix">
<div class="c-float c-background">
我设置了浮动
</div>
</div>

demo

less入门

Less 是一个Css 预编译器,意思指的是它可以扩展Css语言,添加功能如允许变量(variables),混合(mixins),函数(functions) 和许多其他的技术,让你的Css更具维护性,主题性,扩展性。
Less包含了一套自定义的语法及一个解析器,用户可以通过这些语法来编写less文件,然后调用解析器来生成相应的css文件。简单来说,less其实就是在现有css语法的基础上为它加入了程序式语言的特性。

Less 可运行在 Node 环境,浏览器环境和Rhino环境.同时也有3种可选工具供你编译文件和监视任何改变。

官网
中文网址

一、安装

1、命令行下使用

Less可以通过npm在命令行上使用,作为一个脚本文件浏览器或用于广泛的第三方工具下载。

因为我的电脑已经安装了node环境,所以可以直接通过npm包安装的方式来安装less。

1
npm install -g less

完成安装之后,便可以通过lessc命令来编译less文件了。如下例:

1
2
3
4
5
@color: #ccc;
body {
color: @color;
}

编译该文件:

1
lessc test.less > test.css

便可以得到test.css文件如下:

1
2
3
body {
color: #ccc;
}

当然lessc后也可以跟很多的参数,如:

1
2
//-x表示压缩
lessc -x test.less > test.css

更多命令可以参考 —help或者参考官网

2、客户端使用

在浏览器中使用less.js开发是很好的,但不推荐用于生产环境中。

浏览器端使用是在使用LESS开发时最直观的一种方式。如果是在生产环境中,尤其是对性能要求比较高的场合,建议使用node或者其它第三方工具先编译成CSS再上线使用。

下面看如果直接在客户端来使用

1
2
3
4
<!-- 目标样式表 -->
<link rel="stylesheet/less" type="text/css" href="test.less" />
<!-- less文件 -->
<script src="less.min.js" type="text/javascript"></script>

这样当在浏览器中访问该页面时,less.min.js便会编译test.less并在页面head中插入相应编译后的css样式

有两点需要特别注意:

  • 确保包涵.less样式表在less.js脚本之前
  • 当你引入多个.less样式表时,它们都是独立编译的。所以,在每个文件中定义的变量、混合、命名空间都不会被其它的文件共享。

3、在引入了GruntJs的项目中使用

参见grunt-contrib-less

二、语法

1、变量

less允许开发者自定义变量,这样做有什么好处呢?如下例:

less:

1
2
3
4
5
6
7
8
9
10
11
@artical-color: #fff;
@title-color: #ccc;
.con {
.con-title {
color: @title-color;
}
.con-artical {
color: @artical-color;
}
}

css:

1
2
3
4
5
6
.con .con-title {
color: #ccc;
}
.con .con-artical {
color: #fff;
}

不难看到,通过这种方式,可以方便对变量进行统一的管理,可以抽取公共的属性在全局进行定义,一旦涉及到修改,只需修改变量即可。此外,也可以利用这种特性,来定义主题。

在编程中既然有变量,那么就必定涉及到一个概念作用域。下面来看下在less中变量的作用域是怎样的。

less:

1
2
3
4
5
6
7
8
@color: #fff;
.con {
color: @color;
@color: #000;
.con-title {
background-color: @color;
}
}

css:

1
2
3
4
5
6
.con {
color: #fff;
}
.con .con-title {
background-color: #000;
}

2、mixins

在less中,mixins指在一个class中混入另一个已经定义的class。

less:

1
2
3
4
5
6
7
8
9
//定义一个样式
.btn {
background-color: #b72b25;
color: #fff;
}
//在其他的选择器中使用
.con-btns {
.btn;
}

css:

1
2
3
4
.con-btns {
background-color: #b72b25;
color: #fff;
}

mixins其实就是一种规则的复用。除此之外,mixins还允许混入参数。

less:

1
2
3
4
5
6
7
8
9
10
11
//定义一个样式
.btn(@color) {
background-color: @color;
}
//在其他的选择器中使用
.con-enable=btn {
.btn(#b72b25);
}
.con-disable=btn {
.btn(#ddd);
}

css:

1
2
3
4
5
6
.con-enable-btn {
background-color: #b72b25;
}
.con-disable-btn {
background-color: #ddd;
}

mixins还支持传入默认参数,如下:

less:

1
2
3
4
5
6
.border(@w:1px,@t:solid,@c:#ccc) {
border: @arguments;
}
.detail-info {
.border(2px,dashed,#d8d8d8);
}

css:

1
2
3
.detail-info {
border: 2px dashed #d8d8d8;
}

在项目中为了防止选择器重名的问题,可以利用命名空间:

1
2
3
4
5
6
#amo {
.head {}
}
.page-head {
#amo > .head;
}

3、嵌套

嵌套规则很简单,如html本身的dom层次。

1
2
3
4
<div class="con">
<div class="con-title"></div>
<div class="con-artical"><a href="javascript:void(0)"></a></div>
</div>

那么less可以这样编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.con {
...
.con-title {
...
}
.con-artical {
...
a {
...
&:hover { //&表示该元素如果没有&表示后代元素
...
}
}
}
}

4、运算和函数

以按钮的hover为例:

less:

1
2
3
4
5
6
7
8
9
10
11
12
@color: #80e619;
.btn(@color) {
background-color: @color;
}
.enable-btn {
.btn(@color);
&:hover {
.btn(darken(@color, 20%));
}
}

css:

1
2
3
4
5
6
.enable-btn {
background-color: #80e619;
}
.enable-btn:hover {
background-color: #4d8a0f;
}

这样很简单的就实现了鼠标hover到按钮上背景色变暗的效果。

更多功能可以参考function api

4、注释

可采用//注释或者/注释/,但是在编译生成css若想保留注释必须采用css标准注释/../。

5、css3参考用例

  • 圆角
1
2
3
4
5
6
7
8
9
.border-radius (@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
.test-div {
.border-radius(20px);
}
  • 四个角可自由定制角度
1
2
3
4
5
6
7
8
9
.border-radius-custom (@topleft: 5px, @topright: 5px, @bottomleft: 5px, @bottomright: 5px) {
-webkit-border-radius: @topleft @topright @bottomright @bottomleft;
-moz-border-radius: @topleft @topright @bottomright @bottomleft;
border-radius: @topleft @topright @bottomright @bottomleft;
}
.test-div {
.border-radius-custom(20px, 20px, 0px, 0px);
}
  • 阴影
1
2
3
4
5
6
7
8
9
.box-shadow (@x: 0px, @y: 3px, @blur: 5px, @alpha: 0.5) {
-webkit-box-shadow: @x @y @blur rgba(0, 0, 0, @alpha);
-moz-box-shadow: @x @y @blur rgba(0, 0, 0, @alpha);
box-shadow: @x @y @blur rgba(0, 0, 0, @alpha);
}
.test-div {
.box-shadow(5px, 5px, 6px, 0.3);
}
  • 元素过渡效果
1
2
3
4
5
6
7
8
9
10
11
.transition (@prop: all, @time: 1s, @ease: linear) {
-webkit-transition: @prop @time @ease;
-moz-transition: @prop @time @ease;
-o-transition: @prop @time @ease;
-ms-transition: @prop @time @ease;
transition: @prop @time @ease;
}
.test-div {
.transition(all, 0.5s, ease-in);
}
  • 旋转
1
2
3
4
5
6
7
8
9
10
11
.transform (@rotate: 90deg, @scale: 1, @skew: 1deg, @translate: 10px) {
-webkit-transform: rotate(@rotate) scale(@scale) skew(@skew) translate(@translate);
-moz-transform: rotate(@rotate) scale(@scale) skew(@skew) translate(@translate);
-o-transform: rotate(@rotate) scale(@scale) skew(@skew) translate(@translate);
-ms-transform: rotate(@rotate) scale(@scale) skew(@skew) translate(@translate);
transform: rotate(@rotate) scale(@scale) skew(@skew) translate(@translate);
}
.test-div {
.transform(5deg, 0.5, 1deg, 0px);
}
  • 颜色渐变
1
2
3
4
5
6
7
8
9
10
11
12
13
/*线性渐变*/
.gradient (@origin: left, @start: #ffffff, @stop: #000000) {
background-color: @start;
background-image: -webkit-linear-gradient(@origin, @start, @stop);
background-image: -moz-linear-gradient(@origin, @start, @stop);
background-image: -o-linear-gradient(@origin, @start, @stop);
background-image: -ms-linear-gradient(@origin, @start, @stop);
background-image: linear-gradient(@origin, @start, @stop);
}
.test-div {
.gradient(left, #663333, #333333);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/*快速渐变*/
.quick-gradient (@origin: left, @alpha: 0.2) {
background-image: -webkit-linear-gradient(@origin, rgba(0,0,0,0.0), rgba(0,0,0,@alpha));
background-image: -moz-linear-gradient(@origin, rgba(0,0,0,0.0), rgba(0,0,0,@alpha));
background-image: -o-linear-gradient(@origin, rgba(0,0,0,0.0), rgba(0,0,0,@alpha));
background-image: -ms-linear-gradient(@origin, rgba(0,0,0,0.0), rgba(0,0,0,@alpha));
background-image: linear-gradient(@origin, rgba(0,0,0,0.0), rgba(0,0,0,@alpha));
}
.test-div {
background-color: #bada55;
.quick-gradient(top, 0.2);
}
  • 镜像
1
2
3
4
5
6
7
8
.reflect (@length: 50%, @opacity: 0.2){
-webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent),
color-stop(@length, transparent), to(rgba(255,255,255,@opacity)));
}
.test-div {
.reflect(20%, 0.2);
}
  • 颜色
1
2
3
4
5
6
7
8
9
10
11
12
/*互补色*/
@base: #663333;
@complement1: spin(@base, 180);
@complement2: darken(spin(@base, 180), 5%);
@lighten1: lighten(@base, 15%);
@lighten2: lighten(@base, 30%);
.one {color: @base;}
.two {color: @complement1;}
.three {color: @complement2;}
.four {color: @lighten1;}
.five {color: @lighten2;}
1
2
3
4
5
6
7
8
9
10
11
12
/*颜色微调*/
@base: #663333;
@lighter1: lighten(spin(@base, 5), 10%);
@lighter2: lighten(spin(@base, 10), 20%);
@darker1: darken(spin(@base, -5), 10%);
@darker2: darken(spin(@base, -10), 20%);
.one {color: @base;}
.two {color: @lighter1;}
.three {color: @lighter2;}
.four {color: @darker1;}
.five {color: @darker2;}

也可以参考
css3预处理工具
useful mixins

console使用小技巧

作为一个前端开发者,可能每天都会用到console对象的方法进行调试等,但是你真的了解console么?什么是console呢?

最初,console是firebug提供的一个内置对象,它可以用于我们跟踪调试在网页加载过程中的各类信息。

那么我们首先来看下它的基本用法。

一、基本用法

1
console.log("log info");

根据信息的不同性质,console对象还有4种显示信息的方法,分别是:

  • 一般信息console.info()
  • 出错信息console.debug()
  • 警告提示console.warn()
  • 错误提示console.error()

二、格式化输出

console对象支持类似于C语言printf占位符写法的输出,一些复杂的输出利用这种方法可以让结构更加的清晰。

先看一个例子:

1
console.log('%d + %d = %d', 1, 1, 2);

console支持的占位符格式有如下几种:

  • %s : 字符串

  • %d / %i : 整数

  • %f : 浮点数

  • %o / %O : 对象,可以用来查看一个对象内部的情况。虽然对于普通对象这两者打印出来的信息是一样的,但是需要注意的是,在Chrome控制台中打印的如果是一个dom节点,那么此时二者是有区别的,%o打印的为和非格式化输出的结果一样,包括节点、内容、子节点等,但是对于%O来说,打印的是dom节点中各个对象的属性。

  • %c : css样式

下面我们来看几个例子:

1
2
3
//chrome中
console.log("%O", document.body);
console.log("%o", document.body);

1
console.log("%c%s %chas %d fingers", "color:green;text-shadow:1px 1px 1px rgba(0,0,0,.2); font-size: 16pt", "amo", "color: #333333; font-size: 16pt", 10);

原来在控制台里还可以进行样式的控制,是不是很有趣?但是对于IE并不支持样式,所以注意哦既然可以加样式,自然而然就会问,那能不能进行图片的输出呢,答案是否定的(firefox提供console.image插件),可是我们可以通过背景图的方式来进行图片的输出。只是这里的图片大小需要通过padding和line-height来控制。用的时候请谨慎调节(chrome下生效)。

看个例子:

1
2
//chrome
console.log("%c", "padding: 80px 100px;height:1px; background:url(http://p1.gexing.com/G1/M00/24/A6/rBACFFH2hjPAQgmdAAAVighCO6A353_200x200_3.jpg);line-height:200px");

三、分组输出

如果需要打印较多的信息,可以利用分组输出进行结构化的管理。console.group()定义组的开始,console.groupEnd()定义组的结束。

1
2
3
4
5
6
7
8
9
console.group("amo");
console.log("a's hand");
console.log("a's work");
console.groupEnd();
console.group("zicheng");
console.log("z's hand");
console.log("z's work");
console.groupEnd();

四、其他用法

  • console.dir()显示一个对象所有的属性和方法
1
2
var cat = {"eyes": 2, "ears": 2, "sayHi": function(){ return "miao~"; }};
console.dir(cat);

  • console.trace()追踪函数调用时的栈信息

  • 计时功能

console.time()和console.timeEnd(),利用它们分别在代码执行开始和结束时打上标识,以用来显示代码的运行时间。

1
2
3
4
5
console.time("for");
for(var i=0;i<1000;i++){
for(var j=0;j<1000;j++){}
}
console.timeEnd("for"); //for: 3.000ms
  • 计数器

console.count(),用于记录函数被调用的次数统计,在某些复杂场景的调试中很有用。

1
2
3
4
5
function login(user) {
console.count("Login called for user '" + user + "'");
}
login("amo"); //Login called for user 'amo': 1
login("zicheng"); //Login called for user 'zicheng': 1
  • 性能分析

console.profile(),可以帮助我们进行性能分析,找出瓶颈。(firefox有效)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Foo(){
for(var i=0;i<10;i++){
funcA(1000);
}
funcB(10000);
}
function funcA(count){
   for(var i=0;i<count;i++){}
}
function funcB(count){
  for(var i=0;i<count;i++){}
}
console.profile('profile');
Foo();
console.profileEnd();

由上图可以看到各个函数执行的情况。

  • 清空所有调试信息
1
console.clear();

需要注意的是浏览器兼容性

对于IE较老版本,或者是某些属性,并不是所有浏览器都兼容的,所以调试信息请尽量在开发时使用,并不要带到线上。但是我们也看到有些网站会将招聘信息通过console.log()的方式输出到控制台中,这个时候就要注意做好兼容。以下为腾讯所做的处理,仅供参考。

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
(function(){
if(!console || !console.log){
return;
}
var toFixedVersion = function(ver, floatLength){
ver= (""+ver).replace(/_/g,".");
floatLength = floatLength || 1;
ver = String(ver).split(".");
ver = ver[0] + "." + (ver[1] || "0");
ver = Number(ver).toFixed(floatLength);
return ver;
};
var ua = navigator.userAgent.toLowerCase(),
browserName,
browserVer,
s;
var setVer = function(name, ver){
browserName = name;
browserVer = ver;
};
(s = ua.match(/chrome\/([\d]+)/)) ? setVer("chrome",toFixedVersion(s[1])) : 0;
var isSupport = (browserName === 'chrome' && browserVer >= 25);
if(isSupport){
var imgList = [];
for(var i = 0; i < 9; i++){
imgList.push('padding:49px 55.5px;line-height:111px;background:url(http://codestar.alloyteam.com/1/style/image/beauty' + (i+1) + '.jpg) no-repeat;');
}
console.log('%c云云无情,腾腾有爱', 'font-size:18px;text-shadow: rgb(153, 153, 153) 2px 2px 2px;font-weight:bold;line-height:1.8;font -family:"微软雅黑"');
console.log('%c', imgList[Math.round(Math.random()*(imgList.length-1))]);
console.log('%c如果你没有100个“往来”好友,那就来腾讯领红包吧!红包精彩,腾讯更精彩!', 'color:#08c;');
console.log('http://www.ipresst.com/jointencent');
console.log('\n-------------华丽的分割线-------------\n');
console.log('%c【前端特工】\n“据内线消息,TX公司将于近期推出一个新的HTML5重磅产品。\n公司担心该产品会带来威胁,特命你潜入TX,探查底细 ……”\nhttp://codestar.alloyteam.com\n\n', 'line-height:1.8;');
} else {
console.log('【云云无情,腾腾有爱】\n如果你没有100个“往来”好友,那就来腾讯领红包吧!红包精彩,腾讯更精彩!\nhttp://www.ipresst.com/jo intencent');
console.log('\n-------------华丽的分割线-------------\n');
console.log('【前端特工】\n“据内线消息,TX公司将于近期推出一个新的HTML5重磅产品。\n公司担心该产品会带来威胁,特命你潜入TX,探查底细…… ”\nhttp://codestar.alloyteam.com\n\n');
}
})();

参考资料

console-api

跨域问题及解决方案

说到javascript跨越问题,首页必然需要引入一个概念。那就是为什么会存在跨域问题?又该如何解决呢?

一、同源策略(same-origin policy)

在web应用安全模型里同源策略是一个很重要的概念。它是由Netscape提出的一个著名的安全策略,现在所有的可支持javascript的浏览器都会使用这个策略。

同源策略,又称为单源策略,它限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式。

Mozilla认为两个页面它们拥有相同的协议、端口(如果指明)、主机名,那么这两个页面就拥有相同的源。

下面来看一个例子,假设有一个url地址为: http://www.a.com/page/a.html的同源检测示例:

URL 非IE浏览器结果 IE浏览器结果 原因
http://www.a.com/page/b.html 成功 成功 -
http://www.a.com/app/c.html 成功 成功 -
http://username:password@www.a.com/page/b.html 成功 成功 -
http://www.a.com:81/page/d.html 失败 成功 端口不同
https://www.a.com/page/e.html 失败 失败 协议不同
http://www.b.a.com/page/c.html 失败 失败 主机不同
http://www.c.com/page/c.html 失败 失败 主域不同

从上表不难看出,对于IE来说在处理同源策略上有一些不同:

1、端口:IE未将端口号加入到同源策略的组成部分之中,因此 http://a.com:81/index.htmlhttp://a.com/index.html 属于同源并且不受任何限制。

2、授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。

除这些指定的URL之外,也常常会有来自about:blank,javascript:和data:URLs中的内容,它们遵循源继承的原则,继承将其载入的文档所指定的源,因为它们的URL本身未指定任何关于自身源的信息。

二、Javascript跨域解决方案

1、设置Domain

页面可以改变本身的源,但会受到一些限制。脚本可以设置document.domain 的值为当前域的一个后缀

在同源策略中有一个例外,脚本可以设置 document.domain 的值为当前域的一个后缀,如果这样做的话,短的域将作为后续同源检测的依据。例如,假设在 http://b.a.com/page/a.html 中的一个脚本执行了下列语句:

1
document.domain = "a.com"

这条语句执行之后,页面将会成功地通过对 http://a.com/page/a.html 的同源检测。而同理,a.com 不能设置 document.domain 为 b.com.

浏览器单独保存端口号。任何的赋值操作,包括document.domain = documen.domain都会以null值覆盖掉原来的端口号。因此a.com:8080页面的脚本不能仅通过设置document.domain = “a.com”就能与company.com通信。赋值时必须带上端口号,以确保端口号不会为null。

注意:使用document.domain来安全是让子域访问其父域,需要同时将子域和父域的document.domain设置为相同的值。必须要这么做,即使是简单的将父域设置为其原来的值。没有这么做的话可能导致授权错误。

  • 举个例子

    a.taobao.com嵌入一个b.taobao.com的页面,并且需要做高度自适应,那么可以这么来做:

    • 在a页面中设置domain并定义autoHeight方法(用处为改变iframe的高度)
1
document.domain = "taobao.com"
- 在b页面,页面加载之后或者所有涉及到高度变化的事件中,调用a页面的方法:
1
2
3
4
5
function fixHeight(){
document.domain = 'taobao.com';
var oHeight = document.documentElement.scrollHeight;
window.parent.autoHeight(oHeight); //调用a页面的autoHeight方法,在该方法中去改变iframe的高度
}

2、使用代理页

如果主域名也不同该怎么做呢?如:a.com/index.html和b.com/iframe.html

  • 有一种办法是采用代理页的方式

    即在b.com下建立一个b.com/proxy.html代理页面,还是以高度自适应为例来说明:

    a页面iframe该proxy页面,并将高度以hash值的方式填到这个嵌入proxy.html的iframe的src中去
    在proxy.html中去拿到这个hash中的高度值,并去操作父父层页面的高度
    iframe cross domain

    代码如下:

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
#set_height.js
(function(win, doc){
win.onload = function () {
var url = "http://a.com/proxy.html";
var ifmProxy = doc.getElementById("ifmProxy"); //iframe target
var hs; //height
var hsLastTime = 0; //height last time
var startTime = 0; //count
var loadIframeStart = win.setInterval( function () {
setHeight();
}, 500);
function setHeight() {
startTime++;
//get current height
hs = doc.documentElement.scrollHeight;
//update the hs height
if(hs !== hsLastTime) {
ifmProxy.src = url + "#" + hs;
hsLastTime = hs;
}
//clearCount and restart
if(startTime >= 500) {
clearInterval(loadIframeStart);
startTime = 0;
loadIframeStart = win.setInterval( function() {
setHeight();
}, 500)
}
}
};
})(window, document);
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
#proxy.html
<script>
try{
var ifmAnalyst = parent.parent.document.getElementById('isvIframeCon'); //目标iframe
var hs; //获取的高度
var hsLastTime = 0; //上一次获取到的高度
var startTime = 0; //计时器初始值
var loadIframeStart = window.setInterval( function () {
updateHeight();
}, 500);
function updateHeight() {
startTime++;
//获取当前的高度值
hs = window.location.hash;
//当高度改变则去更新iframe的高度同时将hsLastTime更新
if(hs !== hsLastTime) {
ifmAnalyst.style.height = hs.split("#")[1] + "px";
hsLastTime = hs;
}
//当达到一定的次数,清理一次计时器,并重新开始监听
if(startTime >= 500) {
clearInterval(loadIframeStart);
startTime = 0;
loadIframeStart = window.setInterval( function() {
updateHeight();
}, 500)
}
}
} catch(ex) {
}
</script>

3、JSONP(创建script标签形式)

所谓JSONP的方式简单来说就是利用script标签不受同源策略的限制这一特性。

我们通过script标签的形式把想要请求的地址作为src传入,从而获得相应的文件或者JSON数据。

a.com下的数据fn({“name”: “amo”});

b.com下的函数function fn(res){ console.log(res.name); }

下面我们来看下具体来写应该怎样做:

  • 在A.com网站下:
1
2
3
4
5
6
7
8
9
10
function createJs(sUrl){
var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.src = sUrl;
document.getElementByTagName('head')[0].appendChild(oScript);
}
createJs('jsonp.js?callback=fn');
function fn(rs) {
console.log(rs);
}
  • 在B.com的jsonp.js通过拿到这个callback参数,并把它填充到具体的数据中,格式如下
1
fn({"name", "amo"});
这样就相当于页面上是这样的
1
2
3
<script>
fn({"name": "amo"});//fn这个函数的调用
</script>

当然这里只是一个思路的过程,实际JSONP的过程要比这复杂的多,比如说是否onload、回调状态码、格式的校验等。

4、postMessage方式

在HTML5中,提出了工作线程的概念(web workers)。Web Workers 允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。web worker一旦被创建,就可以通过postMessage 向任务池发送任务请求,执行完之后再通过 postMessage 返回消息给创建者指定的事件处理程序 ( 通过 onmessage 进行捕获 )。Web Workers 进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用 XMLHttpRequest 来处理 I/O,但通常,后台进程(包括 Web Workers 进程)不能对 DOM 进行操作。如果希望后台程序处理的结果能够改变 DOM,只能通过返回消息给创建者的回调函数进行处理。

那么利用这个特性,我们怎么来实现跨域之间的通信呢?还是以高度自适应为例。

a.com/parent.html 嵌入 b.com/child.html该如何去获取到b下面的页面高度呢?

在child.html中引入如下代码

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
(function(win, doc){
win.onload = function () {
var hs; //height
var hsLastTime = 0; //height last time
var startTime = 0; //count
var loadIframeStart = win.setInterval( function () {
setHeight();
}, 500);
function setHeight() {
startTime++;
//get current height
hs = doc.documentElement.offsetHeight;
//update the hs height
if(hs !== hsLastTime) {
window.parent.postMessage({h: hs}, '*'); //指定是向父容器postmessage
hsLastTime = hs;
}
//clearCount and restart
if(startTime >= 500) {
clearInterval(loadIframeStart);
startTime = 0;
loadIframeStart = win.setInterval( function() {
setHeight();
}, 500)
}
}
};
})(window, document);

在parent.html加载完iframe之后引入如下代码

1
2
3
4
5
6
window.addEventListener("message", function(data) {
var ifmAnalyst = document.getElementById('isvIframeCon'),//目标iframe
ifmHeight = data.data.h;
//data.data.h即为高度
ifmAnalyst.style.height = ifmHeight + "px";
});

这种方法虽然很方便,但是是H5的特性,所以在使用前先考虑是否需要兼容低版本浏览器

5、服务器代理

6、flash方式

后两种方式,这里不做介绍。

github pages & hexo建站指南

1、注册github 官网

2、环境准备

3、ssh设置

  • 如果没有id_rsa.pub,生成key
1
2
3
4
$ ssh-keygen -t rsa -C "邮件地址@youremail.com"  
Generating public/private rsa key pair.  
Enter file in which to save the key (/Users/your_user_directory/.ssh/id_rsa):<回车就好>
  • 设置加密串
1
2
Enter passphrase (empty for no passphrase):<输入加密串>  
Enter same passphrase again:<再次输入加密串>
  • 有了ssh key之后,添加至github相应的配置中
    打开id_rsa.pub拷贝内容,打开github的设置页面添加key粘贴
    GitHub ssh key
  • 测试是否成功
1
$ ssh -T git@github.com
如果显示如下:
1
2
3
The authenticity of host 'github.com (207.97.227.239)' can't be established.  
RSA key fingerprint is   
Are you sure you want to continue connecting (yes/no)?
输入yes
然后会看到:
1
Hi <em>username</em>! You've successfully authenticated, but GitHub does not provide shell access.
至此,已经可以通过ssh连接到github,配置名称和邮箱:
1
2
$ git config --global user.name "你的名字"  
$ git config --global user.email "your_email@youremail.com"

4、使用github pages建立博客

[官网简易教程](https://pages.github.com/)

5、hexo构建博客

  • Node和Git都安装好了之后,安装hexo
1
npm install hexo -g
  • 初始化hexo到指定目录
1
2
3
4
mkdir blog
hexo init blog
cd blog
npm install
  • 生成静态页面
1
hexo generate
当修改文章tag或内容,不能正确重新生成内容,可以删除hexo/db.json然后重试,不行就去public下删除对应文件重新生成。
  • 本地启动服务
1
hexo server
当修改文章tag或内容,不能正确重新生成内容,可以删除hexo/db.json然后重试,不行就去public下删除对应文件重新生成。
  • 写文章
1
hexo new [layout] "new blog"
layout的默认值是scaffolds/post.md文件,看下该文件:
1
2
3
4
5
6
title: #文章页面上的显示名称,可修改
date: #文章生成时间
categories: #文章分类
tags: #文章标签,可空,多标签请用[tag1,tag2]
---
这里开始使用markdown格式输入正文
  • 当有任何修改时,只需直接刷新浏览器就可本地预览。

    6、hexo和github的关联

    打开hexo目录下的_config.yml文件,修改deploy部分:
1
2
3
4
5
deploy:
type: github
repo: 对应githubio的地址,建议用https的仓库地址
branch: master
message: update
配置完之后,每当要发布时只需执行便会自动push到github io的仓库上
1
hexo generate
1
hexo deploy

如果想要了解更多,可访问 hexo官方文档