传统Web前端
传统编写前端网页大三大技术,HTML、CSS、JavaScript(以及以JavaScript为基础所封装的第三方库,比如:JQuery等)
HTML
HTML 是用来描述网页的一种语言,超文本标记语言 (Hyper Text Markup Language);
标记语言是一套标记标签 ,HTML 使用标记标签来描述网页,构建网页的基本骨架;
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
CSS
CSS 指层叠样式表 (Cascading Style Sheets),定义显示 HTML 元素的方式;
HTML 标签被设计为用于定义文档内容。通过使用 <h1>、<p>、<table> 这样的标签,HTML 的初衷是表达“这是标题”、“这是段落”、“这是表格”之类的信息。最终由浏览器渲染到页面,但是这些标签只能按默认样式,和流动布局的方式渲染。
CSS则通过盒模型、选择器、定位、层叠样式等技术为网页内容添加格式
JavaScript
JavaScript 是轻量级的脚本语言,可插入 HTML 页面,插入 HTML 页面后,可由所有的现代浏览器执行。
JS能够获得页面的文档对象树,从而获得页面中的DOM对象,再通过内部封装的函数来操作这些DOM对象。
另外JS还封装了关于HTTP请求和响应的函数,实现页面发送和响应HTTP请求
HTML+CSS+JavaScript
通过这三个技术就能实现前端页面的内容填充,样式布局,交互响应等所有内容。项目中页面就由page1.html、page1.css、page1.js三者组成。页面的内容是整体加载与渲染的。
React组件化模式下的Web前端
React则另辟蹊径提出了以组件化的形式重新构建页面内容,所谓组件就是将页面的内容按特征分块,然后将特定块中的HTML、CSS、JS封装在一起,最后用组件来构建页面内容。然而React不是一个完整的MVC,它只是V,也就是视图表现,采用React搭建完整的页面还需要其它技术支持:npm、ES6、JSX、bable、less、Router、Redux、WebPack
React
React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架。
(下面是个人理解的说法)
每一个React组件既是一个ES6对象,对象内部可以有属性和方法,从而更好的操作组件内部的页面元素。
React为了统一检测变化,为每个React组件定义了两个固定属性,prop和state,prop是react父组件在使用react组件时所传入的属性,是由外部赋值的,而state只能通过内部的构造函数和setState方法赋值和修改。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
例如:
class App extends Component {
constructor(props){
super(props);
this.onClickButton = this.onClickButton.bind(this);
this.state = {count : 0};
}
onClickButton(){
this.setState({
count : this.state.count + 1
});
}
render() {
return (
<div>
<button id="btn_click" type="button" onClick={this.onClickButton}>click me</button>
<span id="value">{this.state.count}</span>
</div>
);
}
}
而通过JQuery代码则是:
<body>
<button id="btn_click" type="button" name="button">click me</button>
<span id="value">0</span>
<script src="./jquery-3.2.1.js" charset="utf-8"></script>
<script type="text/javascript">
$(function(){
$("#btn_click").click(function(event) {
/* Act on the event */
var clickCounter = $("#value");
var count = parseInt(clickCounter.text(),10);
clickCounter.text(count+1);
});
})
</script>
</body>
对比可以看出来传统JQuery方式需要的到具体的DOM对象,然后进行操作,而React组件方式只需要更改对象内的state属性,不需要操作DOM元素。
npm
NPM(node package manager),通常称为node包管理器。顾名思义,它的主要功能就是管理node包,包括:安装、卸载、更新、查看、搜索、发布等。
npm的背后,是基于couchdb的一个数据库,详细记录了每个包的信息,包括作者、版本、依赖、授权信息等。它的一个很重要的作用就是:将开发者从繁琐的包管理工作(版本、依赖等)中解放出来,更加专注于功能的开发。
Node.js 就是运行在服务端的 JavaScript,是一个基于Chrome JavaScript 运行时建立的一个平台,赋予了JavaScript很多面向对象语言的特性
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
ES6、JSX、bable
ES6即ECMAScript 2015,是 JavaScript 语言的下一代标准,它和JavaScript的关系就是,JS是ES的一种实现。
ES6中有很多新的特性,比如箭头函数、匹配赋值等,使的其更像是一门面向对象的语言。
目前主流的浏览器还不支持ES6,所以需要通过转码器将ES6转为ES5,bable就是目前主流的转码器
JSX就是Javascript和XML结合的一种格式。传统的Web中HTML,CSS,JS一般是分开的,便于管理,要想在HTML中嵌套JS和CSS需要特定格式,而JSX就等价于这种规则。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到“</>”,JSX就当HTML解析,遇到“{}”就当JavaScript解析。
例如:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
less或者Sass
Less (Leaner Style Sheets 的缩写) 是一门向后兼容的 CSS 扩展语言。他丰富了css选择器的种类,使程序员能够在css中定义变量,函数,减少了css编写的代码量。同时他还支持选择器之间的嵌套,这样css更有逻辑,更易维护,也更符合React组件化的思想,我们可以将一个React组件显得选择器封装在一个嵌套层中,这样逻辑更加清晰。
@width: 10px;
@height: @width + 10px;
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
#header {
color: black;
.bordered();
.navigation {
font-size: 12px;
}
.logo {
width: @width;
height: @height;
}
}
Router
前面讲了React是组件化的开发,小组件构成大组件,大组件构成更大的组件,整个网页页面也成了一个组件,那么怎么实现页面的跳转呢?
传统的web前端可以通过HTML文件的路径来跳转,而React中都是组件,那么就不能通过传统的方式来跳转了,这时候Router就来了,他就是来解决这个问题的。
React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。
import React from 'react'
import { render } from 'react-dom'
// 首先我们需要导入一些组件...
import { Router, Route, Link } from 'react-router'
const About = React.createClass({/*...*/})
// 新建一个组件让其在 Inbox 内部渲染
const Message = React.createClass({
render() {
return <h3>Message</h3>
}
})
const Inbox = React.createClass({
render() {
return (
<div>
<h2>Inbox</h2>
{/* 渲染这个 child 路由组件 */}
{this.props.children || "Welcome to your Inbox"}
</div>
)
}
})
// 然后我们从应用中删除一堆代码和
// 增加一些 <Link> 元素...
const App = React.createClass({
render() {
return (
<div>
<h1>App</h1>
{/* 把 <a> 变成 <Link> */}
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
</ul>
{/*
接着用 `this.props.children` 替换 `<Child>`
router 会帮我们找到这个 children
*/}
{this.props.children}
</div>
)
}
})
// 最后,我们用一些 <Route> 来渲染 <Router>。
// 这些就是路由提供的我们想要的东西。
React.render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
{/* 添加一个路由,嵌套进我们想要嵌套的 UI 里 */}
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
), document.body)
Router还提供了<Link/>等组件方便使用,具体参考官方文档
Redux
Redux本不是为了方便React而出现的,React项目中也可以不使用Redux,相反在小项目中使用Redux反而会增加项目的复杂度。但是在大型前端项目中,Redux则能够很好地管理网站中的状态。
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。
Redux将所有的state构建为state树,保存到一个对象中;将所有可能的行为封装到action中,然后编写reducer函数分别处理action,根据action的种类来更改state从而实现state的管理和控制。这就是Redux的核心思想。
webpack
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。