傳統(tǒng)Web前端
傳統(tǒng)編寫前端網(wǎng)頁(yè)大三大技術(shù),HTML、CSS、JavaScript(以及以JavaScript為基礎(chǔ)所封裝的第三方庫(kù),比如:JQuery等)
HTML
HTML 是用來(lái)描述網(wǎng)頁(yè)的一種語(yǔ)言,超文本標(biāo)記語(yǔ)言 (Hyper Text Markup Language);
標(biāo)記語(yǔ)言是一套標(biāo)記標(biāo)簽 ,HTML 使用標(biāo)記標(biāo)簽來(lái)描述網(wǎng)頁(yè),構(gòu)建網(wǎng)頁(yè)的基本骨架;
當(dāng)網(wǎng)頁(yè)被加載時(shí),瀏覽器會(huì)創(chuàng)建頁(yè)面的文檔對(duì)象模型(Document Object Model)。

CSS
CSS 指層疊樣式表 (Cascading Style Sheets),定義顯示 HTML 元素的方式;
HTML 標(biāo)簽被設(shè)計(jì)為用于定義文檔內(nèi)容。通過(guò)使用 <h1>、<p>、<table> 這樣的標(biāo)簽,HTML 的初衷是表達(dá)“這是標(biāo)題”、“這是段落”、“這是表格”之類的信息。最終由瀏覽器渲染到頁(yè)面,但是這些標(biāo)簽只能按默認(rèn)樣式,和流動(dòng)布局的方式渲染。
CSS則通過(guò)盒模型、選擇器、定位、層疊樣式等技術(shù)為網(wǎng)頁(yè)內(nèi)容添加格式
JavaScript
JavaScript 是輕量級(jí)的腳本語(yǔ)言,可插入 HTML 頁(yè)面,插入 HTML 頁(yè)面后,可由所有的現(xiàn)代瀏覽器執(zhí)行。
JS能夠獲得頁(yè)面的文檔對(duì)象樹,從而獲得頁(yè)面中的DOM對(duì)象,再通過(guò)內(nèi)部封裝的函數(shù)來(lái)操作這些DOM對(duì)象。
另外JS還封裝了關(guān)于HTTP請(qǐng)求和響應(yīng)的函數(shù),實(shí)現(xiàn)頁(yè)面發(fā)送和響應(yīng)HTTP請(qǐng)求
HTML+CSS+JavaScript
通過(guò)這三個(gè)技術(shù)就能實(shí)現(xiàn)前端頁(yè)面的內(nèi)容填充,樣式布局,交互響應(yīng)等所有內(nèi)容。項(xiàng)目中頁(yè)面就由page1.html、page1.css、page1.js三者組成。頁(yè)面的內(nèi)容是整體加載與渲染的。
React組件化模式下的Web前端
React則另辟蹊徑提出了以組件化的形式重新構(gòu)建頁(yè)面內(nèi)容,所謂組件就是將頁(yè)面的內(nèi)容按特征分塊,然后將特定塊中的HTML、CSS、JS封裝在一起,最后用組件來(lái)構(gòu)建頁(yè)面內(nèi)容。然而React不是一個(gè)完整的MVC,它只是V,也就是視圖表現(xiàn),采用React搭建完整的頁(yè)面還需要其它技術(shù)支持:npm、ES6、JSX、bable、less、Router、Redux、WebPack
React
React 是一個(gè)采用聲明式,高效而且靈活的用來(lái)構(gòu)建用戶界面的框架。
(下面是個(gè)人理解的說(shuō)法)
每一個(gè)React組件既是一個(gè)ES6對(duì)象,對(duì)象內(nèi)部可以有屬性和方法,從而更好的操作組件內(nèi)部的頁(yè)面元素。
React為了統(tǒng)一檢測(cè)變化,為每個(gè)React組件定義了兩個(gè)固定屬性,prop和state,prop是react父組件在使用react組件時(shí)所傳入的屬性,是由外部賦值的,而state只能通過(guò)內(nèi)部的構(gòu)造函數(shù)和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>
);
}
}
而通過(guò)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>
對(duì)比可以看出來(lái)傳統(tǒng)JQuery方式需要的到具體的DOM對(duì)象,然后進(jìn)行操作,而React組件方式只需要更改對(duì)象內(nèi)的state屬性,不需要操作DOM元素。
npm
NPM(node package manager),通常稱為node包管理器。顧名思義,它的主要功能就是管理node包,包括:安裝、卸載、更新、查看、搜索、發(fā)布等。
npm的背后,是基于couchdb的一個(gè)數(shù)據(jù)庫(kù),詳細(xì)記錄了每個(gè)包的信息,包括作者、版本、依賴、授權(quán)信息等。它的一個(gè)很重要的作用就是:將開發(fā)者從繁瑣的包管理工作(版本、依賴等)中解放出來(lái),更加專注于功能的開發(fā)。
Node.js 就是運(yùn)行在服務(wù)端的 JavaScript,是一個(gè)基于Chrome JavaScript 運(yùn)行時(shí)建立的一個(gè)平臺(tái),賦予了JavaScript很多面向?qū)ο笳Z(yǔ)言的特性
Node.js是一個(gè)事件驅(qū)動(dòng)I/O服務(wù)端JavaScript環(huán)境,基于Google的V8引擎,V8引擎執(zhí)行Javascript的速度非??欤阅芊浅:?。
ES6、JSX、bable
ES6即ECMAScript 2015,是 JavaScript 語(yǔ)言的下一代標(biāo)準(zhǔn),它和JavaScript的關(guān)系就是,JS是ES的一種實(shí)現(xiàn)。
ES6中有很多新的特性,比如箭頭函數(shù)、匹配賦值等,使的其更像是一門面向?qū)ο蟮恼Z(yǔ)言。
目前主流的瀏覽器還不支持ES6,所以需要通過(guò)轉(zhuǎn)碼器將ES6轉(zhuǎn)為ES5,bable就是目前主流的轉(zhuǎn)碼器
JSX就是Javascript和XML結(jié)合的一種格式。傳統(tǒng)的Web中HTML,CSS,JS一般是分開的,便于管理,要想在HTML中嵌套JS和CSS需要特定格式,而JSX就等價(jià)于這種規(guī)則。React發(fā)明了JSX,利用HTML語(yǔ)法來(lái)創(chuàng)建虛擬DOM。當(dāng)遇到“</>”,JSX就當(dāng)HTML解析,遇到“{}”就當(dāng)JavaScript解析。
例如:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
less或者Sass
Less (Leaner Style Sheets 的縮寫) 是一門向后兼容的 CSS 擴(kuò)展語(yǔ)言。他豐富了css選擇器的種類,使程序員能夠在css中定義變量,函數(shù),減少了css編寫的代碼量。同時(shí)他還支持選擇器之間的嵌套,這樣css更有邏輯,更易維護(hù),也更符合React組件化的思想,我們可以將一個(gè)React組件顯得選擇器封裝在一個(gè)嵌套層中,這樣邏輯更加清晰。
@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是組件化的開發(fā),小組件構(gòu)成大組件,大組件構(gòu)成更大的組件,整個(gè)網(wǎng)頁(yè)頁(yè)面也成了一個(gè)組件,那么怎么實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)呢?
傳統(tǒng)的web前端可以通過(guò)HTML文件的路徑來(lái)跳轉(zhuǎn),而React中都是組件,那么就不能通過(guò)傳統(tǒng)的方式來(lái)跳轉(zhuǎn)了,這時(shí)候Router就來(lái)了,他就是來(lái)解決這個(gè)問(wèn)題的。
React Router 是一個(gè)基于 React 之上的強(qiáng)大路由庫(kù),它可以讓你向應(yīng)用中快速地添加視圖和數(shù)據(jù)流,同時(shí)保持頁(yè)面與 URL 間的同步。
import React from 'react'
import { render } from 'react-dom'
// 首先我們需要導(dǎo)入一些組件...
import { Router, Route, Link } from 'react-router'
const About = React.createClass({/*...*/})
// 新建一個(gè)組件讓其在 Inbox 內(nèi)部渲染
const Message = React.createClass({
render() {
return <h3>Message</h3>
}
})
const Inbox = React.createClass({
render() {
return (
<div>
<h2>Inbox</h2>
{/* 渲染這個(gè) child 路由組件 */}
{this.props.children || "Welcome to your Inbox"}
</div>
)
}
})
// 然后我們從應(yīng)用中刪除一堆代碼和
// 增加一些 <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 會(huì)幫我們找到這個(gè) children
*/}
{this.props.children}
</div>
)
}
})
// 最后,我們用一些 <Route> 來(lái)渲染 <Router>。
// 這些就是路由提供的我們想要的東西。
React.render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
{/* 添加一個(gè)路由,嵌套進(jìn)我們想要嵌套的 UI 里 */}
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
), document.body)
Router還提供了<Link/>等組件方便使用,具體參考官方文檔
Redux
Redux本不是為了方便React而出現(xiàn)的,React項(xiàng)目中也可以不使用Redux,相反在小項(xiàng)目中使用Redux反而會(huì)增加項(xiàng)目的復(fù)雜度。但是在大型前端項(xiàng)目中,Redux則能夠很好地管理網(wǎng)站中的狀態(tài)。
Redux 是 JavaScript 狀態(tài)容器,提供可預(yù)測(cè)化的狀態(tài)管理。隨著 JavaScript 單頁(yè)應(yīng)用開發(fā)日趨復(fù)雜,JavaScript 需要管理比任何時(shí)候都要多的 state (狀態(tài))。 這些 state 可能包括服務(wù)器響應(yīng)、緩存數(shù)據(jù)、本地生成尚未持久化到服務(wù)器的數(shù)據(jù),也包括 UI 狀態(tài),如激活的路由,被選中的標(biāo)簽,是否顯示加載動(dòng)效或者分頁(yè)器等等。
管理不斷變化的 state 非常困難。如果一個(gè) model 的變化會(huì)引起另一個(gè) model 變化,那么當(dāng) view 變化時(shí),就可能引起對(duì)應(yīng) model 以及另一個(gè) model 的變化,依次地,可能會(huì)引起另一個(gè) view 的變化。直至你搞不清楚到底發(fā)生了什么。state 在什么時(shí)候,由于什么原因,如何變化已然不受控制。 當(dāng)系統(tǒng)變得錯(cuò)綜復(fù)雜的時(shí)候,想重現(xiàn)問(wèn)題或者添加新功能就會(huì)變得舉步維艱。
Redux將所有的state構(gòu)建為state樹,保存到一個(gè)對(duì)象中;將所有可能的行為封裝到action中,然后編寫reducer函數(shù)分別處理action,根據(jù)action的種類來(lái)更改state從而實(shí)現(xiàn)state的管理和控制。這就是Redux的核心思想。

webpack

Webpack的工作方式是:把你的項(xiàng)目當(dāng)做一個(gè)整體,通過(guò)一個(gè)給定的主文件(如:index.js),Webpack將從這個(gè)文件開始找到你的項(xiàng)目的所有依賴文件,使用loaders處理它們,最后打包為一個(gè)(或多個(gè))瀏覽器可識(shí)別的JavaScript文件。