npm i antd
npm i react-router-dom
react簡介
- React 起源于 Facebook 的內(nèi)部項(xiàng)目光涂,因?yàn)樵摴緦?duì)市場上所有 JavaScript MVC 框架,都不滿意拧烦,就決定自己寫一套,用來架設(shè) Instagram(照片交友) 的網(wǎng)站。做出來以后糙申,發(fā)現(xiàn)這套東西很好用涨冀,
就在2013年5月開源了
。 - Angular1 2009 年 谷歌 MVC 不支持 組件化開發(fā)
- 由于 React 的
設(shè)計(jì)思想極其獨(dú)特
债沮,屬于革命性創(chuàng)新重虑,性能出眾,代碼邏輯卻非常簡單秦士。所以缺厉,越來越多的人開始關(guān)注和使用,認(rèn)為它可能是將來 Web 開發(fā)的主流工具隧土。 - 清楚兩個(gè)概念:
1提针、library(庫):小而巧的庫,只提供了特定的API曹傀;優(yōu)點(diǎn)就是 船小好掉頭辐脖,可以很方便的從一個(gè)庫切換到另外的庫;但是代碼幾乎不會(huì)改變皆愉;
2嗜价、Framework(框架):大而全的是框架艇抠;框架提供了一整套的解決方案;所以久锥,如果在項(xiàng)目中間家淤,想切換到另外的框架,是比較困難的瑟由;
前端三大主流框架
-
Angular.js:出來
較早
的前端框架絮重,學(xué)習(xí)曲線比較陡,NG1學(xué)起來比較麻煩歹苦,NG2 ~ NG5開始青伤,進(jìn)行了一系列的改革,也提供了組件化開發(fā)的概念殴瘦;從NG2開始狠角,也支持使用TS(TypeScript)進(jìn)行編程; -
Vue.js:
最火
(關(guān)注的人比較多)的一門前端框架蚪腋,它是中國人開發(fā)的丰歌,對(duì)我我們來說,文檔要友好一些辣吃; -
React.js:
最流行
(用的人比較多)的一門框架动遭,因?yàn)樗脑O(shè)計(jì)很優(yōu)秀;
React與vue的對(duì)比
- 組件化方面
1神得、什么是模塊化:是從
代碼
的角度來進(jìn)行分析的厘惦;把一些可復(fù)用的代碼,抽離為單個(gè)的模塊哩簿;便于項(xiàng)目的維護(hù)和開發(fā)宵蕉;
2、什么是組件化:是從UI 界面
的角度 來進(jìn)行分析的节榜;把一些可服用的UI元素羡玛,抽離為單獨(dú)的組件;便于項(xiàng)目的維護(hù)和開發(fā)宗苍;
3稼稿、組件化的好處:隨著項(xiàng)目規(guī)模的增大,手里的組件越來越多讳窟;很方便就能把現(xiàn)有的組件让歼,拼接為一個(gè)完整的頁面;
4丽啡、Vue是如何實(shí)現(xiàn)組件化的: 通過.vue
文件谋右,來創(chuàng)建對(duì)應(yīng)的組件,.vue
文件由三部分組成:template 結(jié)構(gòu)补箍;script 行為改执;style 樣式
5啸蜜、React如何實(shí)現(xiàn)組件化:大家注意,React中有組件化的概念辈挂,但是衬横,并沒有像vue這樣的組件模板文件;React中呢岗,一切都是以JS來表現(xiàn)的冕香;因此要學(xué)習(xí)React蛹尝,JS要合格后豫;ES6 和 ES7 (async 和 await) 要會(huì)用;
- 開發(fā)團(tuán)隊(duì)方面
1突那、React是由FaceBook前端官方團(tuán)隊(duì)進(jìn)行維護(hù)和更新的挫酿;因此,React的維護(hù)開發(fā)團(tuán)隊(duì)愕难,技術(shù)實(shí)力比較雄厚早龟;
2、Vue:第一版猫缭,主要是有作者 尤雨溪 專門進(jìn)行維護(hù)的葱弟,當(dāng) Vue更新到 2.x 版本后,也有了一個(gè)以 尤雨溪 為主導(dǎo)的開源小團(tuán)隊(duì)猜丹,進(jìn)行相關(guān)的開發(fā)和維護(hù)芝加;
- 社區(qū)方面
1、在社區(qū)方面射窒,React由于誕生的較早藏杖,所以社區(qū)比較強(qiáng)大,一些常見的問題脉顿、坑蝌麸、最優(yōu)解決方案,文檔艾疟、博客在社區(qū)中都是可以很方便就能找到的来吩;
1蔽莱、Vue是近兩年才火起來的弟疆,所以帜羊,它的社區(qū)相對(duì)于React來說咒程,要小一些讼育,可能有的一些坑帐姻,沒人踩過;
- 移動(dòng)APP開發(fā)體驗(yàn)方面
1奶段、Vue饥瓷,結(jié)合 Weex 這門技術(shù),提供了 遷移到 移動(dòng)端App開發(fā)的體驗(yàn)(Weex痹籍,目前只是一個(gè) 小的玩具呢铆, 并沒有很成功的 大案例;)
2蹲缠、React棺克,結(jié)合 ReactNative,也提供了無縫遷移到 移動(dòng)App的開發(fā)體驗(yàn)(RN用的最多线定,也是最火最流行的)娜谊;
為什么要學(xué)習(xí)React
- 和Angular1相比,React設(shè)計(jì)很優(yōu)秀斤讥,一切基于JS并且實(shí)現(xiàn)了組件化開發(fā)的思想纱皆;
- 開發(fā)團(tuán)隊(duì)實(shí)力強(qiáng)悍,不必?fù)?dān)心斷更的情況周偎;
- 社區(qū)強(qiáng)大抹剩,很多問題都能找到對(duì)應(yīng)的解決方案;
- 提供了無縫轉(zhuǎn)到 ReactNative 上的開發(fā)體驗(yàn)蓉坎,讓我們技術(shù)能力得到了拓展澳眷;增強(qiáng)了我們的核心競爭力;
- 很多企業(yè)中蛉艾,前端項(xiàng)目的技術(shù)選型采用的是React.js钳踊;
React中幾個(gè)核心的概念
- 虛擬DOM(Virtual Document Object Model)
1、DOM的本質(zhì)是什么:瀏覽器中的概念勿侯,用JS對(duì)象來表示 頁面上的元素拓瞪,并提供了操作 DOM 對(duì)象的API;
2助琐、什么是React中的虛擬DOM:是框架中的概念祭埂,是程序員 用JS對(duì)象來模擬 頁面上的 DOM 和 DOM嵌套;
3、為什么要實(shí)現(xiàn)虛擬DOM(虛擬DOM的目的):為了實(shí)現(xiàn)頁面中蛆橡, DOM 元素的高效更新
4舌界、DOM和虛擬DOM的區(qū)別:
DOM
:瀏覽器中,提供的概念泰演;用JS對(duì)象呻拌,表示頁面上的元素,并提供了操作元素的API睦焕;
虛擬DOM
:是框架中的概念藐握;而是開發(fā)框架的程序員,手動(dòng)用JS對(duì)象來模擬DOM元素和嵌套關(guān)系垃喊;本質(zhì): 用JS對(duì)象猾普,來模擬DOM元素和嵌套關(guān)系;目的:就是為了實(shí)現(xiàn)頁面元素的高效更新缔御;
- Diff算法
1抬闷、tree diff:新舊兩棵DOM樹妇蛀,逐層對(duì)比的過程耕突,就是 Tree Diff; 當(dāng)整顆DOM逐層對(duì)比完畢评架,則所有需要被按需更新的元素眷茁,必然能夠找到;
2纵诞、component diff:在進(jìn)行Tree Diff的時(shí)候上祈,每一層中,組件級(jí)別的對(duì)比浙芙,叫做 Component Diff登刺;
如果對(duì)比前后,組件的類型相同嗡呼,則**暫時(shí)**認(rèn)為此組件不需要被更新纸俭;
如果對(duì)比前后,組件類型不同南窗,則需要移除舊組件揍很,創(chuàng)建新組件,并追加到頁面上万伤;
3窒悔、element diff:在進(jìn)行組件對(duì)比的時(shí)候,如果兩個(gè)組件類型相同敌买,則需要進(jìn)行 元素級(jí)別的對(duì)比简珠,這叫做 Element Diff;
創(chuàng)建基本的webpack4.x項(xiàng)目
- 運(yùn)行
npm init -y
快速初始化項(xiàng)目 - 在項(xiàng)目根目錄創(chuàng)建
src
源代碼目錄和dist
產(chǎn)品目錄 - 在 src 目錄下創(chuàng)建
index.html
- 使用 cnpm 安裝 webpack 虹钮,運(yùn)行
cnpm i webpack webpack-cli -D
(如何安裝cnpm
: 全局運(yùn)行npm i cnpm -g
) - 注意:webpack 4.x 提供了 約定大于配置的概念聋庵;目的是為了盡量減少 配置文件的體積荐操;
- 默認(rèn)約定了:
- 打包的入口是
src
->index.js
- 打包的輸出文件是
dist
->main.js
- 4.x 中 新增了
mode
選項(xiàng)(為必選項(xiàng)),可選的值為:development
和production
;
使用 create-react-app 快速構(gòu)建 React 開發(fā)環(huán)境
可以使用create-react-app -V查看當(dāng)前版本
npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start
打包發(fā)布
npm run build
npm install -g serve
serve build
訪問http://localhost:5000/
項(xiàng)目中使用antd
npm i antd
//實(shí)現(xiàn)組件的按需打包
npm i react-app-rewired customize-cra babel-plugin-import
在項(xiàng)目中使用 react
運(yùn)行
cnpm i react react-dom -S
安裝包
react: 專門用于創(chuàng)建組件和虛擬DOM的珍策,同時(shí)組件的生命周期都在這個(gè)包中
react-dom: 專門進(jìn)行DOM操作的托启,最主要的應(yīng)用場景,就是ReactDOM.render()
在
index.html
頁面中攘宙,創(chuàng)建容器:
<!--html-- 容器屯耸,將來,使用 React 創(chuàng)建的虛擬DOM元素蹭劈,都會(huì)被渲染到這個(gè)指定的容器中 -->
<div id="app"></div>
- 導(dǎo)入包:
//js
import React from 'react'
import ReactDOM from 'react-dom'
- 創(chuàng)建虛擬DOM元素:
//jsx
// 這是 創(chuàng)建虛擬DOM元素的 API
<h1 title="啊疗绣,五環(huán)" id="myh1">你比四環(huán)多一環(huán)</h1>
// 第一個(gè)參數(shù): 字符串類型的參數(shù),表示要?jiǎng)?chuàng)建的標(biāo)簽的名稱
// 第二個(gè)參數(shù):對(duì)象類型的參數(shù)铺韧, 表示 創(chuàng)建的元素的屬性節(jié)點(diǎn)
// 第三個(gè)參數(shù): 子節(jié)點(diǎn)
const myh1 = React.createElement('h1', { title: '啊多矮,五環(huán)', id: 'myh1' }, '你比四環(huán)多一環(huán)')
- 渲染:
//js
// 3. 渲染虛擬DOM元素
// 參數(shù)1: 表示要渲染的虛擬DOM對(duì)象
// 參數(shù)2: 指定容器,注意:這里不能直接放 容器元素的Id字符串,需要放一個(gè)容器的DOM對(duì)象
ReactDOM.render(myh1, document.getElementById('app'))
JSX語法
什么是JSX語法:就是符合 xml 規(guī)范的 JS 語法哈打;(語法格式相對(duì)來說塔逃,要比HTML嚴(yán)謹(jǐn)很多) webpack是不能識(shí)別jsx的語法的 需要babel包將其轉(zhuǎn)換為React.creatElement()
-
如何啟用 jsx 語法?
- 安裝能夠識(shí)別轉(zhuǎn)換jsx語法的包
babel/preset-react
- 運(yùn)行
cnpm i @babel/preset-react -D
- 添加
.babelrc
配置文件(新建一個(gè)名為.babelrc的文件)
{ "presets": ["@babel/preset- env","@babel/preset-react"], "plugins": [ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties" ] }
- 添加babel-loader配置項(xiàng)(在webpack.config.js文件中):
https://www.cnblogs.com/amcy/p/10273929.htmlmodule: { //要打包的第三方模塊 rules: [ { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ } ] }
- 安裝能夠識(shí)別轉(zhuǎn)換jsx語法的包
-
jsx 語法的本質(zhì)
并不是直接把 jsx 渲染到頁面上料仗,而是 內(nèi)部先轉(zhuǎn)換成了 createElement 形式湾盗,再渲染的;
3.在 jsx 中混合寫入 js 表達(dá)式
在 jsx 語法中立轧,要把 JS代碼寫到 { }
中:
- 渲染數(shù)字
- 渲染字符串
- 渲染布爾值
- 為屬性綁定值
- 渲染jsx元素
- 渲染jsx元素?cái)?shù)組
- 將普通字符串?dāng)?shù)組格粪,轉(zhuǎn)為jsx數(shù)組并渲染到頁面上【兩種方案】
第一種方法:把字符串?dāng)?shù)組轉(zhuǎn)換為元素?cái)?shù)組
第二種方法:使用map{array.map(item=><h3>{item}</h3>)}
使用key屬性
應(yīng)用在被for foreach map等循環(huán)直接空值得反訴上
例:
//創(chuàng)建虛擬DOM元素:
const obj={name:"趙靜怡",age:18,title:"哈哈"}
const myh2=<h2>我是h2</h2>
var flag=true;
const mydiv=<div>
{obj.name}<!--js語法寫在{}里 !-->
<h1 title={obj.title}>{obj.age}</h1><!--直接綁定屬性弃揽,不需要“:” !-->
{myh2}
<div>{flag?1:2}</div>
</div>
//渲染:
ReactDOM.render(mydiv,document.getElementById("app"))
遍歷方式:
//1.普通方式:
var arr=[]
var obj=["A","B","C"];
obj.forEach((item,index)=>{
arr.push(<h1 key={index}>{item}</h1>)
})
const mydiv=<div>{arr}</div>
//渲染
ReactDOM.render(mydiv,document.getElementById("app"))
//2.Map方式:
var obj=["A","B","C"];
const mydiv=<div className="box">
{obj.map((item,index)=><h2 key={index}>{item}</h2>)}
<p>
<input type="checkbox" value="A" id="A"/>
<label htmlFor="A">A</label>
</p>
</div>
<!--渲染!-->
ReactDOM.render(mydiv,document.getElementById("app"))
<!--遍歷時(shí)一定要傳入key!-->
注意:
-
在 jsx 中 寫注釋:推薦使用
{ /* 這是注釋 */ }
-
為 jsx 中的元素添加class類名:需要使用
className
來替代class
矾兜;htmlFor
替換label的for
屬性 - 在JSX創(chuàng)建DOM的時(shí)候滚朵,所有的節(jié)點(diǎn)峰鄙,必須有唯一的根元素進(jìn)行包裹塔次;
- 在 jsx 語法中户魏,標(biāo)簽必須 成對(duì)出現(xiàn)蟆沫,如果是單標(biāo)簽异雁,則必須自閉和瑰艘!
- 當(dāng) 編譯引擎是鬼,在編譯JSX代碼的時(shí)候,如果遇到了
<
那么就把它當(dāng)作 HTML代碼去編譯紫新,如果遇到了{}
就把 花括號(hào)內(nèi)部的代碼當(dāng)作 普通JS代碼去編譯均蜜;
React中創(chuàng)建組件
第1種 - 創(chuàng)建組件的方式
使用構(gòu)造函數(shù)來創(chuàng)建組件,如果要接收外界傳遞的數(shù)據(jù)芒率,需要在 構(gòu)造函數(shù)的參數(shù)列表中使用
props
來接收囤耳;必須要向外return一個(gè)合法的JSX創(chuàng)建的虛擬DOM;
-
創(chuàng)建組件:
function Hello () { // return null return <div>Hello 組件</div> }
-
為組件傳遞數(shù)據(jù):
// 使用組件并 為組件傳遞 props 數(shù)據(jù)(綁定自定義屬性) <Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello> // 在構(gòu)造函數(shù)中,使用 props 形參充择,接收外界 傳遞過來的數(shù)據(jù) function Hello(props) { // props.name = 'zs' console.log(props) // 結(jié)論:不論是 Vue 還是 React德玫,組件中的 props 永遠(yuǎn)都是只讀的;不能被重新賦值椎麦; return <div>這是 Hello 組件 --- {props.name} --- {props.age} --- {props.gender} </div> }
-
抽離組件
- 在src目錄中新建
components
目錄來存儲(chǔ)組件 - 在components目錄中新建
.jsx
文件 - 在文件中導(dǎo)入
Reacct(import React from "react")
宰僧,因?yàn)樵诮M件中使用了jsx的{} - 在
.jsx
文件中定義組件,并拋出export default function Person(props){ return <h1>{props.name}</h1>; }
- 在父組件中js中引入組件
import Person from "@/components/person"
- 在src目錄中新建
-
在導(dǎo)入組件的時(shí)候观挎,如何省略組件的
.jsx
后綴名:
在導(dǎo)入組件的時(shí)候琴儿,配置和使用@
路徑符號(hào)// 打開 webpack.config.js ,并在導(dǎo)出的配置對(duì)象中嘁捷,新增 如下節(jié)點(diǎn): resolve: { extensions: ['.js', '.jsx', '.json'], // 表示造成,這幾個(gè)文件的后綴名,可以省略不寫 alias: { '@': path.join(__dirname, './src')//配置”@” } }
-
例:
//創(chuàng)建組件 function Person(props){ return <h1>{props.name}</h1>;//子組件接收數(shù)據(jù) } const obj={name:"小明",age:20,sex:"男"} const mydiv=<div className="box"> <!--注釋 !--> {/*<Person name={obj.name}></Person>*/} <!--父組件傳參!--> <Person {...obj}></Person> </div>
-
注意:
- 父組件向子組件傳遞數(shù)據(jù)
給子組件名稱綁定自定義屬性雄嚣,在子組件中用props來接收
- 使用
{...obj}
屬性擴(kuò)散傳遞數(shù)據(jù)<Hello {...obj}></Hello>
- 將組件封裝到單獨(dú)的文件中
- 組件的名稱首字母必須是大寫
- 父組件向子組件傳遞數(shù)據(jù)
第2種 - 創(chuàng)建組件的方式
使用 class 關(guān)鍵字來創(chuàng)建組件
ES6 中 class 關(guān)鍵字晒屎,是實(shí)現(xiàn)面向?qū)ο缶幊痰男滦问剑?/p>
- 了解ES6中 class 關(guān)鍵字的使用
- class 中
constructor
的基本使用 - 實(shí)例屬性和實(shí)例方法
- 靜態(tài)屬性和靜態(tài)方法
- 使用
extends
關(guān)鍵字實(shí)現(xiàn)繼承
- class 中
- 基于
class
關(guān)鍵字創(chuàng)建組件-
最基本的組件結(jié)構(gòu):
class 組件名稱 extends React.Component { constructor(){ super(); this.state={ //定義自己私有數(shù)據(jù),相當(dāng)于 vue組件中的data(),this.state中的數(shù)據(jù)可讀可寫,props中的數(shù)據(jù)只能讀 } } //作用 將里面的內(nèi)容輸出 render(){ return 符合標(biāo)準(zhǔn)的jsx語法的串 } }
-
兩種創(chuàng)建組件方式的對(duì)比
1. 用構(gòu)造函數(shù)
創(chuàng)建出來的組件:叫做“無狀態(tài)組件”
,沒有自己的私有數(shù)據(jù)和生命周期函數(shù)
2. 用class關(guān)鍵字
創(chuàng)建出來的組件:叫做“有狀態(tài)組件”
缓升,有自己的私有數(shù)據(jù)和生命周期函數(shù)
有狀態(tài)組件和無狀態(tài)組件之間的**本質(zhì)區(qū)別**就是:有無state屬性!
props和state/data的區(qū)別
props中的數(shù)據(jù)都是外界的 并且是可讀的不可寫的
state/data中的數(shù)據(jù)都是自己私有的 并且是可讀可寫的
ES6 class類
如果要生成一個(gè)對(duì)象實(shí)例成福,需要先定義一個(gè)構(gòu)造函數(shù)蕴潦,然后通過new操作符來完成。構(gòu)造函數(shù)示例:
//函數(shù)名和實(shí)例化構(gòu)造名相同且大寫(非強(qiáng)制,但這么寫有助于區(qū)分構(gòu)造函數(shù)和普通函數(shù))
function Person(name,age) {
this.name = name;
this.age=age;
}
Person.prototype.say = function(){
return "我的名字叫" + this.name+"今年"+this.age+"歲了";
}
//通過構(gòu)造函數(shù)創(chuàng)建對(duì)象蹦骑,必須使用new 運(yùn)算符
var obj=new Person("laotie",88);
console.log(obj.say());//我的名字叫l(wèi)aotie今年88歲了
React中組件傳值
-
父傳子
- 在父組件中給子組件綁定自定義屬性 屬性={數(shù)據(jù)}
- 在子組件中用this.props.屬性,接收數(shù)據(jù)
-
子傳父
- 在父組件中定義方法(在父組件中設(shè)置事件觸發(fā)的函數(shù))
- 在父組件中給子組件綁定自定義事件谜叹,接收父組件的方法
- 在子組件的某一個(gè)方法中通過 this.props.事件名 來調(diào)用函數(shù),傳遞需要的參數(shù)即可
兄弟傳值
先子傳父 在父傳子-
例:
import React from 'react' import ReactDOM from 'react-dom' class Head extends React.Component{ constructor(){ super(); this.state={ //定義自己的數(shù)據(jù) color:"red", size:"30px" } } //輸入內(nèi)容猜年,返回一個(gè)符合標(biāo)準(zhǔn)的jsx語法的串 render(){ return <div style= {{background:this.state.color,fontSize:this.state.size}}> //設(shè)置樣式用兩個(gè){} 大家好我是頭 </div> } } //父組件 class Content extends React.Component{ constructor(){ super(); this.state={ color:"green", obj:"" } } // ————1.在父組件中定義方法(子傳父) getData(data) { this.setState({ obj: data }) } render(){ return <div> 大家好我是內(nèi)容 {this.state.obj} { /* 1.在父組件中給子組件綁定自定義屬性一罩,接收父組件的數(shù)據(jù)(父傳子) */ } { /* ————2.在父組件的子組件中定義自定義事件接收父組件的事件(子傳父) */ } <Son1 pro1={this.state.color} getData={(data) => { this.getData(data) }}/> <Son2 pro2={this.state.obj}/> </div> } } //子組件 class Son1 extends React.Component{ constructor(){ super(); this.state={ con:"我是son1的數(shù)據(jù)" } } toFa(data) { // ————3.在子組件的事件中接收自定義事件并傳參(子傳父) this.props.getData(data) } //返回符合要求的jsx串 render(){ return <div style={{color:this.props.pro1}}> { /* 2.在子組件中接收父組件的傳值(父傳子) */ } 我是content的------兒子{this.props.pro1} { /* ————4.在子組件中調(diào)用事件并傳參(子傳父) */ } <input type='button' value='傳值' onClick={(e) => { this.toFa(this.state.con) }}/> </div> } } //子組件 class Son2 extends React.Component{ constructor(){ super(); this.state={ } } render(){ return <div> //兄弟組件傳值暖夭,先子傳父奴潘,再父傳子 {this.props.pro2} </div> } }
React中的樣式問題
-
行內(nèi)樣式
在組件中是可以加行內(nèi)樣式的 但是 需要一定的格式
style={ 對(duì)象 } 對(duì)象可以是一個(gè)單獨(dú)的js變量 也可以直接寫在里面
1. style={ {color:'red',fontSize:'20px'} }
2. const hcss={color:'red',fontSize:'20px'};
style={hcss}
例:const hcss={color:"red",fontSize:"30px"}; class Home extends React.Component{ render(){ return <div> <p style={{color:"red"}}>直接寫在里面</p> <p style={hcss}>在外面定義/p> </div> } }
-
外部樣式
- 在react中可以給樣式設(shè)置模塊化
- 在webpack.config.js中給css-loader這個(gè)loader設(shè)置modules參數(shù)
{test:/\.css$/,use:['style-loader','css-loader?modules']}
- 需要注意的是:如果加上這個(gè)參數(shù)夺谁,在普通的css中會(huì)將類選擇器厚者、id 選擇器躁劣,轉(zhuǎn)換成對(duì)象的形式 用的時(shí)候直接在引入的對(duì)象上.類名
(對(duì)象.類名)
- 這樣給樣式設(shè)置了作用域,可以保證不同的組件中可以
避免類名的沖突
。但是库菲,標(biāo)簽選擇器是不會(huì)被編譯的 - 我們自己認(rèn)為 第三方的樣式都是.css結(jié)尾的 我們沒有必要去給他們做模塊化 所以我們約定在webpack.config.js中一般只給后綴名為less和scss的文件設(shè)置模塊化
{test:/\.less$/,use:['style-loader','css-loader?modules','less-loader']}, {test:/\.scss$/,use:['style-loader','css-loader? modules','sass-loader']},
例:
//src里css目錄下的list.css .title{ width: 100px; height: 40px; border: 1px solid blue; } //index.js里 import list from "@/css/1.css";//引入樣式,list是一個(gè)對(duì)象 class Home extends React.Component{ render(){ return <div> <p className={list.tatle}>模塊化后</p> <p className="tatle">沒有模塊化</p> </div> } }
兄弟組件的并列寫
將兄弟組件用標(biāo)簽包起來志膀,語法:
ReactDOM.render(<div>組件1組件2</div>,document.getElementById("app"))
例:
ReactDOM.render(<div>
<Login/>
<Register/>
</div>,document.getElementById("app"))
事件綁定及修改組件的值
- 語法:on事件名 事件名的首字母大寫
onClick={this.方法名}
方法名是組件中的方法 - 事件的綁定方式一(不推薦)
事件名使用的是小駝峰命名熙宇,事件={this.方法名}//add后不可加() <input type="button" value="add" onClick={this.add}/> class Home extends React.Component{ constructor(){ super(); this.state={ name:'哈哈' } //重新綁定this指向 this.add=this.add.bind(this); } add(){ //修改組件數(shù)據(jù) this.setState({ name:"呵呵" }) //在事件里,this.state.name中的this指向已經(jīng)改變溉浙,所以需要重新綁定this alert(this.state.name); } render(){ return <div className={list.tatle}> {this.state.data}<!--調(diào)用組件數(shù)據(jù)!--> </div> } }
- 事件的綁定方式二(推薦)
利用箭頭函數(shù)綁定事件 因?yàn)樗鼪]有自己的this指向
<input type="button" value="add" onClick={(e)=> {this.add(e)}} /> add(e){ //e.target是當(dāng)前原生dom元素 }
- 修改組件的值
- 若要修改組件自己私有的數(shù)據(jù)烫止,即this.state里的數(shù)據(jù)不可以直接修改,需要通過一個(gè)異步的方法
this.setState({屬性:新修改后的值})
修改this.setState({ name:e.target.value })
- this.setstate()方法 注意:
只是修改某一個(gè)或者某幾個(gè)要更新的數(shù)據(jù) 而不會(huì)覆蓋
此方法是一個(gè)異步管理狀態(tài)的函數(shù)
- 若要修改組件自己私有的數(shù)據(jù)烫止,即this.state里的數(shù)據(jù)不可以直接修改,需要通過一個(gè)異步的方法
react實(shí)現(xiàn)的雙向數(shù)據(jù)綁定
-
步驟:
- 給表單元素添加事件
onChange={(e)=>{this.方法名(e)}}
- 在組件中定義方法
方法名(e){ // e.target 是當(dāng)前原生的dom元素 //修改name屬性的值 this.setState({ name:e.target.value }) }
- 給表單元素設(shè)置 value屬性 等于剛才修改的那個(gè)屬性的值
value={this.state.name}
- 給表單元素添加事件
-
案例:
class Test extends React.Component{ constructor(){ super(), this.state={ son:"誰是兒子", name:'' } } add(){ this.setState({ name:'哈哈' }) } //2. 在組件中定義方法 changename(e){ this.setState({ name:e.target.value }) } render(){ return <div style={{background:'red'}}><!-- 行內(nèi)樣式 !--> <!-- 1. 給表單元素添加事件 !--> <!-- 3. 給表單元素設(shè)置 value屬性 !--> <input type='text' value={this.state.name} onChange={(e)=>{this.changename(e)}}/> 輸入的數(shù)據(jù)是{this.state.name} </div> } }
組件的應(yīng)用方式
容器組件和單純組件
class Test extends React.Component{
render(){
return <div>
<!-- 加上這個(gè)就變成了容器組件用來來顯示在組件標(biāo)簽中的孩子 !-->
{this.props.children}
</div>
}
}
class App extends React.Component{
constructor(){
super();
this.state={
data:"大家好"
}
}
render(){
return <div>
<Test>
<span>呵呵</span>
</Test>
</div>
}
}
組件的生命周期
每個(gè)組件的實(shí)例從創(chuàng)建到運(yùn)行直到銷毀
在這個(gè)過程中會(huì)觸發(fā)一系列的事件
戳稽,這些事件就是生命周期的函數(shù)
react的生命周期分為三部分:
組件的
創(chuàng)建階段
特點(diǎn)一輩子只運(yùn)行一次
constructor()
componentWillMount()
在組件掛載到DOM前調(diào)用
Render()
react最重要的步驟馆蠕,創(chuàng)建虛擬dom期升,進(jìn)行diff算法,更新dom樹都在此進(jìn)行互躬。此時(shí)就不能更改state了播赁。
componentDidMount()
組件掛載到DOM后調(diào)用組件的
運(yùn)行階段
特點(diǎn)根據(jù)props和state的值得改變執(zhí)行0此或者多次
shouldComponentUpdate()
componentWillUpdate()
組件更新前被調(diào)用
componentDidUpdate()
組件更新后被調(diào)用,可以操作組件更新的DOM
componentWillReceiveProps()
組件接受新的props時(shí)調(diào)用-
組件的
銷毀階段
特點(diǎn)一輩子只運(yùn)行一次
componentWillUnmount()
組件被卸載前調(diào)用
路由
參考網(wǎng)站
http://www.reibang.com/p/875225b2ec90
https://blog.csdn.net/dongyuxu342719/article/details/86542904-
前端路由
Ajax誕生以后吼渡,解決了每次用戶操作都要向服務(wù)器端發(fā)起請(qǐng)求重刷整個(gè)頁面的問題容为,但隨之而來的問題是無法保存Ajax操作狀態(tài),瀏覽器的前進(jìn)后退功能也不可用寺酪,當(dāng)下流行的兩種解決方法是:hash:hash原本的作用是為一個(gè)很長的文檔頁添加錨點(diǎn)信息坎背,它自帶不改變url刷新頁面的功能寄雀,所以自然而然被用在記錄Ajax操作狀態(tài)中了。
history:應(yīng)該說history是主流的解決方案阿趁,瀏覽器的前進(jìn)后退用的就是這個(gè)膜蛔,它是window對(duì)象下的,以前的history提供的方法只能做頁面之間的前進(jìn)后退脖阵,如下:
history.go(number|URL)
可加載歷史列表中的某個(gè)具體的頁面
history.forward()
可加載歷史列表中的下一個(gè) URL
history.back()
可加載歷史列表中的前一個(gè) URL
為了讓history不僅僅能回退到上一個(gè)頁面皂股,還可以回到上一個(gè)操作狀態(tài)。HTML5新增了三個(gè)方法命黔,其中兩個(gè)是在history對(duì)象里的:
history.pushState(state, title, url)
添加一條歷史記錄呜呐, state用于傳遞參數(shù),可以為空悍募。title是設(shè)置歷史記錄的標(biāo)題蘑辑,可以為空。url是歷史記錄的URL坠宴,不可以為空洋魂。
history.replaceState(state, title, url)
將history堆棧中當(dāng)前的記錄替換成這里的url,參數(shù)同上喜鼓。
還有一個(gè)事件在window對(duì)象下:
window.onpopstate()
監(jiān)聽url的變化副砍,會(huì)忽略hash的變化(hash變化有一個(gè)onhashchange事件),但是前面的兩個(gè)事件不會(huì)觸發(fā)它庄岖。
路由的使用:路由需要的包 react-router-dom 這個(gè)包內(nèi)部依賴于react-router 所以不用手動(dòng)的安裝react-router(cnpm i react-router-dom -S) 前端路由的原理
根據(jù)前端開發(fā)人員自定義的路徑 顯示不同的組件 來達(dá)到頁面的切換效果 但是設(shè)置的這些路徑在后端是沒有 所以history路由有一個(gè)弊端 有時(shí)候?yàn)g覽器會(huì)根據(jù)自己這個(gè)這個(gè)前端的路徑去訪問后臺(tái)的頁面 就會(huì)請(qǐng)求不到報(bào)404 所以得需要前端的開發(fā)人員在webpack中進(jìn)行設(shè)置 這個(gè)路由的路徑就不用請(qǐng)求后端了 以免發(fā)生請(qǐng)求資源不存在-
location對(duì)象的常用的三個(gè)屬性
-
location.href
獲取當(dāng)前的路徑 -
locathon.hash
獲取當(dāng)前的hash值 -
location.search
獲取當(dāng)前的查詢參數(shù)
-
-
hash路由
當(dāng)hash值發(fā)生改變的時(shí)候會(huì)觸發(fā)事件onhashchange
事件
頁面路由 window.location.href='www.baidu.com'
histtory.back()window.location='#hash' window.onhashchange=function(){ window.location.hash 當(dāng)前路由 }
-
history路由
這個(gè)是瀏覽器的history對(duì)象 新增了兩個(gè)方法history.pushState(state, title, url)
history.replaceState(state, title, url)
window.onpopstate()
監(jiān)聽url的變化豁翎,會(huì)忽略hash的變化history.pushState('name',‘title’隅忿,‘/path’) history.replaceState('name'心剥,‘title’邦尊,‘/path’) window.onpopstate=function(){ console.log(window.location.href); console.log(window.location.pathname); console.log(window.location.query); console.log(window.location.search); }
-
按需加載 as關(guān)鍵字后面是別名
import { HashRouter(哈希路由)/BrowserRouter(history路由) as Router, Link, Navlink, Switch, Route, Redirect } from 'react-router-dom'
-
路由方式
常用的兩種路由
react-router-dom的Router有四種,常用的兩種是:<BrowserRouter>
H5路由<HashRouter>
hash路由
<Route>
設(shè)置路由規(guī)則
<Switch>
路由選項(xiàng)优烧,里面包含匹配規(guī)則 會(huì)匹配到第一個(gè)匹配到的路由 如果和<Router> 配合使用 必須包含在<Router>的里面 在子組件中也可以單獨(dú)使用 在渲染虛擬dom時(shí)候放在<Router> 里面
<Redirect>
重定向
<Link>/<NavLink>
路由導(dǎo)航
<Link>
鏈接 轉(zhuǎn)換為a標(biāo)簽
<NavLink>
導(dǎo)航鏈接 可以設(shè)置樣式 更適合導(dǎo)航
注意:NavLink和Link的區(qū)別 NavLink在選中的時(shí)候會(huì)添加選中類 .active 可以在這個(gè)類上設(shè)置選中的樣式<NavLink to="/list" activeClassName={appscss.active}>列表</NavLink>
-
react-router中的exact和strict
參考網(wǎng)站:http://www.reibang.com/p/afe46a62a7baexact
exact默認(rèn)為false蝉揍,如果為true時(shí),需要和路由相同時(shí)才能匹配匙隔,但是如果有斜杠也是可以匹配上的疑苫。
如果在父路由中加了exact,是不能匹配子路由的,建議在子路由中加exact
strict
<Route strict path="/one" component={About} />
strict默認(rèn)為false纷责,如果為true時(shí)捍掺,路由后面有斜杠而url中沒有斜杠,是不匹配的案例:
總結(jié):
如果沒有子路由的情況再膳,建議大家配都加一個(gè)exact挺勿;如果有子路由,建議在子路由中加exact喂柒,父路由不加不瓶;
而strict是針對(duì)是否有斜杠的,一般可以忽略不配置灾杰。
定義方式
<Route path='自定義' compontent/>要被包裹在HashRouter中
-
案例
需求:當(dāng)訪問 / 顯示出home組件
步驟:- 引入包
import {HashRouter as Router,Route} from 'react-router-dom'
- 做了容器組件 App 在render中 {this.props.children}
- 做的home組件
- 配置的規(guī)則蚊丐,這個(gè)規(guī)則屬于一個(gè)入口的規(guī)則 ,如果在子組件中需要路由就去子組件中配置即可
<Router> <App> <Route path='/' component={Home} /> </App> </Router>
需求: 在home組件中艳吠,有兩個(gè)標(biāo)題:用戶列表麦备、商品列表,點(diǎn)擊顯示不同頁面
步驟:- 在home組件中設(shè)置 <NavLink><NavLink> 做導(dǎo)航鏈接
- 在home組件中配置規(guī)則
<Switch> <Route path='/user' component={User} /> <Route path='/goods' component={Goods} /> <Redirect from='/' to='/user'/> </Switch>
- 引入包
路由傳參
-
params
<Route path='/path/:name' component={Path}/> <!-- 跳轉(zhuǎn) !--> <link to="/path/2">xxx</Link> this.props.history.push({pathname:"/path/" + name}); <!-- 讀取參數(shù) !--> this.props.match.params.name
優(yōu)勢(shì):刷新地址欄昭娩,參數(shù)依然存在
缺點(diǎn):只能傳字符串凛篙,并且,如果傳的值太多的話栏渺,url會(huì)變得長而丑陋呛梆。 -
query
<Route path='/query' component={Query}/> <!-- 跳轉(zhuǎn) !--> <Link to={{ path : ' /query' , query : { name : 'sunny' }}}> this.props.history.push({pathname:"/query",query: { name : 'sunny' }}); <!-- 讀取參數(shù) !--> this.props.location.query.name
優(yōu)勢(shì):傳參優(yōu)雅,傳遞參數(shù)可傳對(duì)象磕诊;
缺點(diǎn):刷新地址欄填物,參數(shù)丟失 -
state
<Route path='/sort ' component={Sort}/> <!-- 跳轉(zhuǎn) !--> <Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}> this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }}); <!-- 讀取參數(shù) !--> this.props.location.query.state
優(yōu)缺點(diǎn)同query
-
search
<Route path='/web/departManange ' component={DepartManange}/> <!-- 跳轉(zhuǎn) !--> <link to="web/departManange?tenantId=12121212">xxx</Link> this.props.history.push({pathname:"/web/departManange?tenantId" + row.tenantId}); <!-- 讀取參數(shù) !--> this.props.location.search
優(yōu)缺點(diǎn)同params
-
方式一:通過params
- 路由表中
<Route path=' /sort/:id ' component={Sort}></Route>
- Link處
// HTML方式 <Link to={ ' /sort/ ' + ' 2 ' } activeClassName='active'>XXXX</Link> //JS方式 this.props.history.push( '/sort/'+'2' )
- sort頁面
通過:this.props.match.params.id
,就可以接受到傳遞過來的參數(shù)(id)
- 路由表中
-
方式二:通過query
前提:必須由其他頁面跳過來霎终,參數(shù)才會(huì)被傳遞過來
注:不需要配置路由表融痛。路由表中的內(nèi)容照常:
<Route path='/sort' component={Sort}></Route>
- Link處
//HTML方式 <Link to={{ path : ' /sort ' , query : { name : 'sunny' }}}> //JS方式 this.props.history.push({ path : '/sort' ,query : { name: ' sunny'} })
- sort頁面
this.props.location.query.name
- Link處
-
方式三:通過state
同query差不多,只是屬性不一樣神僵,而且state傳的參數(shù)是加密
的,query傳的參數(shù)是公開
的覆劈,在地址欄
- Link 處
//HTML方式: <Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}> //JS方式: this.props.history.push({ pathname:'/sort',state:{name : 'sunny' } })
- sort頁面
this.props.location.state.name
- Link 處
本地存儲(chǔ)
componentWillMount()
初始化的時(shí)候在這個(gè)方法中讀取localStorage的值
綁定回車事件
onKeyPress={(e)=>this.addlist(e)}
addlist(e){
if(e.which!=13) return false
console.log('我點(diǎn)擊了回車鍵');
}
獲取真實(shí)dom
首先給元素 添加一個(gè) ref屬性 ref="變量"
在方法中通過 this.refs.變量
來獲取真實(shí)的dom元素
http://www.todolist.cn/
https://www.bootcdn.cn/
https://webthemez.com/demo/insight-free-bootstrap-html5-admin-template/index.html
Redux
Redux是針對(duì)JavaScript應(yīng)用的可預(yù)測狀態(tài)容器
就是一個(gè)應(yīng)用的state管理庫 組件之間數(shù)據(jù)共享
redux 是一個(gè)狀態(tài)管理器保礼,那什么是狀態(tài)呢沛励?狀態(tài)就是數(shù)據(jù)
可預(yù)測性(predictable)
: 因?yàn)镽edux用了reducer與純函數(shù)(pure function)的概念,每個(gè)新的state都會(huì)由舊的state建來一個(gè)全新的state炮障。因而所有的狀態(tài)修改都是”可預(yù)測的”目派。
狀態(tài)容器(state container)
: state是集中在單一個(gè)對(duì)象樹狀結(jié)構(gòu)下的單一store,store即是應(yīng)用程序領(lǐng)域(app domain)的狀態(tài)集合胁赢。
JavaScript應(yīng)用
: 這說明Redux并不是單指設(shè)計(jì)給React用的企蹭,它是獨(dú)立的一個(gè)函數(shù)庫,可通用于各種JavaScript應(yīng)用智末。
Redux模型中的幾個(gè)組成對(duì)象:action 谅摄、reducer、store
系馆。
action
:官方的解釋是action是把數(shù)據(jù)從應(yīng)用傳到 store 的有效載荷送漠,它是 store 數(shù)據(jù)的唯一來源;要通過本地或遠(yuǎn)程組件更改狀態(tài)由蘑,需要分發(fā)一個(gè)action闽寡;
reducer
:action發(fā)出了做某件事的請(qǐng)求,只是描述了要做某件事尼酿,并沒有去改變state來更新界面爷狈,reducer就是根據(jù)action的type來處理不同的事件;
store
:store就是把a(bǔ)ction和reducer聯(lián)系到一起的對(duì)象裳擎,store本質(zhì)上是一個(gè)狀態(tài)樹涎永,保存了所有對(duì)象的狀態(tài)。任何UI組件都可以直接從store訪問特定對(duì)象的狀態(tài)句惯。
運(yùn)行流程
在Redux中土辩,所有的數(shù)據(jù)(比如state)被保存在一個(gè)被稱為store的容器中 ,在一個(gè)應(yīng)用程序中只能有一個(gè)store對(duì)象抢野。當(dāng)一個(gè)store接收到一個(gè)action拷淘,它將把這個(gè)action代理給相關(guān)的reducer。reducer是一個(gè)純函數(shù)指孤,它可以查看之前的狀態(tài)启涯,執(zhí)行一個(gè)action并且返回一個(gè)新的狀態(tài)
-
使用:
下載
cnpm i redux -S
引入
import {createStore} from "redux"
從redux包中引入createStore()方法-
創(chuàng)建一個(gè)純函數(shù)
/**創(chuàng)建了一個(gè)名為reducer的方法, 第一個(gè)參數(shù)state是當(dāng)前保存在store中的數(shù)據(jù)恃轩, 第二個(gè)參數(shù)action是一個(gè)容器结洼,用于: type - 一個(gè)簡單的字符串常量,例如ADD, UPDATE, DELETE等叉跛。 payload - 用于更新狀態(tài)的數(shù)據(jù) **/ function reducer(state,action){ state 之前的狀態(tài) action 發(fā)生改變后的狀態(tài) }
-
創(chuàng)建一個(gè)倉庫
//創(chuàng)建一個(gè)Redux存儲(chǔ)區(qū)松忍,它只能使用reducer作為參數(shù)來構(gòu)造。存儲(chǔ)在Redux存儲(chǔ)區(qū)中的數(shù)據(jù)可以被直接訪問筷厘,但只能通過提供的reducer進(jìn)行更新鸣峭。 const store=createStore(reducer,{ count:10 });
補(bǔ)充知識(shí):
combineReducers
目前我們創(chuàng)建的reducer是通用的宏所,那么我們?nèi)绾问褂枚鄠€(gè)reducer呢?此時(shí)我們可以使用Redux包中提供的combineReducers函數(shù)摊溶。做如下內(nèi)容修改:// src/index.js import { createStore } from "redux"; import { combineReducers } from 'redux'; const productsReducer = function(state=[], action) { return state; } const cartReducer = function(state=[], action) { return state; } const allReducers = { products: productsReducer, shoppingCart: cartReducer } const rootReducer = combineReducers(allReducers); let store = createStore(rootReducer);
獲取數(shù)據(jù)
store是一個(gè)對(duì)象爬骤,但是要獲取這個(gè)對(duì)象中的所有儲(chǔ)存的數(shù)據(jù),需要調(diào)用它的方法:store.getState()
,而state就是store.getState()得到的數(shù)據(jù)莫换。
在組件中使用這個(gè)數(shù)據(jù){store.getState().名}
例:
{store.getState().count}
修改數(shù)據(jù)
//如果是修改數(shù)據(jù)霞玄,需要使用store的dispatch派發(fā)一個(gè)action,action需要兩個(gè)參數(shù)
type:通過type區(qū)分是對(duì)state做什么操作
payload:傳遞的數(shù)據(jù)
store.dispatch({
type:'ADD', //自己定義的一個(gè)標(biāo)識(shí)當(dāng)前操作的串
payload:1 //傳遞的數(shù)據(jù)
})
function reducer(state,action){
if(action.type=="ADD"){
state.count+=action.payload;
}
return state;
}更新頁面
//這個(gè)函數(shù)執(zhí)行完畢后只是store中的數(shù)據(jù)已發(fā)生改變,頁面還沒有發(fā)生變化
//頁面發(fā)生變化
store.subscribe(()=>{
this.setState({})
})
//寫在constructor()里面
官網(wǎng)介紹
import { createStore } from 'redux'
/**
- 這是一個(gè) reducer拉岁,形式為 (state, action) => state 的純函數(shù)坷剧。
- 描述了 action 如何把 state 轉(zhuǎn)變成下一個(gè) state。
- state 的形式取決于你膛薛,可以是基本類型听隐、數(shù)組、對(duì)象哄啄、
- 甚至是 Immutable.js 生成的數(shù)據(jù)結(jié)構(gòu)雅任。惟一的要點(diǎn)是
- 當(dāng) state 變化時(shí)需要返回全新的對(duì)象,而不是修改傳入的參數(shù)咨跌。
- 下面例子使用
switch
語句和字符串來做判斷沪么,但你可以寫幫助類(helper) - 根據(jù)不同的約定(如方法映射)來判斷,只要適用你的項(xiàng)目即可锌半。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
圖片路徑
后來看了看create-react-app的官網(wǎng)禽车,官網(wǎng)明確說出最好將圖片樣式等放在public文件夾中,并且據(jù)我測試刊殉,文件夾名最好是assets
修改ant默認(rèn)樣式
拿到這個(gè)名字殉摔,直接在代碼上進(jìn)行修改。
在我們拿到的這個(gè)名字前面加:global(),把名字寫在括號(hào)里面记焊,直接寫上你想要修改的樣式就可以了逸月。
:global(.has-error .ant-form-explain){
position: absolute;
}
這樣直接修改會(huì)破壞其他的組件的樣式,可以在你想要修改樣式的標(biāo)簽外面定義一個(gè)父級(jí)元素遍膜,在用一個(gè)父級(jí)選擇器就可以了碗硬。·
封裝axios
http.js
import axios from 'axios'
import { message } from 'antd'
/*
函數(shù)返回值是promise對(duì)象
優(yōu)化:
一瓢颅、統(tǒng)一處理請(qǐng)求異常
1.在外層抱一個(gè)自己創(chuàng)建的promise對(duì)象
2.在請(qǐng)求出錯(cuò)時(shí)(catch)恩尾,不reject(error),而是顯示錯(cuò)誤提示
二挽懦、異步得道不是response翰意,而是response.data
在異步請(qǐng)求成功resolve時(shí),resolve(response.data)
*/
export default function http (url, data = {}, type = 'GET') {
return new Promise((resolve, reject) => {
let promise
// 1.執(zhí)行異步ajax請(qǐng)求
if (type === "GET") {
promise = axios.get(url, {
params: data//配置對(duì)象
})
} else {
promise = axios.post(url, data)
}
promise.then(response => {
// 2.如果成功了,調(diào)用resolve(value),傳入response
resolve(response.data)
}).catch(error => {
// 3.如果失敗了猎物,不調(diào)用reject(error),而是提示異常信息
// 如果調(diào)用reject就會(huì)觸發(fā)catch虎囚,但是我們想要統(tǒng)一處理錯(cuò)誤提示
message.error('請(qǐng)求出錯(cuò)了了', error)
})
})
}
login.js
import http from './http.js'
export const login = (data) => http('/login', data, 'POST')
login.jsx
import React, { Component } from 'react'
import { Form, Input, Button, message } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import './login.scss'
import { login } from '../../api/login'
// 高階函數(shù)
// 高階組件
export default class Login extends Component {
onFinish = async (values) => {
console.log('Received values of form: ', values);
// 1----
// login(values).then(res => {
// console.log('ok', res)
// }).catch(err => {
// console.log('no', err)
// })
// 2----
// try {
// const response = await login(values)
// console.log('請(qǐng)求ok',response)
// } catch (err) {
// console.log('請(qǐng)求出錯(cuò)',err)
// }
// 3---
// const response = await login(values)
// console.log('請(qǐng)求ok',response)
// 4---
// const response = await login(values)
// const result =response.data
// if(result.meta.status_code===422){
// message.success('登錄成功')
// // replace不能再回到login,push還可以回到login
// this.props.history.replace('/')
// }else{
// message.error('失敗',result.msg)
// }
// 5---
const result = await login(values)
if(result.meta.status_code===422){
message.success('登錄成功')
// replace不能再回到login蔫磨,push還可以回到login
this.props.history.replace('/')
}else{
message.error('失敗',result.msg)
}
};
render () {
return (
<div className='login'>
<header className='header'>
<img src="assets/logo.png" alt="" />
<h1>電考:后臺(tái)管理系統(tǒng)</h1>
</header>
<section className='content'>
<h2>用戶登錄</h2>
<Form
name="normal_login"
className="login-form"
initialValues={{
remember: true,
}}
onFinish={this.onFinish}
>
<Form.Item
name="username"
rules={[{ required: true, message: '請(qǐng)輸入用戶名!', },]}>
<Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="用戶名" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: '請(qǐng)輸入密碼!', },]}>
<Input prefix={<LockOutlined className="site-form-item-icon" />} type="password" placeholder="密碼" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button">登錄</Button>
</Form.Item>
</Form>
</section>
</div>
)
}
}
/* async和await
簡化promise對(duì)象的使用:
1.不用再使用.then()來指定成功/失敗的回調(diào)函數(shù)
2.以同步編碼(沒有回調(diào)函數(shù))方式實(shí)現(xiàn)異步流程
await:在返回promise的表達(dá)式左側(cè)await,不想要promise圃伶,想要promise異步執(zhí)行的成功的value數(shù)據(jù)
async:await所在函數(shù)(最近的)定義的左側(cè)寫async
onFinish = async (values) => {
try {
const response = await login(values)
console.log('請(qǐng)求ok',response)
} catch (err) {
console.log('請(qǐng)求出錯(cuò)',err)
}
};
onFinish = (values) => {
console.log('Received values of form: ', values);
login(values).then(res => {
console.log('ok', res)
}).catch(err => {
console.log('no', err)
})
};
*/