React
時代的發展
1.jq dom操做時代,面向過程開發--seajs requirejs(2012年左右-2014年 grunt gulp 前端構建工具)模塊化的開發(把一個功能封裝成一個js文件,對外經過module.exports暴露方法,---14年至今 組件化開發 dom js css都封裝到一個文件 而後暴露出去 經過es6的export,框架就這個文件轉成自定義的html標籤。)
2.咱們react.js用的版本是15.5的。
3.react.js 核心庫(15.5),react-dom.min.js(將虛擬dom轉換成真實的dom插入到頁面中),babel.js(轉es6和jsx語法)
4.ReactDOM.render()函數把組件渲染成真實的DOM,並插入到DOM中
5.render函數表示當前組件的模板
CommonJS,AMD,CMD //模塊化開發的規範
1.CommonJS
CommonJS就是爲JS的表現來制定規範,由於js沒有模塊的功能因此CommonJS應運而生,它但願js能夠在任何地方運行,不僅是瀏覽器中。
CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
require()用來引入外部模塊;exports對象用於導出當前模塊的方法或變量,惟一的導出口;module對象就表明模塊自己。
CommonJS是主要爲了JS在後端的表現制定的,他是不適合前端的。
在node中:
Node應用由模塊組成,採用CommonJS模塊規範。根據這個規範,每個文件就是一個模塊,有本身的做用域,在每個文件裏面定義的變量,函數,類,都是私有的,對其餘的文件是不可見的。
CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,他的exports屬性(即module.exports)是對外的接口,加載某個模塊,實際上是加載該模塊的module.exports屬性。require方法用於加載模塊。
2.AMD CMD
AMD規範:是 RequireJS 在推廣過程當中對模塊定義的規範化產出的,而CMD規範:是SeaJS 在推廣過程當中對模塊定義的規範化產出的。
AMD(異步模塊定義)出現了,它就主要爲前端JS的表現制定規範,CommonJS規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操做。AMD規範則是非同步加載模塊,容許指定回調函數,因爲Node.js主要用於服務器編程,模塊文件通常都已經存在於本地硬盤,因此加載起來比較快,不用考慮非同步加載的方式,因此CommonJS規範比較適用。可是,若是是瀏覽器環境,要從服務器端加載模塊,這時就必須採用非同步模式,所以瀏覽器端通常採用AMD規範。
define( id?, dependencies?, factory );
1.seajs:
一個Web模塊加載框架,追求簡單、天然的代碼書寫和組織方式,:Sea.js 遵循 CMD 規範,模塊化JS代碼。依賴的自動加載、配置的簡潔清晰,可讓程序員更多地專一編碼。
優勢:
1).提升可維護性。
2).模塊化編程。
3).動態加載,前端性能優化
缺點:
1).學習文檔偏少且混亂,會更改團隊使用JS的編寫習慣,必須使用模塊化編程。
2).不太適合團隊目前的狀況,多JS文件但少改動,動態加載優點和模塊化優點不明顯。
3). 須要配套使用SPM工具,JS的打包和管理工具。
2.gulp 和 grunt
自動化構建工具,可以優化前端的工做流程,更加效率的開發,好比編碼的時候,它會自動幫你刷新頁面,壓縮你的js,css代碼,編譯less等等。總之,經過gulp和grunt,配置一些插件,你不少繁瑣的須要手動操做的事情它自動幫你完成,很是高效率,nice!
3.browserify / webpack seajs / requirejs
這四個都是JS模塊化的方案。其中seajs / require 是一種類型,browserify / webpack 是另外一種類型。
seajs / require : 是一種在線"編譯" 模塊的方案,至關於在頁面上加載一個 CMD/AMD 解釋器。這樣瀏覽器就認識了 define、exports、module 這些東西。也就實現了模塊化。
browserify / webpack : 是一個預編譯模塊的方案,相比於上面 ,這個方案更加智能。沒用過browserify,這裏以webpack爲例。首先,它是預編譯的,不須要在瀏覽器中加載解釋器。另外,你在本地直接寫JS,不論是 AMD / CMD / ES6 風格的模塊化,它都能認識,而且編譯成瀏覽器認識的JS。
總結:Gulp是一個工具,而webpack等等是模塊化方案。Gulp也能夠配置seajs、requirejs甚至webpack的插件。
好圖:
基礎
1.jsx
1)添加自定義屬性,須要使用data-前綴(但願當前的這個數據顯示在真實的dom中,須要data-)
2)樣式添加,內聯樣式,style,className
3 ) 註釋
4)數組展開
5)變量{}
6)render只能有一個父節點
2.組件
1)組件的定義
2)複合組件
3)組件的props:從父組件到子組件的傳遞,父組件經過調用子組件,定義一個組件名,子組件經過this.props.屬性名獲得這個數據,而且在子組件中定義propTypes來進行屬性的驗證。
4)默認的props(getDefaultProps)
屬性的(props)驗證:
propTypes:組件的健壯性---容錯率(對傳進來的屬性進行驗證,告訴開發者你傳錯數據了)
{
msg:PropTypes.oneOf([123,456]) //只能傳這兩個參數中的一個
}
3.狀態
以前的:
咱們能夠在父組件中設置state,(並經過在子組件上使用props將其傳遞到子組件中)--數據驅動,在render函數中設置this.state...來獲取父組件傳遞的值。
當前頁面中顯示的關注是從父節點或者父組件來的,點擊切換的時候,是當前這個組件本身的狀態。總結:狀態是本身的狀態,是用來改變視圖的。
什麼是狀態:數據就是狀態 ,數據改變就是狀態改變。
getInitialState:初始化當前組件的內部狀態
state:定義組件內部的數據,這個內部的數據就是狀態
數據驅動:數據驅動視圖的變化,狀態改變,數據進而改變。
狀態和props的區別:props是用於父組件向子組件傳遞數據,可是沒有辦法直接去改變從父組件傳過來的值,state定義組件內部的數據,狀態改變,數據進而改變,數據驅動視圖的變化 。
{num:this.state.num++}---num值沒有改變:當你有多個狀態的時候,調用render函數是異步的,react更新視圖是異步的。若是想要狀態更新成功以後,在上一次狀態的基礎上改變,經過preSate。
若是子組件可以擅自改變父組件傳過來的值,頁面會顯得很混亂。當前這個子組件和父組件就耦合了,就複用不了了。
單向數據流:數據只能從父組件流向子組件,而不能在子組件中直接修改父組件的值
es6--class:
1)constructor:當前的子類的實例默認狀況下面沒有本身的this對象,必須顯示的定義這個constructor 函數,而且調用super(),這個this是父節點的this,當咱們去new 這個子類的時候,這個this就指向這個子類的實例,render裏面才能調用到這個this。
2)實例方法:handle裏面的this不知道是誰,經過類的繼承,在實例上面增長方法的時候,默認狀況下是拿不到this的,爲何render函數裏面知道這個this呢,是由於模板知道這個this是誰。
3)this.handleClick = this.handleClick.bind(this);
在class Concat extends React.Component 中咱們是聲明該class,由於this具體是由其上下文決定的,所以在類定義中咱們沒法得知this用法。
經過顯示的定義constructor()函數,而且調用super(),這個this指向的是父節點的this,經過new一個Concat實例,這個this就指向new出來的Concat實例,render() 函數中 this.state.liked 的this上下文也是該實例。
可是在原來 React.createClass 中,handleClick() 在onClick事件觸發的時候,會自動綁定到Concat實例上,這時候該函數的this的上下文就是該實例。
不過在ES6的class的寫法中,Facebook取消了自動綁定,給虛擬dom綁定一個onclick事件的時候,傳遞的是一個匿名函數,獲取的是這個函數的引用,js中是值傳遞,因此匿名函數中運行的上下文不知道是哪裏。
因此實例化Concat後,handleClick()的上下文this指向的是這個dom,可是這個dom又不是真實的dom,因此react返回一個null回來。
4.事件
1)handle(e){}:默認狀況下會把event對象做爲第一個參數傳入回調函數
2)e.target.dataset:經過dataset能夠拿到當前dom上data-開頭的屬性
5.生命週期
1)什麼是生命週期
從new一個組件開始,再到這個組件被銷燬,就稱這個過程爲生命週期。
Mounting:插入真實的DOM階段
Updating:當狀態更新的時候
Unmounting:移除真實的DOM階段
2)生命週期鉤子函數:在生命週期每一個階段的回調函數稱之爲生命週期鉤子函數(針對於每個階段要作的事情--你的業務邏輯),當這個組件執行到這個階段後,就調用這個函數。
3)生命週期方法
componentWillMount:在插入真實dom前調用,看不到數據的一個變化的過程
componentDidMount:當組件第一次插入到真實的dom之後調用
componentWillReceiveProps:組件接收到一個新的prop時被調用,初始化render時不會被調用,有一個newProps參數,表明新的props。
shouldComponentUpdate:在組件接收到新的props和state時觸發,能夠確認更不更新數據,return true接收新傳來的props和states
,贊成更新視圖,return false就不會接受新傳來的props和state,不一樣意更新視圖。有newProps,newState兩個參數,表明新的props和state 。
componentWillUpdate:在組件接收到新的props和state但尚未render時調用(更新以前),有nextProps,nextState兩個參數,表明新的props和state。
componentDidUpdate:組件更新完成以後調用,有prevProps,prevState兩個參數,表明更新以前的值。
componentWillUnmount:當組件從DOM中移除的時候調用
6.條件渲染
1)在 React 中,你能夠建立不一樣的組件來封裝各類你須要的行爲。而後還能夠根據應用的狀態變化只渲染其中的一部分。
React 中的條件渲染和 JavaScript 中的一致,使用 JavaScript 操做符 if 或條件運算符來建立表示當前狀態的元素,而後讓 React 根據它們來更新 UI。放在render函數裏面,作判斷,將結果放在一個變量裏面,再在return裏面渲染出來
7.列表
key:key屬性至關於給列表中的每一個元素增長一個惟一值。目的在dom中的某些元素被增長或者刪除的時候幫助react識別那個元素髮生了變化。(爲每個對象指定一個key,讓key指向這個惟一值,react經過這個key知道操做的是哪個)
8.表單
1)受控組件:經過設置input的value屬性, 沒法改變輸入框值,value='',不能操控。非受控組件,沒有value,能夠輸入值
2)經過傳遞一個函數給子組件,當子組件的數據變化的時候,執行傳遞過去的函數,在父組件當中預先定義好傳給子組件的函數。
9.ref
若是你想對dom節點進行操做,能夠在文本框裏添加一個屬性ref
總結:必須獲取真實的 DOM節點,虛擬DOM是拿不到用戶輸入的。爲了作到這一點,文本輸入框必須有一個 ref 屬性,而後 this.refs.[refName] 就會返回這個真實的DOM節點。須要注意的是,因爲 this.refs.[refName] 屬性獲取的是真實DOM,因此必須等到虛擬DOM插入文檔之後,才能使用這個屬性,不然會報錯。
<input ref="myInput" /> :添加
var input = this.refs.myInput;獲取
ref還能夠接受一個函數
<input type="text" ref={(input) => { this.textInput = input; }} /> //ref 回調接收了當前的 DOM 元素做爲參數
10.react路由
1)腳手架:
cnpm install -g create-react-app
create-react-app my-app
create-react-app -v
src是用來存放組件的(組件和組件的樣式),public目錄是用來存放靜態資源的(經過link,src標籤引入)。
2)根據hash值來進行頁面的切換
3)單頁面應用:在瀏覽器不刷新的狀況下面,讓不一樣的組件在惟一的html文件中切換。
4)url變化可是瀏覽器不刷新-----動態爲url添加hash值(hash不會觸發瀏覽器刷新,根據hash來定位當前應該加載什麼組件)
5)npm run start:運行項目
6)安裝路由
cnpm i --save react-router@2(通常用版本2)
cnpm i --save prop-types(由於react15.5剔除掉了它,用於屬性驗證)
7)registerServiceWorker.js:PWA,在桌面上面生成圖標,將頁面保存成一個個圖標。只有chrome支持,處理離線
8)e.target.dataset
8)擼~
webpack的入口文件是index.js
最外層的組件是app.js
Router:路由器Router就是React的一個組件,Router組件自己只是一個容器,真正的路由要經過Route組件定義。
Route:Route組件定義了URL路徑與組件的對應關係。你能夠同時使用多個Route組件。Route組件還能夠嵌套。
IndexRoute:指定默認狀況下加載的子組件,<IndexRoute component={Content}/> 顯示的指定Content是根路由的子組件。
Redirect:該組件用於路由的跳轉,即用戶訪問一個路由,會自動跳轉到另外一個路由。
IndexRedirect:組件用於訪問根路由的時候,將用戶重定向到某個子組件。
Link:用於取代<a>元素,生成一個連接,容許用戶點擊後跳轉到另外一個路由。它基本上就是<a>元素的React 版本,能夠接收Router的狀態。若是但願當前的路由與其餘路由有不一樣樣式,這時可使用Link組件的activeStyle屬性。
histroy 屬性:Router組件的history屬性,用來監聽瀏覽器地址欄的變化,並將URL解析成一個地址對象,供 React Router 匹配。
1) hashHistory:路由將經過URL的hash部分(#)切換,URL的形式相似example.com/#/some/path。
2) browserHistory:瀏覽器的路由就再也不經過Hash完成了,而顯示正常的路徑example.com/some/path,背後調用的是瀏覽器的History API。(從hash值得路由切換變換爲路徑切換,至關於向後臺發了一個請求,若是後臺配置不對,就會報404,可是history api幫咱們處理了,你發送get請求,都返回給你一個index.html頁面給你(單頁面),就不會出現404狀況了)
二者區別:History API 提供了 pushState() 和 replaceState() 方法來增長或替換歷史記錄。而 hash 沒有相應的方法,因此並無替換歷史記錄的功能。另外一個緣由是 hash 部分並不會被瀏覽器發送到服務端,也就是說不論是請求 http://domain.com/index.html#foo 仍是 http://domain.com/index.html#bar ,服務只知道請求了 index.html 並不知道 hash 部分的細節。而 History API 須要服務端支持,這樣服務端能獲取請求細節。
動態路由:當用戶匹配到user/123或者user/343都加在User這個組件,後面這個123就至關於一個變量,獲取到這個變量,向後臺發送請求,後臺根據這個變量查詢到相關數據,再響應給前端
11. 總結
1)組件的做用域都是獨立的,顯示的數據一般是父組件傳遞進來的。
2)給組件傳遞數據的方式有2種,第一種是使用組件的 props 經過 this.props.xx來獲取;經過組件的innerHTML 來傳遞 ,使用 this.props.children 來獲取。
3)return()使用小括號包起來的是爲了換行。
4)this.props.children 拿到當前使用這個組件的時候傳的innerHTML的值。
項目總結
1
setState({
value:''
})
驅動視圖的改變
this.state.value=''
僅僅只是改變value的值,不驅動視圖的改變
2
componentDidMount(){}
在第一次插入真實的dom以後調用
componentWillReceiveProps(){}
shouldComponentUpdate(){}
componentWillUpdate(){}
在第一次渲染DOM而且有接受外來的props的時候並不會被調用,經過父組件調用一些事件再傳值纔會被調用 和 經過一些事件驅動視圖的時候纔會被調用,而且是在render函數以前調用
3 localstorage的使用
註冊帳號的話,是將帳號以JSON字符串的方式存進storage中,再以JSON對象的方式讀出來
4 動態路由
user / : id 當用戶匹配到user/123或者user/343的時候,後面這個123就至關於一個變量,經過Link或者browserHistory標籤將這個變量帶到User組件中,用this.props.params獲取到這個變量,根據變量的值向後臺發送不一樣的請求,後臺根據這個變量查詢到相關數據,再響應給前端,前端作相應的處理。好比job詳情頁面,加載的都只是job這個組件,經過不一樣的url帶上不一樣的參數加載到這個組件的時候,根據參數的不一樣顯示不一樣的詳情頁面。
常常看到一些name?id=1這種url,這種通常是get方式帶上參數
5 業務邏輯
1)加載更多,首先讀出全部的數據對象,放在一個數組裏arr,定義一個截取標記idx,從0開始,若是每頁只加載5條的話,arr.slice(idx,idx+5),在更新狀態而且更新idx的值this.state.idx=...
2)
6 history
回退