摘要:入門與實戰組件虛擬的概念這是性能高效的核心算法為此引入了虛擬的機制。這個過程是自動完成的。實際上是改變了樣式文件中類的名稱,使其唯一。如果希望使用達到的效果,則需要做件事情服務器支持。
React 入門與實戰 react組件
虛擬DOM的概念 這是React性能高效的核心算法
React為此引入了虛擬DOM(Virtual DOM)的機制。基于React進行開發時所有的DOM構造都是通過虛擬DOM進行,每當數據變化時,React都會重新構建整個DOM樹,然后React將當前整個DOM樹和上一次的DOM樹進行對比,得到DOM結構的區別,然后僅僅將需要變化的部分進行實際的瀏覽器DOM更新。盡管每一次都需要構造完整的虛擬DOM樹,但是因為虛擬DOM是內存數據,性能是極高的,而對實際DOM進行操作的僅僅是Diff部分,因而能達到提高性能的目的。
React 組件,理解什么是組件化
像插入普通 HTML 標簽一樣,在網頁中插入這個組件
所謂組件,即封裝起來的具有獨立功能的UI部件
React推薦以組件的方式去重新思考UI構成,將UI上每一個功能相對獨立的模塊定義成組件,然后將小的組件通過組合或者嵌套的方式構成大的組件,最終完成整體UI的構建。
對于React而言,則完全是一個新的思路,開發者從功能的角度出發,將UI分成不同的組件,每個組件都獨立封裝。
React一個組件應該具有如下特征:
可組合(Composeable):一個組件易于和其它組件一起使用,或者嵌套在另一個組件內部。如果一個組件內部創建了另一個組件,那么說父組件擁有它創建的子組件,通過這個特性,一個復雜的UI可以拆分成多個簡單的UI組件.
可重用(Reusable):每個組件都是具有獨立功能的,它可以被使用在多個UI場景
可維護(Maintainable):每個小的組件僅僅包含自身的邏輯,更容易被理解和維護
語法
組件名稱一定要大寫
組件只能包含一個頂層標簽
// Header組件 // export 導出供外部使用 export default class ComponentHeader extends React.Component{ //render方法:用于解析本身類的輸出 render(){ return () } } // Index組件 import ComponentHeader from "./component/header"; class Index extends React.Component{ render(){ // 插入普通 HTML 標簽一樣 return 這里是頭部
} } // 將模版轉化為HTML語言,并插入到指定節點 // 相當于程序的入口 ReactDOM.render( ,document.getElementById("one"))
React 多組件嵌套
各個組件之間相互獨立,利于維護,重用。在Index文件中進行調用,簡明。
需要變更時,我們只需要改變相應的組件,所有引用該組件的的頁面就都發生的變更,很好維護。
import ComponentHeader from "./component/header"; import BodyIndex from "./component/body"; import ComponentFooter from "./component/footer"; class Index extends React.Component{ render(){ //將組件賦值給一個變量,這樣方便做判斷 var component; if(/*條件*/){ component =; }else{ component = ; } return ( { component}) } }
JXS內置表達式
HTML 語言直接寫在 JavaScript 語言之中,不加任何引號,這就是 JSX 的語法,它允許 HTML 與 JavaScript 的混寫。
JSX 的基本語法規則:遇到 HTML 標簽(以 < 開頭),就用 HTML 規則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規則解析
JSX 中的注釋 {/*注釋*/}
export default class BodyIndex extends React.Component{ render(){ var userName = "xiaoxiong"; var boolInput; var html1 = "Mooc Lesson"; //對 進行Unicode轉碼 var html2 = "Moocu0020Lesson" return () } }頁面主體內容
// 三元表達式的使用{userName = "" ?"用戶還沒有登錄":"用戶名:" +userName }
// 使用{boolInput}進行值的綁定 //解析html{html1}
//"Mooc Lesson" 不會被解析為空格{html2}
//"Mooc Lesson" //"Mooc Lesson" 此方法可能會存在xss攻擊
聲明周期,縱觀整個React的生命周期
在ES6中,一個React組件是用一個class來表示的
過程描述
在React中有4中途徑可以觸發render
首次渲染Initial Render
constructor --> componentWillMount --> render -->conponentDidMount
調用this.setState (并不是一次setState會觸發一次render,React可能會合并操作,再一次性進行render)
shouldComponentUpdate --> componentWillUpdate --> render --> componentDidUpdate
父組件發生更新(一般就是props發生改變,但是就算props沒有改變或者父子組件之間沒有數據交換也會觸發render)
componentWillReceiveProps --> shouldComponentUpdate --> componentWillUpdate --> render --> componentDidUpdate
調用this.forceUpdate
componentWillUpdate --> render --> componentDidUpdate
總結
constructor、componentWillMount、componentDidMount只有第一次渲染時候會被調用
componentWillUpdate、componentDidUpdate、shouldComponentUpdate 在以后的每次更新渲染之后都會被調用
考慮到性能的問題,如果有些屬性的變化,不需要重新刷新頁面,我們是使用 componentShouldUpdate() 進行控制。
官方文檔
https://facebook.github.io/re...
參考文獻
http://www.jianshu.com/p/4784...
state 屬性控制React的一切
組件自身的狀態,props為外部傳入的狀態
state對組件做了更新之后,會馬上反應到虛擬DOM上,最后更新到DOM上。這個過程是自動完成的。
組件免不了要與用戶互動,React 的一大創新,就是將組件看成是一個狀態機,一開始有一個初始狀態,然后用戶互動,導致狀態變化,從而觸發重新渲染 UI .
export default class BodyIndex extends React.Component{ // 初始化 constructor(){ super();//調用基類的所有初始化方法 //state的作用域是當前組件,不會污染其他模塊 this.state = { username:"xiaoxiong" }; }; //修改state setTimeOut(()=>{ this.setState({username:"miaomiao"}) },4000); render(){ return () } }頁面主體內容
// 引用state值{this.state.username}
Props屬性
其他組件傳遞參數,對于本模塊來說,屬于外來屬性。
//使用組件時,傳入參數 < BodyIndex userid="123" username={xiaoxiong}/> export default class BodyIndex extends React.Component{ render(){ return () } }頁面主體內容
// 接收參數{this.props.userid}
{this.props.username}
添加組件屬性,有一個地方需要注意,就是 class 屬性需要寫成 className ,for 屬性需要寫成 htmlFor ,這是因為 class 和 for 是 JavaScript 的保留字。
事件和數據的雙向綁定,包含了父子頁面之間的參數互傳
父組件給子組件傳遞參數,使用props
事件綁定
export default class BodyIndex extends React.Component{ constructor(){ super(); this.state={ username="xiaoxiong", age:20 } }; changeUserInfo(){ this.setState({age:50}) }; render(){ return () } }頁面主體內容
{this.props.username} {this.props.age }
//事件綁定 ES6寫法 //ES5寫法 onClick=this.chanchangeUserInfo
子組件為父組件傳參使用事件
在子頁面中通過調用父頁面傳遞過來的事件 props 進行組件間的參數傳遞
就是讓子頁面的變動體現在父頁面上,而頁面狀態的改變由state控制,因此我們讓父頁面通過props將函數傳遞給子頁面,此函數可以取得子頁面的值,并改變父頁面的state
//子組件 export default class BodyChild extends React.Component{ render(){ return (// 調用父組件傳過來的函數) } } //父組件 import BodyChild from "./component/bodychild"; export default class Body extends React.Component{ constructor(){ super(); this.state={ age:20 } } // 父頁面的函數,可以操控父頁面的 state handler(e){ this.setState({age:e.target.value}) } render(){ return (子頁面輸入:
) } }{this.state.age}
可復用組件,真正讓React開發快速、高效的地方
使用組件時,傳遞props,在組件定義的文件中可使用這些props
export default class BodyIndex extends React.Component{ render(){ return () } } // 對傳遞過來的 props 的類型進行約束 BodyIndex.propTypes = { // userid為number類型且必須傳遞 userid:React.propTypes.number.isRuquired }; // 設置默認值,使用組件時,如果不傳遞參數,將顯示默認值 BodyIndex.defaultProps = { username:"xiaoxiong" };{this.props.userid}
{this.props.username}
組件多層嵌套時,傳遞參數的簡便方法
export default class Body extends React.Component{ render(){ return (//在父頁面定義props) } } export default class BodySon extends React.Component{ render(){ return ( ) } } export default class Bodygrandson extends React.Component{ render(){ return ({this.props.username}
//取得父頁面(BodySon)的所有props屬性 // 使用傳遞過來的props) } }{this.props.username}{this.props.age}
組件的Refs
React中多數情況下,是通過state的變化,來重新刷新頁面。但有時也需要取得html節點,比如對input進行focus等;下面我們來看下,怎么取得原生的html節點,并對其進行操作。
export default class BodyChild extends React.Component{ handler(){ //第一種方式 var mySubmitBotton = document.getElementById("submitButton"); //這樣也是可以的 mySubmitBotton.style.color="red"; ReactDOM.findDOMNode(mySubmitBotton).style.color = "red"; //第二種方式 this.refs.submitBotton.style.color = "red"; } render(){ return () } }
refs是訪問到組件內部DOM節點的唯一可靠方式
refs會自動銷毀對子組件的引用
不要在Render或Render之前對Refs進行調用,因為Refs獲取的是真實的DOM節點,要在插入真實DOM節點之后調用。
不要濫用Refs
不必須使用真實DOM時,用方法1即可
獨立組件間共享Mixins
在所有的組件見共享一些方法
ES6中使用mixin需要插件支持
npm install react-mixin --save
使用
//mixin.js const MixinLog = { //有自身的生命周期 componentDidMount(){ console.log("MixinLog ComponentDidMount"); }, log(){ console.log("Mixins"); } }; //暴露供外部使用 export default MixinLog; //body.js //導入MixinLog import MixinLog from "./component/mixin.js"; import ReactMixin from "react-mixin"; export default class Body extends React.Component{ handler(){ //調用MixinLog中方法 MixinLog.log(); } render(){ return (react樣式) } } ReactMixin(Body.prototype,MixinLog);{this.props.username}
內聯樣式
原生中用 - 連接的樣式屬性,在這里要采用駝峰寫法或加引號"",屬性值一律加引號"" ,這樣的書寫方式,實際上就是加入了內聯樣式,結構和樣式混在一起,不是很好的做法。并且這種寫法,不能使用偽類、動畫。
export default class Header extends React.Component{ render(){ //將樣式定義為一個變量 //注意樣式屬性的書寫 const styleComponentHeader = { header:{ backgroundColor:"#333", color:"#fff", "padding-top":"15px", paddingBottom:"15px", }, //還可以定義其他樣式 }; return ( //使用樣式,這樣寫,實際上就是內聯樣式) } } 頭部
也可以在index.html文件中,引入css文件,并在需要使用樣式的地方加入類名(className),但這種寫法會污染全局。
//index.html//組件 export default class Header extends React.Component{ render(){ return ( //使用類名,加入樣式 ) } } 頭部
內聯樣式中的表達式
根據state的值,控制樣式
export default class Header extends React.Component{ constructor(){ super(); this.state={ miniHeader:false } } //點擊頭部,樣式發生變化 swithHeader(){ this.setState({ miniHeader:!this.state.miniHeader }) } render(){ const styleComponentHeader = { header:{ backgroundColor:"#333", color:"#fff", "padding-top":"15px", //根據state的值,變化 paddingBottom的值 //樣式中可以使用表達式 paddingBottom: (this.state.miniHeader)?"3px":"15px" }, }; return () } } 頭部
CSS模塊化,學習如何使用require進行樣式的引用
問題:
怎樣實現css的按需加載,使用這個模塊時,只加載這個模塊的樣式。
模塊之間的樣式是相互獨立的,即使使用相同的類名,也不會相互影響。
-
使用webpack,安裝相關插件
//使用require導入css文件 npm install css-loader --save //計算之后的樣式加入頁面中 npm install style-loader --save
webpack.config.js文件中進行配置
將css文件導入相應的組件后,會生成一個對應關系
footer:_footer_minifooter_vxs08s
_footer_minifooter_vxs08s是按照一定的規則生成一個唯一的類名,當我們為當前組件應用 .footer 類的時候,就會按照這個對應關系去樣式文件中找,然后應用響應的樣式。
實際上是改變了樣式文件中類的名稱,使其唯一。
這樣即使將所有文件打包到一起,也不會引起沖突。
不同的文件可以 使用相同的類名,不會沖突,因為模塊化之后,類名都進行了轉換。
module:{ loaders:[ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader", query: { presets: ["es2015","react"] } }, { test: /.css$/, //modules 模塊化配置 loader: "style-loader!css-loader?modules" }, ] },
使用
//footer.css .footer{ background-color:#333; } //Footer組件 //導入css樣式,這樣這個樣式文件只作用于這個組件 var footerCss = require("./css/footer.css"); export default class Footer extends React.Component{ render(){ return ( ) } }
總結
為什么要css模塊化
可以避免全局污染、命名混亂
模塊化的優點
所有的樣式都是local的,解決的命名沖突和全局污染的問題
class名生成規則配置靈活,可以以此來壓縮class名(在webpack.config.js文件中配置)
使用某個組件時,只要import組件,再使用即可,無需管理樣式。
不需要像書寫內部樣式一樣,屬性的名稱需要駝峰寫法。只需在webpack.config.js中進行配置,書寫時,還是我們熟悉的css。
JSX樣式與CSS樣式互轉
線上轉換工具
http://staxmanade.com/CssToRe...
Router 概念
控制頁面之間的層級關系
底層機制
通過狀態的改變,導致組件從新渲染,從而改變頁面顯示
React: state/props -> Component ->UI
通過改變url,導致Router變化,從而改變頁面顯示
React:location(hasj) -> Router ->UI
hashHistory && browserHistory
慕課老師的demo使用的是hashHistory,而另一種方式則是使用browserHistory。
如果希望使用browserHistory達到hashHistory的效果,則需要做2件事情:
1、服務器支持。如果開發服務器使用的是webpack-dev-server,加上--history-api-fallback參數就可以了。
2、作為項目入口的HTML文件中,相關外鏈的資源路徑都要改為絕對路徑,即以"/"根路徑開頭。
安裝
// 版本 2.8.1 npm install react-router
使用
component指定組件
path 指定路由的匹配規則
router可以進行嵌套
ComponentDetails嵌套在Index頁面中,我們要在Index中進行展示。
//index.js export default class Index extends React.Component{ render(){ return (//此處展示的是ComponentDetails頁面 {this.props.children}) } }
import React from "react"; import ReactDOM from "react-dom"; import Index from "./index"; import { Router, Route, hashHistory} from "react-router"; import ComponentList from "./components/list"; import ComponentHeader from "./components/header"; import ComponentDetails from "./components/details"; export default class Root extends React.Component{ render(){ //這里替換了之前的index,變成了程序的入口 (注意修改webpack.conf.js中的入口文件為root.js) return (); }; } ReactDOM.render( , document.getElementById("example") );
有了Router之后,用Link進行跳轉
首頁 嵌套的詳情頁面
Router 參數傳遞
//在Router中定義參數名稱使用NPM配置React環境//在Link中傳入參數 //在list組件頁面中讀取傳入的參數 render(){ {this.props.params.id}}
//初始化 建立初始化文件 npm init
package.json文件
npm的start是一個特殊的腳本名稱,它的特殊性表現在,在命令行中使用npm start就可以執行相關命令,如果對應的此腳本名稱不是start,想要在命令行中運行時,需要這樣用npm run {script name}如npm run build
{ "name": "reactconf",//項目名稱 "version": "1.0.0",//項目版本 "description": "",//項目描述 "main": "root.js",//入口文件 //自定義的腳本任務 "scripts": { "test": "echo "Error: no test specified" && exit 1", "start": "webpack-dev-server --inline --content-base ." }, "author": "", "license": "ISC", "dependencies": { "antd": "^2.10.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babelify": "^7.3.0", "css-loader": "^0.25.0", "react": "^15.5.4", "react-dom": "^15.5.4", "react-mixin": "^2.0.2", "react-router": "^2.8.1", "style-loader": "^0.13.1", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.1" }, "devDependencies": { "babel-core": "^6.24.1", "babel-loader": "^7.0.0" } }
安裝依賴
babelify
Babel其實是一個編譯JavaScript的平臺,它的強大之處表現在可以通過編譯幫你達到以下目的:
下一代的JavaScript標準(ES6,ES7),這些標準目前并未被當前的瀏覽器完全的支持
使用基于JavaScript進行了拓展的語言,比如React的JSX
babel-preset-react react轉碼規則
babel-preset-es2015 ES2015轉碼規則
npm install react react-dom babelify --save npm install babel-preset-react babel-preset-es2015 --save
使用webpack打包
安裝相關的包
npm install webpack -g npm install webpack-dev-server -g npm install webpack --save npm install webpack-dev-server --save
//webpack.config.js // 引用webpack相關的包 var webpack = require("webpack"); var path = require("path"); var WebpackDevServer = require("webpack-dev-server"); module.exports = { //入口文件 __dirname 項目根目錄 //“__dirname”是node.js中的一個全局變量,它指向當前執行腳本所在的目錄 context: __dirname + "/src", entry:"./js/root.js", //loaders module:{ loaders:[ { test: /.js$/, exclude: /node_modules/, loader: "babel", query: { presets: ["es2015","react"] } }, //下面是使用 ant-design 的配置文件 不再使用 ?modules 因為樣式是全局的 不再需要局部樣式 { test: /.css$/, //modules 模塊化配置 loader: "style-loader!css-loader?modules" }, ] }, //出口文件 output: { path: __dirname + "/src/", filename: "bundle.js" }, };
打包命令
// 正常情況下 webpack //配置熱加載情況下 webpack-dev-server --inline
使用 --watch 可是自動打包,但不會自動刷新
可以用content-base設定 webpack-dev-server 伺服的 directory (就是指管這個路徑下文件的變動),如果不進行設定的話,默認是在當前目錄下
webpack-dev-server --content-base -src --inline關于webpack
為什么使用webpack
現今的很多網頁其實可以看做是功能豐富的應用,它們擁有著復雜的JavaScript代碼和一大堆依賴包。為了簡化開發的復雜度,前端社區涌現出了很多好的實踐方法
模塊化,讓我們可以把復雜的程序細化為小的文件;類似于TypeScript這種在JavaScript基礎上拓展的開發語言,使我們能夠實現目前版本的JavaScript不能直接使用的特性,并且之后還能能裝換為JavaScript文件使瀏覽器可以識別.
Scss,less等CSS預處理器
...
這些改進確實大大的提高了我們的開發效率,但是利用它們開發的文件往往需要進行額外的處理才能讓瀏覽器識別,而手動處理又是非常繁瑣的,這就為WebPack類的工具的出現提供了需求。
webpack并不強制你使用某種模塊化方案,而是通過兼容所有模塊化方案讓你無痛接入項目,當然這也是webpack牛逼的地方
webpack和gulp的區別
gulp是工具鏈、構建工具,可以配合各種插件做js壓縮,css壓縮,less編譯 替代手工實現自動化工作
1.構建工具 2.自動化 3.提高效率用
webpack是文件打包工具,可以把項目的各種js文、css文件等打包合并成一個或多個文件,主要用于模塊化方案,預編譯模塊的方案
1.打包工具 2.模塊化識別 3.編譯模塊代碼方案
雖然都是前端自動化構建工具,但看他們的定位就知道不是對等的。
gulp嚴格上講,模塊化不是他強調的東西,他旨在規范前端開發流程。
webpack更是明顯強調模塊化開發,而那些文件壓縮合并、預處理等功能,不過是他附帶的功能。
webpack工作方式
Webpack的工作方式是:把你的項目當做一個整體,通過一個給定的主文件(如:index.js),Webpack將從這個文件開始找到你的項目的所有依賴文件,使用loaders處理它們,最后打包為一個瀏覽器可識別的JavaScript文件。
Loaders
通過使用不同的loader,webpack通過調用外部的腳本或工具可以對各種各樣的格式的文件進行處理,比如說分析JSON文件并把它轉換為JavaScript文件,或者說把下一代的JS文件(ES6,ES7)轉換為現代瀏覽器可以識別的JS文件。或者說對React的開發而言,合適的Loaders可以把React的JSX文件轉換為JS文件。
Loaders需要多帶帶安裝并且需要在webpack.config.js下的modules關鍵字下進行配置,Loaders的配置選項包括以下幾方面:
test:一個匹配loaders所處理的文件的拓展名的正則表達式(必須)
loader:loader的名稱(必須)
include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選);
query:為loaders提供額外的設置選項(可選)
// MediaQuery 進行移動端適配 var MediaQuery = require("react-responsive");
fetch 向后臺請求數據
響應式 以1224px為分界
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/116667.html
摘要:入門與實戰組件虛擬的概念這是性能高效的核心算法為此引入了虛擬的機制。這個過程是自動完成的。實際上是改變了樣式文件中類的名稱,使其唯一。如果希望使用達到的效果,則需要做件事情服務器支持。 React 入門與實戰 react組件 虛擬DOM的概念 這是React性能高效的核心算法 React為此引入了虛擬DOM(Virtual DOM)的機制。基于React進行開發時所有的DOM構造都是通...
摘要:建議閱讀博客前端工程基礎篇鏈接書籍深入淺出鏈接服務器端的是在年正式提出并開源的,傳統的都運行在瀏覽器這樣的宿主環境中,而基于谷歌瀏覽器的引擎構建的運行環境,使用了一個事件驅動非阻塞式的模型,將帶入服務器領域。 1.網頁布局HTML+CSS 技能要求 學會用工具(如PS)切圖,將設計稿還原成網頁布局 掌握常規布局方法:文檔流布局,flex布局,grid布局,居中,浮動…… HTML5...
摘要:數據綁定入門學習總結時間年月日星期日說明本文部分內容均來自慕課網。慕課網教學示例源碼個人學習源碼第一章課程介紹數據綁定入門概述數據綁定概念來自百度百科簡單綁定是將一個用戶界面元素控件的屬性綁定到一個類型對象實例上的某個屬性的方法。 《SpringMVC數據綁定入門》學習總結 時間:2017年2月19日星期日說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.co...
閱讀 1093·2021-10-12 10:11
閱讀 877·2019-08-30 15:53
閱讀 2286·2019-08-30 14:15
閱讀 2961·2019-08-30 14:09
閱讀 1197·2019-08-29 17:24
閱讀 972·2019-08-26 18:27
閱讀 1282·2019-08-26 11:57
閱讀 2146·2019-08-23 18:23