期末考完了,春活也全甲全船了,来继续更这个没人看的系列

我的前端写的很丑,就不提CSS了……

前端

React

React是Facebook开源的一个前端框架,它把本来应该写在HTML文件中的HTML语句放到JS中,HTML结构不是由浏览器直接下载解析,而是执行JS语句之后才会生成,再交给浏览器解析。那么相比于传统的HTML+JS的结构,React这种框架有什么优势呢,以下的链接可能会有帮助:

  • https://facebook.github.io/react/blog/2013/06/05/why-react.html
  • https://blog.syncano.io/reactjs-reasons-why-part-1/

从我这个初学者的角度来说,React的组件化开发方式相比于HTML的树状结构在结构上更清晰,开发效率也更高,更接近传统桌面应用程序的结构。对于页面结构(也就是HTML的结构)的变化更容易处理,适合构建单页应用

React文档地址:https://facebook.github.io/react/docs/hello-world.html

初始化React应用程序

安装指引:https://facebook.github.io/react/docs/installation.html

1
2
3
4
5
npm install -g create-react-app
create-react-app frontend

cd frontend
npm start

我当前的React版本

1
2
3
4
"dependencies": {
"react": "^15.5.4",
"react-dom": "^15.5.4"
},

最后的npm start会启动一个HTTP调试服务器,访问http://localhost:3000可以看到初始页面。运行npm run build可以在build/static目录下编译出静态js和css文件。

虽然React把HTML放在了JS中,但是还是要有一个最简单的HTML文件作为基础,这个文件在public/index.html。这个文件很简单,body标签中只有一个id="root"div标签,整个过程中我们基本不需要修改这个文件,我们的主要目标在src目录中。

渲染组件

src目录中有一个index.js文件,该文件调用ReactDOM.render来进行组件的渲染。

1
2
3
4
5
6
7
8
9
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';

ReactDOM.render(
<App />,
document.getElementById('root')
);

App.js中创建了一个继承ComponentApp类,并把它导出。这个类中的render()方法返回了HTML文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}

export default App;

增加组件

创建一个Chatroom.js文件用于保存聊天室js代码。页面上显示三个component:标题,消息列表,发送消息的表单。所以先创建一个Chatroom类,它再创建这三个组件。

1
2
3
4
5
6
7
8
9
render() {
return (
<div>
<h1>{this.title}</h1>
<MessageList messages = {this.messages}/>
<NewMessageForm />
</div>
);
}

MessageList

MessageList用于显示消息列表,它就是一个简单的<ul>标签,它的传入参数中有一个messages是要显示的消息的list。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MessageList extends Component {
constructor(props) {
super(props);

this.props = props;
}

getMessageList (messages) {
return messages.map((msg) =>
<li>
<Message message = {msg} />
</li>
);
}


render() {
return (
<ul>
{this.getMessageList(this.props.messages)}
</ul>
);
}
}

getMessageList这个函数使用map方法为messages中的每一条message创建一个<li>标签,<li>标签中包含Message组件。

Message

Message组件返回一个包含message内容的<div>标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Message extends Component {
constructor(props) {
super(props);

this.props = props;
}

render() {
return (
<div>
<p>{this.props.message}</p>
</div>
);
}
}

NewMessageForm

NewMessageForm是发送消息的表单,关于React表单的使用参考这里https://facebook.github.io/react/docs/forms.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
29
30
31
32
33
34
35
class NewMessageForm extends Component {
constructor(props) {
super(props);

this.state = {inputMessage: ''};

this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

handleSubmit (event) {
alert("Message: " + this.state.inputMessage);
event.preventDefault();
}

handleChange (event) {
this.setState({inputMessage: event.target.value});
}

render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<label>Message:</label>
<textarea value={this.state.inputMessage} onChange={this.handleChange} />
</div>
<div>
<button type='submit'>Send</button>
</div>
</form>
</div>
);
}
}

该类的实现中使用了this.state,它可以用于保存组件的各种状态,并且在state发生变更时自动地更新使用它的值的位置所显示的内容。关于state参考这里:https://facebook.github.io/react/docs/state-and-lifecycle.html

在表单提交的时候,为了避免页面刷新,以前我都是使用AJAX来提交数据,不过这次我打算使用WebSocket来进行通信。

下一步

实现WebSocket通信。