Mou 书写格式

Mou

Mou icon

Overview

Mou, the missing Markdown editor for web developers.

Syntax

Strong and Emphasize

strong or strong ( Cmd + B )

emphasize or emphasize ( Cmd + I )

Sometimes I want a lot of text to be bold.
Like, seriously, a LOT of text

Blockquotes

Right angle brackets > are used for block quotes.

An email example@example.com link.

Simple inline link http://chenluois.com, another inline link Smaller, one more inline link with title Resize.

A reference style link. Input id, then anywhere in the doc, define the link with corresponding id:

Titles ( or called tool tips ) in the links are optional.

Images

An inline image Smaller icon, title is optional.

A Resize icon reference style image.

Inline code and Block code

Inline code are surround by backtick key. To create a block code:

Indent each line by at least 1 tab, or 4 spaces.
var Mou = exactlyTheAppIwant; 

Ordered Lists

Ordered lists are created using “1.” + Space:

  1. Ordered list item
  2. Ordered list item
  3. Ordered list item

Unordered Lists

Unordered list are created using “*” + Space:

  • Unordered list item
  • Unordered list item
  • Unordered list item

Or using “-“ + Space:

  • Unordered list item
  • Unordered list item
  • Unordered list item

Hard Linebreak

End a line with two or more spaces will create a hard linebreak, called <br /> in HTML. ( Control + Return )
Above line ended with 2 spaces.

Horizontal Rules

Three or more asterisks or dashes:




Headers

Setext-style:

This is H1

This is H2

atx-style:

This is H1

This is H2

This is H3

This is H4

This is H5
This is H6

Extra Syntax

Footnotes

Footnotes work mostly like reference-style links. A footnote is made of two things: a marker in the text that will become a superscript number; a footnote definition that will be placed in a list of footnotes at the end of the document. A footnote looks like this:

That’s some text with a footnote.[^1]

[^1]: And that’s the footnote.

Strikethrough

Wrap with 2 tilde characters:

Strikethrough

Fenced Code Blocks

Start with a line containing 3 or more backticks, and ends with the first line with the same number of backticks:

1
2
3
Fenced code blocks are like Stardard Markdown’s regular code
blocks, except that they’re not indented and instead rely on
a start and end fence lines to delimit the code block.

Tables

A simple table looks like this:

First Header Second Header Third Header
Content Cell Content Cell Content Cell
Content Cell Content Cell Content Cell

If you wish, you can add a leading and tailing pipe to each line of the table:

First Header Second Header Third Header
Content Cell Content Cell Content Cell
Content Cell Content Cell Content Cell

Specify alignment for each column by adding colons to separator lines:

First Header Second Header Third Header
Left Center Right
Left Center Right

Shortcuts

View

  • Toggle live preview: Shift + Cmd + I
  • Toggle Words Counter: Shift + Cmd + W
  • Toggle Transparent: Shift + Cmd + T
  • Toggle Floating: Shift + Cmd + F
  • Left/Right = 1/1: Cmd + 0
  • Left/Right = 3/1: Cmd + +
  • Left/Right = 1/3: Cmd + -
  • Toggle Writing orientation: Cmd + L
  • Toggle fullscreen: Control + Cmd + F

Actions

  • Copy HTML: Option + Cmd + C
  • Strong: Select text, Cmd + B
  • Emphasize: Select text, Cmd + I
  • Inline Code: Select text, Cmd + K
  • Strikethrough: Select text, Cmd + U
  • Link: Select text, Control + Shift + L
  • Image: Select text, Control + Shift + I
  • Select Word: Control + Option + W
  • Select Line: Shift + Cmd + L
  • Select All: Cmd + A
  • Deselect All: Cmd + D
  • Convert to Uppercase: Select text, Control + U
  • Convert to Lowercase: Select text, Control + Shift + U
  • Convert to Titlecase: Select text, Control + Option + U
  • Convert to List: Select lines, Control + L
  • Convert to Blockquote: Select lines, Control + Q
  • Convert to H1: Cmd + 1
  • Convert to H2: Cmd + 2
  • Convert to H3: Cmd + 3
  • Convert to H4: Cmd + 4
  • Convert to H5: Cmd + 5
  • Convert to H6: Cmd + 6
  • Convert Spaces to Tabs: Control + [
  • Convert Tabs to Spaces: Control + ]
  • Insert Current Date: Control + Shift + 1
  • Insert Current Time: Control + Shift + 2
  • Insert entity <: Control + Shift + ,
  • Insert entity >: Control + Shift + .
  • Insert entity &: Control + Shift + 7
  • Insert entity Space: Control + Shift + Space
  • Insert Scriptogr.am Header: Control + Shift + G
  • Shift Line Left: Select lines, Cmd + [
  • Shift Line Right: Select lines, Cmd + ]
  • New Line: Cmd + Return
  • Comment: Cmd + /
  • Hard Linebreak: Control + Return

Edit

  • Auto complete current word: Esc
  • Find: Cmd + F
  • Close find bar: Esc

Post

  • Post on Scriptogr.am: Control + Shift + S
  • Post on Tumblr: Control + Shift + T

Export

  • Export HTML: Option + Cmd + E
  • Export PDF: Option + Cmd + P

And more?

Don’t forget to check Preferences, lots of useful options are there.

Follow @Mou on Twitter for the latest news.

For feedback, use the menu Help - Send Feedback

React开发中关于this的那些事儿

React开发中关于this的那些事儿

在React开发,关于this以及es6中方法的书写及其使用出现一些问题

  • 在es5中, 普通用function声明的函数是定义在window对象上的,显而易见其内部的this肯定是默认指向window对象。而直接用函数名来调用得到的函数内this也是window对象。可以这么理解,那个看不见的调用者就是window

  • 在es6中,为了规范function中this的所属问题,在使用‘use strict’模式下,不显示地用window对象调用函数则其内部的this为undefined,也就是强制你使用window对象严格得去调用。

与this相关的 bind call apply 三兄弟

  1. bind通常用来重新绑定函数体中的this并返回一个具有指定this的函数。
  2. call 和 apply 则表示重新指定this并调用返回结果,区别在于call采用多个实参的方式传参,apply则是使用一个数组。

    共同点: 在于第一个参数指定为this(这里用对象描述比较合理些),作用都是用来重定向this;从第二个参数起都算作是参数传递。

    不同点: [1] 是用来返回具有特定this的函数,[2] 是用来调用函数的。而对于函数的获得,则通过其声明宿主(指所在对象,并非es6中的class类。在es6中,class和Java的类似,想要调用需要创建对象)

React中的bind

准确说,应该是es6中bind的使用,但因为在开发中常用到,就暂且以React开发为背景。
因为是返回指定this的函数,因此它的应用场景一定是函数的传递,而非函数的普通调用。在开发中,函数的传递赋值主要有以下几个场景(如有遗漏,欢迎补充):

  • 组件属性:组件内部函数的回调,通过把一个函数传递给组件的props,本质上和把函数作为实参传递给被调用函数是一致的。(至于是在Jsx中虚拟Dom中传递还是通过createElementcloneElement等React API就不多说了)
  • 高阶函数:本质上也是一种回调,就是在调用的地方提前写好即将被调用的函数并传进去,这里的‘即将’既可以是同步也可以是异步。

在以上两种情况中,组件的属性对this的依赖还是比较大的

当我们给组件属性所传递的函数中,需要使用到当前类中非静态函数或字段(这两种成员都归属于this)时就不得不使用this来调用。

使用场景一

1
2
3
4
5
6
7
8
9
10
class Foo extends Component{
render () {
return <CustomView onPress={this.readBook} />
}
readBook () {
let bookName = this.getBookName()
this.props.ooxx
this.state.ooxx
}
}

以上代码在运行时,由于this.readBook传递了一个纯函数,而该函数在CustomView类中执行时,this会被指向当前类CustomView的实例this,显而易见此时的foo、props、ooxx显然在另外一个类中是找不到的,undefined这个老朋友的如约而至也成为必然。

此时我们只需要改写传入方式为this.readBook.bind(this)即可将当前this绑定到readBook中,当然也可以绑定其他你所想要的,只要符合你的需求。

使用场景二

由于让函数调用bind会返回一个全新的函数,因此在高阶函数的某些场景下就会因为不是同一个函数(准确说是引用) 而导致出错,如监听器的注册与注销:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class PauseMenu extends Component {
constructor (props) {
super(props);
this._onAppPaused = this.onAppPaused.bind(this);
}
componentWillMount () {
AppStateIOS.addEventListener('change', this._onAppPaused);
}
componentDidUnmount () {
AppStateIOS.removeEventListener(
'change', this._onAppPaused
)
}
onAppPaused(event){
}
}

可以看到我们在构造函数里为onAppPaused函数单独绑定了this并存到当前this当中,这样在注册和注销的时候都可以保证拿到的是同一个函数对象。(这里需要注意,_onAppPaused是直接定义在this上的,因此在针对一个class new出实例后,_onAppPaused是属于实例的,而onAppPaused是定义在类里的非静态函数,在类的prototype上,实例的proto原型上的。)

在bind时传参数

这个需求,就我个人来讲是一个非常不合理的需求。高阶函数本来就是传入一个方法签名,而你非要利用bind的附加参数功能有点‘乱来’的意思了。不过也不是不可以,只需要注意此时如果在高阶函数内(或组件内) 的方法回调中本身带有参数,则在bind时禁止附加参数,否则会覆盖原有的回调参数。

Lambda表达式与匿名函数

Lambda表达式是es6中函数的一种新的声明方式,如下:

1
2
3
() => {
console.log(...)
}

以上是一个简单的Lambda表达式,在多数的Js教程中都被称作”箭头函数”,它的书面写法上等价于匿名函数,如下:

1
2
3
function () {
console.log(...)
}

他们都可以被用来在高阶函数以及组件属性上以及普通方法的定义,然而又有一些差异:

  • Lambda表达式中的this指向当前作用域的this,因此这种情况下就没有bind的事情了,因为Lambda已经有自己的this了。同bind一样,Lambda同样会返回一个全新的函数。
1
<CustomView onPress={() => this.props...} />

此时呢,Lambda表达式是直接作为回调被赋值了。因此所有的回调参数都可以在此获取到,后续与this相关的逻辑代码都可以在Lambda表达式中书写。

  • 匿名函数会因为es5、6的情况而指向window或者undefined,此时如果方法体内需要用到当前的组件的this,则可以通过bind来完成,如:
1
2
3
<CustomView onPress={function(){
this.props...
}.bind(this)} />

这样的代码等价于使用函数名bind this一样,如:

1
2
3
4
5
<CustomView onPress={this.readProps.bind(this)} />
...
readProps () {
this.props...
}

如果上边的readProps的回调没有传出一些特别的参数,也可以用Lambda表达式改为:

1
<CustomView onPress={() => this.readProps()} />

当然,这只是用箭头函数包裹了一下,我们仍然可以通过在箭头函数的参数列表中声明参数的方式来达到相同的目的。

使用Lambda表达式优化

之前提到了用bind在this中存留一份,可以在构造函数里用对象的属性来存储唯一的函数。

1
2
3
4
5
6
7
8
9
10
class PauseMenu extends Component {
componentWillMount () {
AppStateIOS.addEventListener('change', this._onAppPaused);
}
componentDidUnmount () {
AppStateIOS.removeEventListener('change', this._onAppPaused)
}
_onAppPaused = (event) => {
};
}

这样做可以将_onAppPaused 作为类属性的一部分,就不用担心拿不到方法的唯一引用啦

Lambda表达式补充:

  1. 箭头后的部分即为表达式的返回值
  2. 如果出现多条语句操作运算的,需要使用{…} 以函数体的形式书写并以显示的方式return返回值
  3. 如果需要直接返回一个Object的话,语法上会和函数体冲突,此时就必须使用()保护一下,声明此处是一个对象而非函数体
  4. 参数方面,单参数可以不加()括弧, 但是一个以上就必须要加了。同时没有参数时需要使用()来完成语法上的补位

结语

在日常开发中,this还是一个让人比较头疼的东西。方法(对象中的函数) 内函数会导致this的重定向,其他的一些对象嵌套也会导致重定向问题,因此大家不要慌,不妨尝试手动获取一下外部this。

CSS3 线性渐变(linear-gradient)

CSS3 Gradient 分为 linear-gradient(线性渐变)和 radial-gradient(径向渐变)。而我们今天主要是针对线性渐变来剖析其具体的用法。为了更好的应用 CSS3 Gradient,我们需要先了解一下目前的几种现代浏览器的内核,主要有 Mozilla(Firefox,Flock等)、WebKit(Safari、Chrome等)、Opera(Opera浏览器)、Trident(讨厌的IE浏览器)。

本文忽略IE不管,我们主要看看在 Mozilla、Webkit、Opera 下的应用,当然在 IE 下也可以实现,他需要通过 IE 特有的滤镜来实现,在后面会列出滤镜的使用语法,但不会具体介绍如何实用,感兴趣的可以搜索相关技术文档。

一、线性渐变在 Mozilla 下的应用

语法:

1
-moz-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )

参数:其共有三个参数,第一个参数表示线性渐变的方向,top 是从上到下、left 是从左到右,如果定义成 left top,那就是从左上角到右下角。第二个和第三个参数分别是起点颜色和终点颜色。你还可以在它们之间插入更多的参数,表示多种颜色的渐变。如图所示:

Mou

根据上面的介绍,我们先来看一个简单的例子:

HTML:

1
<div class="example example1"></div>

CSS:

1
2
3
4
.example {
width: 150px;
height: 80px;
}

如无特殊说明,我们后面的示例都是应用这一段 html 和 css 的基本代码。

现在我们给这个div应用一个简单的渐变样式:

1
2
3
.example1 {
background: -moz-linear-gradient( top,#ccc,#000);
}

Mou

二、线性渐变在 Webkit 下的应用

语法:

1
2
-webkit-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )//最新发布书写语法
-webkit-gradient(<type>, <point> [, <radius>]?, <point> [, <radius>]? [, <stop>]*) //老式语法书写规则

参数:-webkit-gradient 是 webkit 引擎对渐变的实现参数,一共有五个。第一个参数表示渐变类型(type),可以是linear(线性渐变)或者radial(径向渐变)。第二个参数和第三个参数,都是一对值,分别表示渐变起点和终点。这对值可以用坐标形式表示,也可以用关键值表示,比如 left top(左上角)和left bottom(左下角)。第四个和第五个参数,分别是两个color-stop函数。color-stop 函数接受两个参数,第一个表示渐变的位置,0为起点,0.5为中点,1为结束点;第二个表示该点的颜色。如图所示:

Mou

Mou

我们先来看一个老式的写法示例:

1
background: -webkit-gradient(linear,center top,center bottom,from(#ccc), to(#000));

接着我们在来看一下新式的写法:

1
-webkit-linear-gradient(top,#ccc,#000);

这个效果我就不在贴出来了,大家在浏览器中一看就明白了,他们是否一致的效果。仔细对比,在 Mozilla 和 Webkit 下两者的学法都基本上一致了,只是其前缀的区别,当然哪一天他们能统一成一样,对我们来说当然是更好了,那就不用去处理了。将大大节省我们的开发时间哟。

三、线性渐变在 Opera 下的应用

语法:

1
-o-linear-gradient([<point> || <angle>,]? <stop>, <stop> [, <stop>]); /* Opera 11.10+ */

参数:-o-linear-gradient 有三个参数。第一个参数表示线性渐变的方向,top 是从上到下、left 是从左到右,如果定义成 left top,那就是从左上角到右下角。第二个和第三个参数分别是起点颜色和终点颜色。你还可以在它们之间插入更多的参数,表示多种颜色的渐变。(注:Opera 支持的版本有限,本例测试都是在 Opera11.1 版本下,后面不在提示),如图所示:

Mou

示例代码:

1
background: -o-linear-gradient(top,#ccc, #000);

四、线性渐变在 Trident (IE) 下的应用

语法:

1
2
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr=#1471da, endColorstr=#1C85FB);/*IE<9>*/
-ms-filter: "progid:DXImageTransform.Microsoft.gradient (GradientType=0, startColorstr=#1471da, endColorstr=#1C85FB)";/*IE8+*/

IE依靠滤镜实现渐变。startColorstr表示起点的颜色,endColorstr 表示终点颜色。GradientType 表示渐变类型,0 为缺省值,表示垂直渐变,1 表示水平渐变。如图所示:

Mou

上面我们主要介绍了线性渐变在上述四大核心模块下的实现方法,接着我们主要针对线性渐变在 Mozilla、Webkit、Opera 三大模块下实现各种不同线性渐变实例:

从上面的语法中我们可以很清楚的知道,要创建一个线性渐变,我们需要创建一个起点和一个渐变方向(或角度),定义一个起始色:

1
2
3
-moz-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )
-webkit-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )
-o-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )

具体应用如下:

1
2
3
4
background:-moz-linear-gradient(left,#ace,#f96);/*Mozilla*/
background:-webkit-gradient(linear,0 50%,100% 50%,from(#ace),to(#f96));/*Old gradient for webkit*/
background:-webkit-linear-gradient(left,#ace,#f96);/*new gradient for Webkit*/
background:-o-linear-gradient(left,#ace,#f96); /*Opera11*/

效果如下:

Mou

起始点(Starting Point)的工作方式类似于 background position。您可以设置水平和垂直位置为百分比,或以像素为单位,或在水平方向上可以使用left/center/right,在垂直方向上可以使用top/center/bottom。位置起始于左上角。如果你不指定水平或垂直位置,它将默认为center。其工作方式主要包含:Top → Bottom、Left → Right、bottom → top、right → left等,接着我们主要一种一种来看其实现的效果:

1、开始于center(水平方向)和top(垂直方向)也就是Top → Bottom:

1
2
3
4
5
6
7
8
9
/* Firefox 3.6+ */
background: -moz-linear-gradient(top, #ace, #f96);
/* Safari 4-5, Chrome 1-9 */
/* -webkit-gradient(, [, ]?, [, ]? [, ]*) */
background: -webkit-gradient(linear,top,from(#ace),to(#f96));
/* Safari 5.1+, Chrome 10+ */
background: -webkit-linear-gradient(top, #ace, #f96);
/* Opera 11.10+ */
background: -o-linear-gradient(top, #ace, #f96);

效果:

Mou

2、始于left(水平方向)和center(垂直方向)也是就Left → Right:

1
2
3
4
5
6
/* Firefox 3.6+ */
background: -moz-linear-gradient(left, #ace, #f96);
/* Safari 5.1+, Chrome 10+ */
background: -webkit-linear-gradient(left, #ace, #f96);
/* Opera 11.10+ */
background: -o-linear-gradient(left, #ace, #f96);

效果如下:

Mou

3、起始于left(水平方向)和top(垂直方向):

1
2
3
background: -moz-linear-gradient(left top, #ace, #f96);
background: -webkit-linear-gradient(left top, #ace, #f96);
background: -o-linear-gradient(left top, #ace, #f96);

效果如下:

Mou

4、Linear Gradient (with Even Stops):

1
2
3
4
5
6
7
8
/* Firefox 3.6+ */
background: -moz-linear-gradient(left, #ace, #f96, #ace, #f96, #ace);
/* Safari 4-5, Chrome 1-9 */
background: -webkit-gradient(linear, left top, right top, from(#ace), color-stop(0.25, #f96), color-stop(0.5, #ace), color-stop(0.75, #f96), to(#ace));
/* Safari 5.1+, Chrome 10+ */
background: -webkit-linear-gradient(left, #ace, #f96, #ace, #f96, #ace);
/* Opera 11.10+ */
background: -o-linear-gradient(left, #ace, #f96, #ace, #f96, #ace);

效果如下:

Mou

5、with Specified Arbitrary Stops:

1
2
3
4
5
6
7
8
/* Firefox 3.6+ */
background: -moz-linear-gradient(left, #ace, #f96 5%, #ace, #f96 95%, #ace);
/* Safari 4-5, Chrome 1-9 */
background: -webkit-gradient(linear, left top, right top, from(#ace), color-stop(0.05, #f96), color-stop(0.5, #ace), color-stop(0.95, #f96), to(#ace));
/* Safari 5.1+, Chrome 10+ */
background: -webkit-linear-gradient(left, #ace, #f96 5%, #ace, #f96 95%, #ace);
/* Opera 11.10+ */
background: -o-linear-gradient(left, #ace, #f96 5%, #ace, #f96 95%, #ace);

效果如下:

Mou

6、角度(Angle):

正如上面看到的示例,如果您不指定一个角度,它会根据起始位置自动定义。如果你想更多的控制渐变的方向,您不妨设置角度试试。例如,下面的两个渐变具有相同的起点left center,但是加上一个30度的角度。

没有角度的示例代码:

1
2
3
background: -moz-linear-gradient(left, #ace, #f96);
background: -webkit-linear-gradient(left,#ace,#f96);
background: -o-linear-gradient(left, #ace, #f96);

加上30度的角度代码:

1
2
3
background: -moz-linear-gradient(left 30deg, #ace, #f96);
background: -webkit-gradient(linear, 0 0, 100% 100%, from(#ace),to(#f96));
background: -o-linear-gradient(30deg, #ace, #f96);

效果图如下:

Mou
Mou

当指定的角度,请记住,它是一个由水平线与渐变线产生的的角度,逆时针方向。因此,使用0deg将产生一个左到右横向梯度,而90度将创建一个从底部到顶部的垂直渐变。我来看看你核心代码:

1
2
3
4
background: -moz-linear-gradient(<angle>, #ace, #f96);
background: -webkit-gradient(<type>,<angle>, from(#ace), to(#f96));
background: -webkit-linear-gradient(<angle>, #ace, #f96);
background: -o-linear-gradient(<angle>, #ace, #f96);

我们来看看各角度的区别:

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
.deg0 {
background: -moz-linear-gradient(0deg, #ace, #f96);
background: -webkit-gradient(linear,0 50%,100% 50%,from(#ace),to(#f96));
background: -webkit-linear-gradient(0deg, #ace, #f96);
background: -o-linear-gradient(0deg, #ace, #f96);
}
.deg45 {
background: -moz-linear-gradient(45deg, #ace, #f96);
background: -webkit-gradient(linear,0 100%,100% 0%,from(#ace),to(#f96));
background: -webkit-linear-gradient(45deg, #ace, #f96);
background: -o-linear-gradient(45deg, #ace, #f96);
}
.deg90 {
background: -moz-linear-gradient(90deg, #ace, #f96);
background: -webkit-gradient(linear,50% 100%,50% 0%,from(#ace),to(#f96));
background: -webkit-linear-gradient(90deg, #ace, #f96);
background: -o-linear-gradient(90deg, #ace, #f96);
}
.deg135 {
background: -moz-linear-gradient(135deg, #ace, #f96);
background: -webkit-gradient(linear,100% 100%,0 0,from(#ace),to(#f96));
background: -webkit-linear-gradient(135deg, #ace, #f96);
background: -o-linear-gradient(135deg, #ace, #f96);
}
.deg180 {
background: -moz-linear-gradient(180deg, #ace, #f96);
background: -webkit-gradient(linear,100% 50%,0 50%,from(#ace),to(#f96));
background: -webkit-linear-gradient(180deg, #ace, #f96);
background: -o-linear-gradient(180deg, #ace, #f96);
}
.deg225 {
background: -moz-linear-gradient(225deg, #ace, #f96);
background: -webkit-gradient(linear,100% 0%,0 100%,from(#ace),to(#f96));
background: -webkit-linear-gradient(225deg, #ace, #f96);
background: -o-linear-gradient(225deg, #ace, #f96);
}
.deg270 {
background: -moz-linear-gradient(270deg, #ace, #f96);
background: -webkit-gradient(linear,50% 0%,50% 100%,from(#ace),to(#f96));
background: -webkit-linear-gradient(270deg, #ace, #f96);
background: -o-linear-gradient(270deg, #ace, #f96);
}
.deg315 {
background: -moz-linear-gradient(315deg, #ace, #f96);
background: -webkit-gradient(linear,0% 0%,100% 100%,from(#ace),to(#f96));
background: -webkit-linear-gradient(315deg, #ace, #f96);
background: -o-linear-gradient(315deg, #ace, #f96);
}
.deg360 {
background: -moz-linear-gradient(360deg, #ace, #f96);
background: -webkit-gradient(linear,0 50%,100% 50%,from(#ace),to(#f96));
background: -webkit-linear-gradient(360deg, #ace, #f96);
background: -o-linear-gradient(360deg, #ace, #f96);
}

效果如下:

Mou

除了起始位置和角度,你应该指定起止颜色。起止颜色是沿着渐变线,将会在指定位置(以百分比或长度设定)含有指定颜色的点。色彩的起止数是无限的。如果您使用一个百分比位置,0%代表起点和100%是终点,但区域外的值可以被用来达到预期的效果。 这也是通过CSS3 Gradient制作渐变的一个关键所在,其直接影响了你的设计效果,像我们这里的示例都不是完美的效果,只是为了能给大家展示一个渐变的效果,大家就这样先用着吧。我们接着看一下不同的起址色的示例:

1
2
3
background: -moz-linear-gradient(top, #ace, #f96 80%, #f96);
background: -webkit-linear-gradient(top,#ace,#f96 80%,#f96);
background: -o-linear-gradient(top, #ace, #f96 80%, #f96);

效果如下:

Mou

如果没有指定位置,颜色会均匀分布。如下面的示例:

1
2
3
background: -moz-linear-gradient(left, red, #f96, yellow, green, #ace);
background: -webkit-linear-gradient(left,red,#f96,yellow,green,#ace);
background: -o-linear-gradient(left, red, #f96, yellow, green, #ace);

效果如下:

Mou

7、渐变上应用透明度(Transparency):

透明渐变对于制作一些特殊的效果是相当有用的,例如,当堆叠多个背景时。这里是两个背景的结合:一张图片,一个白色到透明的线性渐变。我们来看一个官网的示例吧:

1
2
3
background: -moz-linear-gradient(right, rgba(255,255,255,0), rgba(255,255,255,1)),url(http://demos.hacks.mozilla.org/openweb/resources/images/patterns/flowers-pattern.jpg);
background: -webkit-linear-gradient(right, rgba(255,255,255,0), rgba(255,255,255,1)),url(http://demos.hacks.mozilla.org/openweb/resources/images/patterns/flowers-pattern.jpg);
background: -o-linear-gradient(right, rgba(255,255,255,0), rgba(255,255,255,1)),url(http://demos.hacks.mozilla.org/openweb/resources/images/patterns/flowers-pattern.jpg);

接着看看效果吧

Mou

关于图片的懒加载

Mou

目前,一些图片类型的网站上,在图片加载时均采用了一种名为懒加载的方式,具体表现为,当页面被请求时,只加载可视区域的图片,其它部分的图片则不加载,只有这些图片出现在可视区域时才会动态加载这些图片,从而节约了网络带宽和提高了初次加载的速度,具体实现的技术并不复杂,下面分别对其说明。首先,在页面中准备一个id为div1的div,在这个div中放一个ul,ul中准备了一些li,然而这些li都有一个data-src的属性,准备着图片的地址,具体结构如下:

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
<div id="div1">
<ul>
<li data-src="http://4493bz.1985t.com/uploads/allimg/140710/1-140G0161612.jpg"></li>
<li data-src="http://4493bz.1985t.com/uploads/allimg/140628/1-14062Q33R6.jpg"></li>
<li data-src="http://4493bz.1985t.com/uploads/allimg/140628/1-14062Q33242.jpg"></li>
<li data-src="http://img.bizhi.sogou.com/images/2014/12/10/997251.jpg"></li>
<li data-src="http://dl.bizhi.sogou.com/images/2014/12/02/986640.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170473_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170475_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170477_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
<li data-src="http://imgstore.cdn.sogou.com/app/a/100540002/1170479_s_90_2_219x160.jpg"></li>
</ul>
</div>

图片的动态加载就是通过读取li元素,然后获得li元素的data-src属性的值赋予动态创建的图片的src,从而实现了图片的创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function setImg(index){
var oDiv=document.getElementById("div1")
var oUl=oDiv.children[0];
var aLi=oUl.children;
if (aLi[index].dataset) {
var src=aLi[index].dataset.src;
} else{
var src=aLi[index].getAttribute('data-src');
}
var oImg=document.createElement('img');
oImg.src=src;
if (aLi[index].children.length==0) {
aLi[index].appendChild(oImg);
}
}

那么怎么识别是否在可视区域呢?这里需要一个函数,能够实现获得当前元素距离网页顶部的距离!

1
2
3
4
5
6
7
8
9
//获得对象距离页面顶端的距离
function getH(obj) {
var h = 0;
while (obj) {
h += obj.offsetTop;
obj = obj.offsetParent;
}
return h;
}

当网页的滚动条滚动时要时时判断当前li的位置!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
window.onscroll = function () {
var oDiv = document.getElementById('div1');
var oUl = oDiv.children[0];
var aLi = oUl.children;
for (var i = 0, l = aLi.length; i < l; i++) {
var oLi = aLi[i];
//检查oLi是否在可视区域
var t = document.documentElement.clientHeight + (document.documentElement.scrollTop || document.body.scrollTop);
var h = getH(oLi);
if (h < t) {
setTimeout("setImg(" + i + ")", 500);
}
}
};

当页面加载完成以后要主动运行一下window.onscroll,从而获得当前可视范围内的图片

1
2
3
window.onload = function () {
window.onscroll();
};

另外,像这样的页面,障眼法和美化都是必须的,比如给每个li一个loading的图片作为背景,从而实现了当前图片正在加载的效果,美化工作就是做好合理的布局。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
* {
margin: 0;
padding: 0;
}
#div1 {
width: 520px;
margin: 30px auto;
border: 1px solid red;
overflow: hidden;
}
li {
width: 160px;
height: 160px;
float: left;
list-style: none;
margin: 5px;
background: url(loading.gif) center center no-repeat;
border: 1px dashed green;
}
img{
width:100%
}

line-height,vertical-align及图片居中对齐

line-height,vertical-align及图片居中对齐问题根源解析

主要的问题如下:

  • 1.line-height是个什么东西,范围在哪里,具体应用于什么元素?

  • 2.vertiacal-align和line-height有什么关系,元素对齐到底是一个什么样的过程。

  • 3.图片对齐和文本对齐有什么区别?

  • 4.浮动元素为什么对齐会出现问题?

解答这些问题,牵涉的碎片化知识:

  • 基线,底端,行内框,行框,行间距,替换元素及非替换元素,对齐

下面围绕着上面的几个问题,以及相应的碎片化知识点来进行解析问题。

一般来说,之所以不了解vertical-align,是因为不清楚对齐后面的这些碎片化知识,而这些也是很多博客在解析的时候常常忽略的地方。

先说结论:

1.line-height是行高,主要作用是在文本上下行间距,基于文本产生影响文本元素位置的作用,对于行内元素的位置影响显著,但是对于块元素的影响甚微。

2.vertical-align和line-height的关系是:line-height是vertical-align的对齐依据。vertical-align主要是影响行内元素的对齐,不影响块元素布局。

而决定行内元素对齐的有两个因素:

  • 1.元素本身的height(类似于图片和按钮等替换元素)
  • 2.还有其他span、em非替换元素的line-height。行框通过计算height,line-height,来将各个行内元素与行内的基线进行对齐。

但是当产生浮动的时候,浮动会对行内元素的布局产生特殊影响,因此不会按照原先的方式来进行对齐,此时设置了vertical-align往往没有效果。

3.图片的对齐是将自己的底端,也就是图片的最下端与行框的默认基线进行对齐,对齐依据是底端。影响图片对齐的依据是图片的height、padding、border大小。

而文本元素,例如

<span>文本内容</span>

,则是将自身的行内框基线与行框基线进行对齐,对齐依据是基线。影响行内文本元素的依据是line-height,以及元素自身的font属性。

4.元素浮动之后实际上是从正常的文档流中除去了(因此会出现高度塌陷,父容器收缩的问题),但是同时又对文档产生着影响(最经典的就是环绕效果)。元素浮动类似于一个被除名的黑户,虽然不在土地登记簿上,但是的的确确占用一块地方,因此别的元素也不能因此占据浮动元素的空间,但是因为是黑户,所以别的元素会环绕它,好像它不存在一样。

因此此时行内元素浮动之后,浮动的规则会覆盖vertical-align的规则,这个时候设置vertical-align往往会出现问题,最典型的就是对一个段落中的图片进行浮动,然后设置vertical-align,但是发现往往不起作用。

但是文本元素浮动之后往往不会受到影响,因为line-height实际上还是作用于文本元素的,虽然文本元素的容器位置“漂”到其他位置,但是里面的文本因为line-height,仍然有行高,可以影响到行内元素的布局。

结论如何推导出来

看完这些结论,想必很多人也是一时之间有些不明白所以然,因为不同的人掌握的背景知识是不同的,而这些结论的关键恰恰是这些关键性的碎片化知识,它们起到了穿针引线的作用。下面来梳理一下,到底是怎么得出结论的。

Mou icon

1.核心问题:关于对齐

对齐涉及到两个对象,要对齐元素及对齐对象,一个对象是不可能对齐。比如平常在战队,从高往低对齐,每个人都要有一个参考系,对着参考系进行对齐。

而行内元素的对齐,除了行内元素本身,还有一个参考系,这个参考系就是行框的基线,而行框的基线依据于行内框元素的基线位置。

1.1对齐延伸问题:什么是基线?

每一个文本元素自身都会有四条线,顶线,中线,基线,底线。而基线一般是指文本元素中以x字母为准,x字母的下边缘为该文本元素的基线。

而行高则是两个文本行基线之间的距离,往往使段落产生间距。

但是也可以这样理解,行高 = 字体大小 + 上半行距 + 下半行距(其中上下半行距相等,这个等式可以从图中推导出来)

Mou icon

每一个文本元素和文本行元素,都会有一条基线,基线的位置受到文本的字体格式以及line-height的影响。

1.2对齐延伸问题:什么是行框和行内框?

Mou icon

在每一个段落行内,不同的行内元素除了包裹自身内容的内容框之外,还会自动生成一个行内框,其中没有标签包裹的文本会生成匿名行内框,不同的行内框会根据各自不同的line-height产生行间距,而行框则会刚好包括最高的顶端和最低的底端,从而来生成行框。

Mou icon

行内框的基线很好计算,但是行框的基线如何计算呢?

行框的基线是立足于行内框中基线最低的元素,也就是line-height最大的文本元素。

下面的例子,可以测试出来,当设置其中一个行内文本元素的line-height超过其他行内元素的line-height的时候,整个容器会自动扩展,位置也会往下移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>测试行框基线</title>
<style>
p{
border:1px solid red;line-height:20px;
}
span{
line-height:40px;/*可以在浏览器中取消一下,观察一下位置变动*/
}
</style>
</head>
<body>
<p>
<span>文本内容1</span>匿名文本内容<em>文本内容2</em>
<img>
</p>
</body>
</html>
1.3对齐延伸问题:什么是替换元素。

替换元素是指元素的内容本身并非文档直接表现的,换句话说,就是不同的页面中,浏览器不能确定其具体内容的元素,比如图片,按钮,因为图片的内容取决于图片引用的src属性源,按钮的类型则依据于其input类型,因此浏览器是不能确定今天img元素里面是一张美女图片,那么明天加载的页面里面img是不是一张美女图片。

除了替换元素,其他的元素就是非替换元素。非替换元素和替换元素在行框中的影响,主要是其高度计算方式,替换元素在行框中的位置是由其height,padding和border来决定,而非替换元素在行框中的位置则是其line-height和字体样式。

1.4对齐延伸问题:图片等替换元素在行框中有什么影响。

如果只有文本元素的话,那么行框是很好计算基线位置的,但是如果有图片按钮等替换元素的话,那么计算方式就会变的稍微复杂一些。

在css中,有两种高度方式,一种是height,一种是line-height,这两种会决定元素的高度和位置,对于图片等行内替换元素来说,height是行框计算的依据,line-height对图片、按钮不会产生影响。

因此,如果有图片在行内的话,那么图片的底端会对齐文本的基线。

那么,如果图片的高度高于其他行内框的整体高度,这个时候会发生什么呢?

图片会在对齐原来的行框文本基线的基础上,撑开高度,使行框最高点刚好包括图片的顶端。

因此,当p段落里面的line-height都是40px的时候,加入图片之后,行框的高度就会比没有加入图片之前多50px - 40px=10px高度,因此基线就会下移10px的高度。

1
2
3
<p style=”line-height:40px;”>
<span>文本内容1</span> <em>文本内容2</em> <img src="img/img2.png" height="50px" width="50px" alt="高度图片">
</p>
1.5对齐延伸问题:浮动对行内元素产生了什么样的影响。

设置一个元素的浮动之后,元素会从正常的文档流中去除,但是同时也会对原来的文档流产生一些影响。

可以设想一下,在长方形区域的水面上,有很多人都想要有一个固定位置的水床(浏览器盒模型布局),但是固定水床需要登记(告诉浏览器的如何布局计算)。突然有一天,有一个人想要在长方形区域的最左侧建一个水床(设置元素左浮动),它悄悄地从水底移动到最左侧,把原先的水床挤走(浮动元素会尽可能移动在到容器最高处,及最左处或最右处),在最左侧那里建了一所水床,没有登记(没有告知父容器高度,因此产生高度塌陷)。其他的人不知道,在去最左端的固定水床的时候,发现已经有人固定了,因此只能固定在它旁边(浮动会产生环绕效果,而这一点就是因为浮动元素从正常文档流中去除掉的原因)。

图片是属于替换元素,在行框中的计算中,是依据于图片的高度,如果图片进行浮动的话,对于行框来说,图片不存在了,因此,行框还是依据原来的文本行基线来计算基线,进行对齐。

因此,效果如下

1
2
3
<p style=”line-height:40px;”>
<span>文本内容1</span> <em>文本内容2</em> <img src="img/img2.png" height="100px" width="100px" alt="高度图片">
</p>

图片没有浮动:

Mou icon

图片左浮动:

Mou icon

没有图片:
Mou icon

2.对齐的过程

行内元素是默认设置的vertical-align为baseline,也就是基线对齐。当一个文本行开始渲染的时候,

  • 1.首先浏览器会找出每一个元素的类型,是替换元素还是非替换元素

  • 2.然后根据它们的height或者line-height以及字体大小来生成每个元素行内框

  • 3.确定行内框基线位置,确定行框基线位置

  • 4.根据每个元素是否设置vertical-align来进行对齐。

3.关于居中对齐

vertical-align:middle是将元素行内框的中点与父元素基线上方0.5ex处的一个点对齐,这里的1ex相对于元素的font-size来计算x字母的高度,1ex等于该字体下x的字母高度。

多数浏览器会将1ex处理为0.5em,也就是0.5倍字体大小font-size。
Mou icon

Mou icon

js数组的基本用法

js数组的用法包括创建、取值赋值、添加以及根据下标(数值或字符)移除元素等等,在本文将为大家详细介绍下,感兴趣的朋友可以参考下
1、创建数组
1
2
3
var array = new Array();
var array = new Array(size);//指定数组的长度
var array = new Array(item1,item2……itemN);//创建数组并赋值
2、取值、赋值
1
2
var item = array[index];//获取指定元素的值
array[index] = value;//为指定元素赋值
3、添加新元素
1
2
3
array.push(item1,item2……itemN);//将一个或多个元素加入数组,返回新数组的长度
array.unshift(item1,item2……itemN);//将一个或多个元素加入到数组的开始位置,原有元素位置自动后移,返回 新数组的长度
array.splice(start,delCount,item1,item2……itemN);//从start的位置开始向后删除delCount个元素,然后从start的位置开始插入一个或多个新元素
4、删除元素
1
2
3
array.pop();//删除最后一个元素,并返回该元素
array.shift();//删除第一个元素,数组元素位置自动前移,返回被删除的元素
array.splice(start,delCount);//从start的位置开始向后删除delCount个元素
5、数组的合并、截取
1
2
array.slice(start,end);//以数组的形式返回数组的一部分,注意不包括 end 对应的元素,如果省略 end 将复制 start 之后的所有元素
array.concat(array1,array2);//将多个数组拼接成一个数组
6、数组的排序
1
2
array.reverse();//数组反转
array.sort();//数组排序,返回数组地址
7、数组转字符串
1
array.join(separator);//将数组原因用separator连接起来

其次,数值型的直接传递数值的参数即可。例如var arr = [“aa”,”bb”];arr.del(0);
下面说一下字符型的下标

1
2
var arr = [].
arr["aa"] = 1;

react-native-icons的简单使用

react-native-vector-icons的简单使用,图片,按钮,标签视图,导航条

icons是可以直接使用图片名, 就能加载图片的三方,使用很方便, 你不需要在工程文件夹里塞各种图片, 节省很多空间,下面就来看看怎么使用吧!

1.首先打开终端进入到我们的工程文件夹下输入

npm install react-native-vector-icons --save (回车)

npm install rnpm -g

rnpm link (回车)  

2. 在Finder中用Xcode打开工程: …/Demo/ios/Demo.xcodeproj

(1).右键工程文件Add Files to “(你工程名)”
(2).选择node_modules/react-native-vector-icons/Fonts文件
(3).点击”完成”.

Mou icon

Mou icon

3. 在xcode的Info.plist文件中,加入: Fonts provided by application数组,并加入以下9项:

Mou icon

到此环境就算设置好了, 接下来就是使用ICONS了.

4. 在Finder中右键用Atom打开工程:

Mou icon

5.然后就开始编辑我们的程序了:

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
'use strict';
import React, {
AppRegistry,
Component,
View,
StyleSheet,
AlertIOS,
Text,
TabBarIOS,
NavigatorIOS,
} from 'react-native';
var Icon = require('react-native-vector-icons/FontAwesome');
import FindComponent from './FindComponent';
import SearchComponent from './SearchComponent';
class Demo extends Component {
state = {
selectedTab: 'find',
};
loginWithFacebook = () => {
//点击"Login with Facebook"按钮后触发的方法
AlertIOS.alert("facebook");
}
render() {
return (
<View style={styles.container}>
<Icon
name="rocket" //图片名连接,可以到这个网址搜索:http://ionicons.com/, 使用时:去掉前面的 "icon-" !!!!
size={30} //图片大小
color="red" //图片颜色
/>
<Icon.Button //在图片后加文字
name="facebook"
backgroundColor="#3b5998"
onPress={this.loginWithFacebook} //点击该按钮后触发的方法
>
Login with Facebook
</Icon.Button>
<Icon.Button //在图片后加, 自定义样式的文字
name="facebook"
backgroundColor="#3b5998">
<Text style={{fontFamily: 'Arial', fontSize: 15}}>Login with Facebook</Text>
</Icon.Button>
<TabBarIOS //和标签视图一起使用
tintColor="#4977f0"
barTintColor="#E6E6E6">
<Icon.TabBarItem //用 Icon.TabBarItem 代替 TabBarIOS.Item
title="发现"
iconName="home"
selectedIconName="home"
selected = {this.state.selectedTab === 'find'}
onPress={() => {
this.setState({
selectedTab: 'find',
});
}}
>
<NavigatorIOS //导航栏
style={styles.container}
tintColor='#FFFFFF'
barTintColor='#4977f0'
initialRoute={{
title: "发现",
titleTextColor: 'white',
component: FindComponent
}}
/>
</Icon.TabBarItem>
<Icon.TabBarItem //用 Icon.TabBarItem 代替 TabBarIOS.Item
title="搜索"
iconName="search"
selectedIconName="search"
selected = {this.state.selectedTab === 'search'}
onPress={() => {
this.setState({
selectedTab: 'search',
});
}}
>
<NavigatorIOS
style={styles.container}
tintColor='#FFFFFF'
barTintColor='#4977f0'
initialRoute={{
title: "搜索",
titleTextColor: 'white',
component: SearchComponent
}}
/>
</Icon.TabBarItem>
</TabBarIOS>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
});
AppRegistry.registerComponent('Demo', () => Demo);

在terminal中的工程文件夹下,输入react-native run-ios(回车)等待程序运行起来就能看到效果啦.

主要代码下载地址: http://download.csdn.net/detail/margaret_mo/9512769

参考网站: https://github.com/oblador/react-native-vector-icons

ReactNative准备:环境的创建和应用

配置相关环境,点击下面两个网址,打开终端,按要求安装要下面4个环境:

官网:https://facebook.github.io/react-native/docs/getting-started.html#content

中文网:http://reactnative.cn/docs/0.24/getting-started.html#content

这里仅列出了OS X操作系统的环境安装, window的可以自己查看上面给出网址里有.

Mon icon

重要安装命令如下:

1.安装homebrew,在终端输入:

/usr/bin/ruby -e "$(curl -fsSLhttps://raw.githubusercontent.com/Homebrew/install/master/install)"
2.安装watchman:(监测文件变化的工具)
brew install --HEAD watchman
3.安装node:
brew install node
4.安装flow:(监测CSS语法的工具)
brew install flow

之后是安装ReactNative:

5.安装ReactNative:
npm install -g react-native-cli
6.初始化应用:
react-native init ReactNative_1 (你需要的工程名)
7.运行应用:(这里假设你已安装了Xcode,有simulator虚拟机)
react-native run-ios

到此环境已经搭建完毕,可以运行ReactNative程序了

vue.js

Vue.js双向绑定的实现原理


Vue.js最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。本文仅探究几乎所有Vue的开篇介绍都会提到的hello world双向绑定是怎样实现的。先讲涉及的知识点,再参考源码,用尽可能少的代码实现那个hello world开篇示例

一、访问器属性


访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过defineProperty()方法单独定义。

var obj = { };

   // 为obj定义一个名为hello的访问器属性

   Object.defineProperty(obj, "hello", {

     get: function () {return sth},

     set: function (val) {/* do sth */}

   })

   obj.hello // 可以像普通属性一样读取访问器属性

   访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。

   obj.hello // 读取属性,就是调用get函数并返回get函数的返回值
   obj.hello = "abc" // 为属性赋值,就是调用set函数,赋值其实是传参

Mou

get和set方法内部的this都指向obj,这意味着get和set函数可以操作对象内部的值。另外,访问器属性的会"覆盖"同名的普通属性,因为访问器属性会被优先访问,与其同名的普通属性则会被忽略(也就是所谓的被"劫持"了)。

二、极简双向绑定的实现


Mou

此例实现的效果是:随文本框输入文字的变化,span中会同步显示相同的文字内容;在js或控制台显式的修改obj.name的值,视图会相应更新。这样就实现了model =>view以及view => model的双向绑定,并且是响应式的。

Mou

以上就是Vue实现双向绑定的基本原理。

三、分解任务


上述示例仅仅是为了说明原理。我们最终要实现的是:

Mou

首先将该任务分成几个子任务:

1、输入框以及文本节点与data中的数据绑定

2、输入框内容变化时,data中的数据同步变化。即view => model的变化。

3、data中的数据变化时,文本节点的内容同步变化。即model => view的变化。

要实现任务一,需要对DOM进行编译,这里有一个知识点:            DocumentFragment。

四、DocumentFragment


DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点,当我们将它插入到DOM中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。使用DocumentFragment处理节点,速度和性能远远优于直接操作DOM。Vue进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持)到DocumentFragment中,经过一番处理后,再将DocumentFragment整体返回插入挂载目标。

Mou
Mou

五、数据初始化绑定


Mou

Mou

Mou

以上代码实现了任务一,我们可以看到,hello world已经呈现在输入框和文本节点中。

Mou

六、响应式的数据绑定


再来看任务二的实现思路:当我们在输入框输入数据的时候,首先触发input事件(或者keyup、change事件),在相应的事件处理程序中,我们获取输入框的value并赋值给vm实例的text属性。我们会利用defineProperty将data中的text劫持为vm的访问器属性,因此给vm.text赋值,就会触发set方法。在set方法中主要做两件事,第一是更新属性的值,第二留到任务三再说。

Mou

Mou

任务二也就完成了,text属性值会与输入框的内容同步变化:

Mou

七、订阅/发布模式(subscribe&publish)


text属性变化了,set方法触发了,但是文本节点的内容没有变化。如何让同样绑定到text的文本节点也同步变化呢?这里又有一个知识点:订阅发布模式。

订阅发布模式(又称观察者模式)定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。

发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应操作

Mou

之前提到的,当set方法触发后做的第二件事就是作为发布者发出通知:“我是属性text,我变了”。文本节点则是作为订阅者,在收到消息后执行相应的更新操作。 

八、双向绑定的实现


回顾一下,每当new一个Vue,主要做了两件事:第一个是监听数据:observe(data),第二个是编译HTML:nodeToFragement(id)。
在监听数据的过程中,会为data中的每一个属性生成一个主题对象dep。
在编译HTML的过程中,会为每个与数据绑定相关的节点生成一个订阅者watcher,watcher会将自己添加到相应属性的dep中。
我们已经实现:修改输入框内容 => 在事件回调函数中修改属性值 => 触发属性的set方法。
接下来我们要实现的是:发出通知dep.notify() => 触发订阅者的update方法 => 更新视图。
这里的关键逻辑是:如何将watcher添加到关联属性的dep中。

Mou

在编译HTML过程中,为每个与data关联的节点生成一个Watcher。Watcher函数中发生了什么呢?

Mou

首先,将自己赋给了一个全局变量Dep.target;

其次,执行了update方法,进而执行了get方法,get的方法读取了vm的访问器属性,从而触发了访问器属性的get方法,get方法中将该watcher添加到了对应访问器属性的dep中;

再次,获取属性的值,然后更新视图。

最后,将Dep.target设为空。因为它是全局变量,也是watcher与dep关联的唯一桥梁,任何时刻都必须保证Dep.target只有一个值。

Mou

Mou

Mou

至此,hello world双向绑定就基本实现了。文本内容会随输入框内容同步变化,在控制器中修改vm.text的值,会同步反映到文本内容中。    

Flex布局教程

一、Flex布局是什么?

Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。

任何一个容器都可以指定为Flex布局。

.box{
display: flex;
}

行内元素也可以使用Flex布局。

.box{
display: inline-flex;
}

Webkit内核的浏览器,必须加上-webkit前缀。

.box{
display: -webkit-flex; /* Safari */
display: flex;
}

注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。

二、基本概念


采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。
mou

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。

项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。

三、容器的属性


以下6个属性设置在容器上。

·flex-direction
·flex-wrap
·flex-flow
·justify-content
·align-items
·align-content

3.1 flex-direction属性


flex-direction属性决定主轴的方向(即项目的排列方向)。

.box {
flex-direction: row | row-reverse | column | column-reverse;
}

Mou

它可能有4个值。

·row(默认值):主轴为水平方向,起点在左端。
·row-reverse:主轴为水平方向,起点在右端。
·column:主轴为垂直方向,起点在上沿。
·column-reverse:主轴为垂直方向,起点在下沿。

3.2 flex-wrap属性


默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

Mou

.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}

它可能取三个值。

(1)nowrap(默认):不换行。

Mou

(2)wrap:换行,第一行在上方。

Mou

(3)wrap-reverse:换行,第一行在下方。

Mou

3.3 flex-flow


flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

.box {
flex-flow: <flex-direction> || <flex-wrap>;
}

3.4 justify-content属性


justify-content属性定义了项目在主轴上的对齐方式。

.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}

Mou

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。

·flex-start(默认值):左对齐
·flex-end:右对齐
·center: 居中
·space-between:两端对齐,项目之间的间隔都相等。
·space-around:每个项目两侧的间隔相等。所以,项目之间的间隔    ·比项目与边框的间隔大一倍。

3.5 align-items属性


align-items属性定义项目在交叉轴上如何对齐。

.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}

Mou

它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

·flex-start:交叉轴的起点对齐。
·flex-end:交叉轴的终点对齐。
·center:交叉轴的中点对齐。
·baseline: 项目的第一行文字的基线对齐。
·stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

3.6 align-content属性


align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

.box {
 align-content: flex-start | flex-end | center | space-between | space-around | stretch;
 }

Mou

该属性可能取6个值。

flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。

四、项目的属性


以下6个属性设置在项目上。

order
flex-grow
flex-shrink
flex-basis
flex
align-self

4.1 order属性


order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

.item {
order: <integer>;
}

Mou

4.2 flex-grow属性


flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

.item {
flex-grow: <number>; /* default 0 */
}

Mou

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

4.3 flex-shrink属性


flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

.item {
flex-shrink: <number>; /* default 1 */
}

Mou

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

4.4 flex-basis属性


flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

.item {
flex-basis: <length> | auto; /* default auto */
}

它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。

4.5 flex属性


flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

.item {
 flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
 }

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

4.6 align-self属性


align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

.item {align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

Mou

该属性可能取6个值,除了auto,其他都与align-items属性完全一致。