写在星期一之前

心情记事

我想给自己做一个上面这样的表情,因为一个星期又要过完了,而我又把任务拖到下一个星期,然后假装下面这样的表情,显得无辜又可怜。

图片

在星期日的晚上仔细一想,还真是这样,然后本着无所谓的态度,高高兴兴上学去!

上学去啦

这就是我的常态,患了拖延症

我病了,月初患的感冒还不见痊愈,精神萎靡。
我病了,得了一种叫拖延症的病,不容易治愈!
我病了,找不到方向,就快要迷失方向!

当我病入膏肓的时候,最悲哀的是,我还以为自己还有救!

然后…明天启程去苏州了,无论是旅游也好,只希望好好享受这个过程,不虚此行!

细细想来,我的确还有事件自救,因为上面的总总根本就没发生在我身上!

可是,像我这样,离发生还远吗?

对,还有时间,去改变!

分享到 评论

浅谈JS闭包

变量的作用域

了解JS的人都知道,在ES6之前JavaScript中只有函数作用域和全局作用域,而没有块级作用域(try…catch是一个例外)。该怎么理解这句话呢?我们先来看一个例子:

1
2
3
4
for(var i=0; i<5; i++){
console.log(`i=${i}`)
}
console.log(i) // 4

当运行完一个for循环后,i=4。由于JS中不存在块级作用域,所以这里在for循环中申明的变量i是一个全局变量,因此可以在外部访问到。
现在我们来看下一个例子:

1
2
3
4
5
6
7
8
9
function init(){
var name = 'limoer';
function sayHello(){
console.log(`hello ${name}`)
}
sayHello();
}
init(); // hello limoer
console.log(name); // undefined

这里我们定义了一个函数,函数中申明了一个局部变量name,并且在函数内部定义了一个内部函数sayHello,这个函数只能在函数init内使用,然而sayHello并没有自己的局部变量,但是其可以访问到函数外部的变量,即其父级函数的name变量

通过上面的两个例子可以清楚的知道,变量的作用域完全是由它在源代码中的位置决定的,并且嵌套的函数也可以访问其外层作用域中的变量。

闭包

闭包和变量的作用域息息相关。现在我们来修改上面的这个例子

1
2
3
4
5
6
7
8
9
function init(){
var name = 'limoer';
function sayHello(){
console.log(`hello ${name}`)
}
return sayHello
}
var sayHelloFunc = init();
sayHello(); // hello limoer

注意修改的地方,我们这次是直接返回这个内部函数,然后在外部执行这个函数。
但是,通常来说,当函数一旦运行完成,其局部变量就不可用了,在这里是当执行了var sayHelloFunc = init();后name应该不可用了。但是实际运行情况是成功访问到了name这个属性。

原因是因为这里sayHelloFunc已经成为了一个闭包。它由两部分组成,返回的函数本身以及创建该函数的环境。
而所谓的环境是由闭包在创建时其作用域内的变量组成的。对于上面的这个例子,这里的变量就是指的name

再看一个闭包的例子

1
2
3
4
5
6
7
8
9
function addSome(num){
return function(y){
console.log(num + y)
}
}
var add10 = addSome(10);
var add1 = addSome(1);
add10(1); // 11
add1(10); // 11

对于上面的这个例子,addSome()做为一个函数工厂产生了两个闭包,它们共享了函数的定义,但是却又保存了不同的环境。

闭包的应用

通过上面的描述,知道闭包其实就是将函数和其作用环境相互关联起来,达到保存变量的目的。

把上面的例子稍微改一下,我们可以把它用到实践中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<button id="toBlue">切换背景为蓝色</button>
<button id="toYello">切换背景为黄色</button>
<button id="toGreen">切换背景成绿色</button>
<script type="text/javascript">
function changeBgColorTo(type){
return function(){
document.body.style.backgroundColor = type;
}
};
var toBlue = changeBgColorTo('blue');
var toYellow = changeBgColorTo('yellow');
var toGreen = changeBgColorTo('green');
document.getElementsById('toBlue').addEventListener('click', toBlue);
document.getElementsById('toYellow').addEventListener('click', toYello);
document.getElementsById('toGreen').addEventListener('click', toGreen);
</script>
</body>
</html>

上面的例子展示了如何使用闭包来定义公共函数,来减少代码的冗余。

一个常见的错误,使用闭包来解决

直接贴代码吧:
html:

1
2
3
4
<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>

js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function showHelp(help) {
document.getElementById('help').innerHTML = help;
}

function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];

for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = function() {
showHelp(item.help);
}
}
}
setupHelp();

上面的代码是我们实际开发过程中非常常见的错误。我们使用循环来给每一个输入框绑定一个事件,从而实现当聚焦到不同的输入框是产生不同的输出。
但是,上面的代码显然不能完成这样的工作,因为当循环完成后,此时item已经指向了helpText的最后一项,而给onfocus绑定的是一个匿名函数,当聚焦到某一个输入框时,执行showHelp(item.help)而item早已是helpText中的最后一项了,所以造成了错误.

知道错误后,我们就知道改怎样修改了。我们需要保存运行时的环境,返回一个闭包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];

for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = (function(help) {
return function(){
showHelp(help)
}
})(item.help);
}
}

好了,简单的对于闭包的介绍就到这里了!
想更系统的学习JS点击这里

分享到 评论

踩过React表单的坑后有感

如题所示,最近捣鼓React表单踩坑了,才捣鼓没多少时日,心就变浮躁了,开始看不下去文档,也不谷歌百度直接开码,然后就是各种报错,越报错心越急越得不到解决心情越差,好不容易静下心来搜集资料准备搞定表单,这里先记下来,以备不时只需!

踩过的坑…

直接开写吧:

input标签忘记闭合导致报错

1
2
3
4
5
6
var SimpleComp = React.createClass({
render(){
return <input type="text" placeholder="随便输入点什么吧!">
}
});
ReactDOM.render(<SimpleComp />, document.body)

运行上面的这段代码,发现并页面渲染异常,打开浏览器console一看,下面的出现了错误,并且是下面这样的:

报错图片

清清楚楚明明白白,标签并没有闭合,并且直指9行行最后渲染出了问题,然后我就一直找一直找,没错误啊,可始终还是报错
最后经过各种尝试才知道,input标签要强制闭合的,不然就会转换错误
知道真相的我眼泪掉下来,原来是这么回事啊,平时html写得飞起,细节这些什么的,都没注意哎!
再有,控制台上打印的异常和错误可千万别轻信,以前已经在这个被坑过了

受控与不受控

有过React基础的童鞋都知道,React内部通过props和state来传递属性和状态,其中属性经由组件外属性传入,作用于组件后无法改变
state 产生于组件内部, 通过setState()来改变状态,每一次改变状态,组件将会被重绘
对于表单来说,props和state用得都很频繁,所以在这里提及一下

先来看非受控组件吧,顾名思义就是组件的状态不受控制,从代码上体现出来的就是,一个input不含有value属性

1
2
3
4
5
6
var NotControlComp = React.createClass({
render() {
return <input type="text" defaultValue={this.props.placeholder}/>
}
});
ReactDOM.render(<NotControlComp placeholder='随便输入点什么吧!' />, document.body)

上面的一段代码定义了一个非受控的input,接受用户的输入而改变状态
注意:这里使用到的defaultValue属性作用类似于placeholder属性

好吧,事实上我们使用非受控组件的情况比较多,我们会监听input的onChange时间,通过state来更新状态
下面是一个简单的获取用户输入的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var ExampleComp = React.createClass({
getDefaultProps(){
return{placeholder: '输入吧'}
},
getInitialState(){
return{
val: ''
}
},
handleChange(e){
this.setState({val: e.target.value})
},
render(){
return(
<div>
<input type="text" defaultValue={this.props.val} onChange={this.handleChange}/>
<p>你输入了:{this.state.val}</p>
</div>
)
}
});
ReactDOM.render(<ExampleComp placeholder='随便输入点什么吧!' />, document.body)

那么受控组件就很显而易见了,受控的input定义了一个value属性,并且value部位null

1
2
3
4
5
6
var ControlComp = React.createClass({
render(){
return <input type="text" value="不要尝试修改这个值啦!" />
}
});
ReactDOM.render(<ControlComp />, document.getElementById('app'))

好了,最简单的受控组件就写好了,当你尝试去修改表单中的值的时候,发现根本无法修改
这点明显和我们平时写html不一样,同样的input标签在html中就可以修改但是到了react中就没办法修改了,想过原因吗?
官方文档中给出了答案: 不比HTML,React组件必须在任何时间点呈现视图的状态而不仅仅是在初始化的时候, 好好理解!

其他

  1. 不要通过添加子节点的方式给<textarea>添加内容,应该使用defaultValue或者value属性,避免产生歧义,因为JSX本身就是javascript

  2. 你可以通过selected属性来选中一个下拉栏, 但是为了组件的可操作性,请使用value 或者 defaultValue来代替就像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var SelectComp = React.createClass({
    render(){
    return(
    <select value='B'>
    <option value='A'>A</option>
    <option value='B'>A</option>
    <option value='C'>A</option>
    </select>
    )
    }
    });
    ReactDOM.render(<SelectComp />, document.body)

    想要非受控组件的话,就使用defaultValue属性好了
    当然了,可以通过传入一个数组来达到多选的目的, 前提是给select添加multiple={true}就可以了

看到这里,也许有人心里还有疑问,受控的组件既然不能修改那到底该怎么用?
对于这个问题,请看下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var ControlComp = React.createClass({
getInitialState(){
return{value: 0}
},
handleClick(e){

this.setState({value: this.state.value + 1})
},
render(){
return (
<div>
<input type="text" value={this.state.value} />
<button onClick={this.handleClick}>+</button>
</div>
)
}
});
ReactDOM.render(<ControlComp />, document.body)

好了,我们添加了一个button来控制受控组件的值,当然还有很多方式,比如我们可以给受控组件添加一个onChange事件监听

好了,React表单的基本知识就说到这里,感谢那些曾经让我烦躁无比的坑!

分享到 评论

在React中使用mixin

mixin到底为何方神圣?

mixin被理解为‘混入’的意思,
我们知道,如果你经常使用某一段相同的代码的时候,你会把它进行抽象,封装成类或者function,
‘混入’也一样,它可以解决代码段重复的问题。

jade中的Mixins

jade(pug)是一个高性能的模版引擎,它使用javascript实现,并提供给Node使用.
我在使用Jade模版引擎接触到了Mixin, 下面给出一个例子理解下

1
2
3
4
5
6
7
8
9
10
mixin box(styles)
.conponent
-each style in styles
.squire
-var x = styles.indexOf(style) + 1;
a(href='/users/' + x + '/list') #{style}
.container
mixin(['lin', 'limoer'])
.links
mixin(['parents', 'classmates', 'others'])

你可以无视jade的语法,如果你想学习jade,点这里

首先我使用mixin 关键字申明了一个带参数mixin结构,然后依据传入的参数生成了很多url
这个mixin 结构可以在这个模版文件中使用,通过不同的参数来生成url
从上面可以看出,mixin的确可以解决代码重复的问题

React中的Mixin

首先来写一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var TimerComp = React.createClass({
getInitialState: function() {
return {secondsElapsed: 0}
},
tick: function() {
this.stateState({secondsElapsed: this.state.secondsElapsed + 1})
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000)
},
componentWillUnmount: function() {
clearInterval(this.interval)
},
render: function(){
return (
<div>
<p>Seconds Elapse {this.state.secondsElapsed}</p>
</div>
)
}
});

简单的说一下,这里定义了一个定时器组件,会随着时间的增加来自动计时
但是一个应用需要多个计时器呢?我们第一时间想到了组件的嵌套,但是组件的嵌套不但会增加组件的复杂程度
而且,想要修改计时器也是比较困难的
好了,解决代码复用的问题,我们可以使用Mixin, 让其混入进其他组件就好了

码起,还是计时器的例子!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var MixinTimerComp = React.createClass({
mixins: [MixinInterval(1000)],
getInitialState: function() {
return {secondsElapsed: 0}
},
onTick: function(){
this.setState({secondsElapsed: this.state.secondsElapsed + 1})
},
render: function(){
return (
<div>
<p>Seconds Elapse {this.state.secondsElapsed}</p>
</div>
)
}
});

这里我们使用了mixins属性,把自定义的MixinInterval对象混入了Timer组件

来看看MixinInterval的实现:

1
2
3
4
5
6
7
8
9
10
var MixinInterval: function(interval) {
return {
componentDidMount() {
this.__interval = setInterval(this.onTick, interval)
},
componentWillUnmount() {
clearInterval(this.__interval)
}
}
};

就这样实现了一个最简单的问题,和最前面的例子做对比,我们发现,只是把组件中一些代码独立出来成为一个mixin对象
但这样做无疑是解决了代码重用的问题,当我们想定义另一个计时器时候,我们只需混入这个mixin代码
而不必关心混入的计时处理对象是怎么实现的

mixin 实现起来非常简单,React也支持多个mixin的混入(在mixins赋值为一个mixin对象数组)
但有一个问题需要注意,在mixin中尝试覆盖state中定义的键的话,React会抛出错误

1
2
3
4
5
6
7
8
9
10
11
React.createClass({
mixins: [{
getInitialState(){
return {cover: 1}
}
}],
getInitialState(){
return {cover: 2}
}
})
// 错误,尝试覆盖cover属性
分享到 评论

React学习之JSX

什么是JSX?

简单点说,JSX是对javascript的扩展,语法类似于XML,但JSX不是一门新的语言,
确切来说只是语法糖,每一个XML都会被响应的转换工具转换成纯的javascript代码。
在使用React时,你没有必要使用JSX来构建组件,但是推荐使用JSX,因为这样可以让组件的结构
和组件之间的关系看起来更清晰。

好了,开始使用JSX吧!

首先我们分别使用JSX和纯js来渲染一个组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// 使用JSX
ReactDOM.render(
<div>
<h2>使用了JSX语法糖</h2>
</div>,
document.body
)
// 不使用jsx
ReactDOM.render(
React.createElement('div', null,
React.createElement('h1', null, '不使用jsx')
),
document.body
)

html标签和React组件

ReactDOM.render()可以渲染html标签,也可以渲染React组件,但是这里有一些命名上的规范

html标签使用首字母小写的方式,但使用首字母大写也能够正常加载

1
2
var renderDiv = <div>这是一个标签</div>
ReactDOM.render(renderDiv, document.body)

React组件使用首字母大写的方式

1
2
3
4
5
6
var RenderComp = React.createClass({
render: function(){
return: <div>这是一个组件</div>
}
});
ReactDOM.render(<RenderComp />, document.body)

经过测试,发现如果使用首字母小写的方式,将不会正常渲染组件,也不会报错, 当然你也可以这样写:

1
2
3
4
5
6
7
var RenderComp = React.createClass({
render: function(){
return: <div>这是一个组件</div>
}
});
var renderComp = <RenderComp />
ReactDOM.render(renderComp, document.body)

js表达式

当我们想要在React中使用js变量或者是表达式时候,使用{}来进行包裹,不能够出现””,否则会被当作字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var SampleComp = React.createClass({
getInitialState: function(){
return {
iscls: false;
}
},
render: function(){
return (
// 表达式
<div className={this.state.iscls ? 'cls' : 'no_cls'}>
// 变量
<h2>{this.props.msg}</h2>
</div>
)
}
});
ReactDOM.render(<SampleComp msg='学习搬砖中...' />, document.body)

这里提示一下,在JSX中,标签的class和for属性分别使用className和htmlFor代替了

其它

在给标签添加style属性的时候,应该这样写:

1
style={{display: 'none'}}

也可以把要应用的样式赋值给一个变量,再使用变量

1
2
3
4
5
var style = {
color: red,
display: none
};
<div style={style}></div>

HTML转义,为了防止XSS攻击,React默认是使用转义的,所以当你想使用一些富文本这里就必须注意
为了不让其转义,我们可以这样写:

1
2
3
4
5
6
var mesg = '<h2>这里的字体大小是多少?</h2>'
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: mesg}}>
</div>,
document.body
)

总结

刚开始学习React的时候对JSX是生畏的,以为会很难理解。当慢慢的接触React,踩过一些小坑,
发现使用JSX是那么好掌握, 它仅仅是语法糖而已,并且转换的规则也很简单

分享到 评论

写在正式学习React之前

如果你还不知道大名鼎鼎的ReactJS, 先去这里看看吧

在使用过了诸如BootStrap, Foundation这类的前端框架后,在初识React就被其虚拟DOM和组件化的开发深深的吸引。
然后在接下来的几天,我慢慢的对React产生的恐惧,模式转变得太快,让我很不舒服。
然后又经过几天玩坏了,我才返现React简直是一股清流,开始爱上它了!

好了,开始使用React吧!

安装React

请先安装Node和npm

使用React之前,先来安装一下bower

1
$ npm install -g bower

安装bower后我们来正式的进入React的学习中来

新建一个目录

1
$ mkdir proj

使用以下命令来安装React

1
$ bower install react

安装完后我们在proj目录下会看见一个bower_components目录,目录里面有一个React目录,ok!

1
$ touch index.html

使用文本编辑器打开index.html, 开始码起!

第一个React helloworld

引入react.js和react-dom.js(在head,或者body中引入都可以,但是必须在我们开写地方的上面)

就像这样
引入图片

接着申明一个script标签

1
<script type="text/babel"></script>

注意这里的type是text/babel

1
2
3
4
5
6
7
8
9
10
var HelloWorldComponent = React.createClass({
render: function(){
return (
<div id="app">
<h1>开始学习使用工具搬砖啦!</h1>
</div>
)
}
});
ReactDOM.render(<HelloWorldComponent />, document.body)

好了,不出意外的话,我们将会在浏览器中看到
结果图

好啦,我们的第一个react组件算是开发完成了,这里讲一讲我们到底做了什么
首先我们使用了JSX语法,有关JSX的知识会单独的加深了解,但是最基本的规则就是,遇到{}解析成js,遇到‘<’解析成html
然后使用了React提供的createClass来创建一个组件类,类名一定要大写,实现了其中一个必须要实现的render方法,返回一个h1标签
最后使用ReactDOM.render()渲染到body中去
搞定

分享到 评论

依偎

这么晚起床,还不见阳光!

Scenery

以最快的速度看完了《依偎》,结局太出乎意料,细细想来却有觉得情理之中。
随心所欲的在图书馆借的书,越看越有味道,以至于,我竟然忘了自己还要学习搬砖…
太不真实的两人相遇,相识,从喝藤香茶到寻找虚无飘渺的“藤乡”

在一口气读完整本书之后,心里面有一种说不出的滋味,甜甜的,又有些萧索。我想,在最后的最后,“我”会静静地看着安芬,不再去想那虚无缥缈的藤乡,因为,有你在的地方,就是最美的“藤乡”,在那一刻,“我们”相对笑着,往日的种种都不再重要,重要的是,你我此刻,紧紧依偎。

分享到 评论