react 0基礎(chǔ)學(xué)習(xí)

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)目

  1. 運(yùn)行npm init -y 快速初始化項(xiàng)目
  2. 在項(xiàng)目根目錄創(chuàng)建src源代碼目錄和dist產(chǎn)品目錄
  3. 在 src 目錄下創(chuàng)建 index.html
  4. 使用 cnpm 安裝 webpack 虹钮,運(yùn)行cnpm i webpack webpack-cli -D(如何安裝 cnpm: 全局運(yùn)行 npm i cnpm -g
  5. 注意:webpack 4.x 提供了 約定大于配置的概念聋庵;目的是為了盡量減少 配置文件的體積荐操;
    • 默認(rèn)約定了:
    • 打包的入口是src -> index.js
    • 打包的輸出文件是dist -> main.js
    • 4.x 中 新增了 mode 選項(xiàng)(為必選項(xiàng)),可選的值為:developmentproduction;

使用 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

  1. 運(yùn)行 cnpm i react react-dom -S 安裝包
    react: 專門用于創(chuàng)建組件和虛擬DOM的珍策,同時(shí)組件的生命周期都在這個(gè)包中
    react-dom: 專門進(jìn)行DOM操作的托启,最主要的應(yīng)用場景,就是ReactDOM.render()

  2. index.html頁面中攘宙,創(chuàng)建容器:

 <!--html-- 容器屯耸,將來,使用 React 創(chuàng)建的虛擬DOM元素蹭劈,都會(huì)被渲染到這個(gè)指定的容器中 -->
   <div id="app"></div>
  1. 導(dǎo)入包:
 //js
   import React from 'react'
   import ReactDOM from 'react-dom'
  1. 創(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)')
  1. 渲染:
  //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()

  1. 如何啟用 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文件中):
    module: { //要打包的第三方模塊
         rules: [
           { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }
         ]
     }
    
    https://www.cnblogs.com/amcy/p/10273929.html
  2. 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>
    }
    
  • 抽離組件

    1. 在src目錄中新建components目錄來存儲(chǔ)組件
    2. 在components目錄中新建.jsx文件
    3. 在文件中導(dǎo)入Reacct(import React from "react")宰僧,因?yàn)樵诮M件中使用了jsx的{}
    4. .jsx文件中定義組件,并拋出
      export default function Person(props){
             return <h1>{props.name}</h1>;
      }
      
    5. 在父組件中js中引入組件
      import Person from "@/components/person"
      
  • 在導(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>
    
  • 注意:

    1. 父組件向子組件傳遞數(shù)據(jù)
      給子組件名稱綁定自定義屬性雄嚣,在子組件中用props來接收
    2. 使用{...obj}屬性擴(kuò)散傳遞數(shù)據(jù)
      <Hello {...obj}></Hello>
      
    3. 將組件封裝到單獨(dú)的文件中
    4. 組件的名稱首字母必須是大寫

第2種 - 創(chuàng)建組件的方式

使用 class 關(guān)鍵字來創(chuàng)建組件
ES6 中 class 關(guān)鍵字晒屎,是實(shí)現(xiàn)面向?qū)ο缶幊痰男滦问剑?/p>

  • 了解ES6中 class 關(guān)鍵字的使用
    1. class 中 constructor 的基本使用
    2. 實(shí)例屬性和實(shí)例方法
    3. 靜態(tài)屬性和靜態(tài)方法
    4. 使用 extends 關(guān)鍵字實(shí)現(xiàn)繼承
  • 基于class關(guān)鍵字創(chuàng)建組件
    1. 最基本的組件結(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中組件傳值

  • 父傳子

    1. 在父組件中給子組件綁定自定義屬性 屬性={數(shù)據(jù)}
    2. 在子組件中用this.props.屬性,接收數(shù)據(jù)
  • 子傳父

    1. 在父組件中定義方法(在父組件中設(shè)置事件觸發(fā)的函數(shù))
    2. 在父組件中給子組件綁定自定義事件谜叹,接收父組件的方法
    3. 在子組件的某一個(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>
        }
    }
    
  • 外部樣式

    1. 在react中可以給樣式設(shè)置模塊化
    2. 在webpack.config.js中給css-loader這個(gè)loader設(shè)置modules參數(shù){test:/\.css$/,use:['style-loader','css-loader?modules']}
    3. 需要注意的是:如果加上這個(gè)參數(shù)夺谁,在普通的css中會(huì)將類選擇器厚者、id 選擇器躁劣,轉(zhuǎn)換成對(duì)象的形式 用的時(shí)候直接在引入的對(duì)象上.類名(對(duì)象.類名)
    4. 這樣給樣式設(shè)置了作用域,可以保證不同的組件中可以避免類名的沖突。但是库菲,標(biāo)簽選擇器是不會(huì)被編譯的
    5. 我們自己認(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元素
    }
    
  • 修改組件的值
    1. 若要修改組件自己私有的數(shù)據(jù)烫止,即this.state里的數(shù)據(jù)不可以直接修改,需要通過一個(gè)異步的方法this.setState({屬性:新修改后的值})修改
      this.setState({
          name:e.target.value
      })  
      
    2. this.setstate()方法 注意:
      只是修改某一個(gè)或者某幾個(gè)要更新的數(shù)據(jù) 而不會(huì)覆蓋
      此方法是一個(gè)異步管理狀態(tài)的函數(shù)

react實(shí)現(xiàn)的雙向數(shù)據(jù)綁定

  • 步驟
    1. 給表單元素添加事件 onChange={(e)=>{this.方法名(e)}}
    2. 在組件中定義方法
      方法名(e){
          // e.target 是當(dāng)前原生的dom元素
          //修改name屬性的值
          this.setState({
              name:e.target.value
          }) 
      }
      
    3. 給表單元素設(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)用

    image.png

路由

  • 參考網(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è)屬性

    1. location.href 獲取當(dāng)前的路徑
    2. locathon.hash 獲取當(dāng)前的hash值
    3. 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/afe46a62a7ba

    exact
    exact默認(rèn)為false蝉揍,如果為true時(shí),需要和路由相同時(shí)才能匹配匙隔,但是如果有斜杠也是可以匹配上的疑苫。
    如果在父路由中加了exact,是不能匹配子路由的,建議在子路由中加exact
    strict
    <Route strict path="/one" component={About} />
    strict默認(rèn)為false纷责,如果為true時(shí)捍掺,路由后面有斜杠而url中沒有斜杠,是不匹配的

    案例:


    image.png

    總結(jié):

    如果沒有子路由的情況再膳,建議大家配都加一個(gè)exact挺勿;如果有子路由,建議在子路由中加exact喂柒,父路由不加不瓶;
    而strict是針對(duì)是否有斜杠的,一般可以忽略不配置灾杰。

  • 定義方式
    <Route path='自定義' compontent/>要被包裹在HashRouter中

  • 案例
    需求:當(dāng)訪問 / 顯示出home組件
    步驟:

    1. 引入包
      import  {HashRouter as Router,Route} from 'react-router-dom'
      
    2. 做了容器組件 App 在render中 {this.props.children}
    3. 做的home組件
    4. 配置的規(guī)則蚊丐,這個(gè)規(guī)則屬于一個(gè)入口的規(guī)則 ,如果在子組件中需要路由就去子組件中配置即可
      <Router>
          <App>
              <Route path='/' component={Home} />
          </App>
      </Router>
      

    需求: 在home組件中艳吠,有兩個(gè)標(biāo)題:用戶列表麦备、商品列表,點(diǎn)擊顯示不同頁面
    步驟:

    1. 在home組件中設(shè)置 <NavLink><NavLink> 做導(dǎo)航鏈接
    2. 在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

    1. 路由表中
      <Route path=' /sort/:id '   component={Sort}></Route>
      
    2. Link處
      // HTML方式
      <Link to={ ' /sort/ ' + ' 2 ' }  activeClassName='active'>XXXX</Link>
       //JS方式
       this.props.history.push(  '/sort/'+'2'  )
      
    3. sort頁面
      通過:this.props.match.params.id,就可以接受到傳遞過來的參數(shù)(id)
  • 方式二:通過query
    前提:必須由其他頁面跳過來霎终,參數(shù)才會(huì)被傳遞過來
    注:不需要配置路由表融痛。路由表中的內(nèi)容照常:
    <Route path='/sort' component={Sort}></Route>

    1. Link處
      //HTML方式
      <Link to={{ path : ' /sort ' , query : { name : 'sunny' }}}>
      //JS方式
      this.props.history.push({ path : '/sort' ,query : { name: ' sunny'} })
      
    2. sort頁面
      this.props.location.query.name
      
  • 方式三:通過state
    同query差不多,只是屬性不一樣神僵,而且state傳的參數(shù)是加密的,query傳的參數(shù)是公開的覆劈,在地址欄

    1. Link 處
      //HTML方式:
      <Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}> 
      //JS方式:
      this.props.history.push({ pathname:'/sort',state:{name : 'sunny' } })
      
    2. sort頁面
      this.props.location.state.name
      

本地存儲(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)

  • 使用
    1. 下載cnpm i redux -S

    2. 引入import {createStore} from "redux"從redux包中引入createStore()方法

    3. 創(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)
      }
      
    4. 創(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);
      
    5. 獲取數(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}

    6. 修改數(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;
      }

    7. 更新頁面
      //這個(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


WechatIMG69.png

WechatIMG71.png

修改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)
     })

    };
*/

431605993228_.pic.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子膛锭,更是在濱河造成了極大的恐慌腋粥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥猩,死亡現(xiàn)場離奇詭異榔至,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)欺劳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門唧取,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人划提,你說我怎么就攤上這事枫弟。” “怎么了鹏往?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵淡诗,是天一觀的道長。 經(jīng)常有香客問我伊履,道長韩容,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任唐瀑,我火速辦了婚禮群凶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘介褥。我一直安慰自己座掘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布柔滔。 她就那樣靜靜地躺著溢陪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睛廊。 梳的紋絲不亂的頭發(fā)上形真,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼咆霜。 笑死邓馒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛾坯。 我是一名探鬼主播光酣,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼脉课!你這毒婦竟也來了救军?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤倘零,失蹤者是張志新(化名)和其女友劉穎唱遭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呈驶,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拷泽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袖瞻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片司致。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖虏辫,靈堂內(nèi)的尸體忽然破棺而出蚌吸,到底是詐尸還是另有隱情,我是刑警寧澤砌庄,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布羹唠,位于F島的核電站,受9級(jí)特大地震影響娄昆,放射性物質(zhì)發(fā)生泄漏佩微。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一萌焰、第九天 我趴在偏房一處隱蔽的房頂上張望哺眯。 院中可真熱鬧,春花似錦扒俯、人聲如沸奶卓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夺姑。三九已至,卻和暖如春掌猛,著一層夾襖步出監(jiān)牢的瞬間盏浙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留废膘,地道東北人竹海。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像丐黄,于是被迫代替她去往敵國和親斋配。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 包含 react基礎(chǔ) react傳值 react路由 和redux管理 和react-redux reactDom...
    梔璃鳶年_49a3閱讀 1,102評(píng)論 0 1
  • 40孵稽、React 什么是React许起?React 是一個(gè)用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,005評(píng)論 0 1
  • HTML模版 之后出現(xiàn)的React代碼嵌套入模版中。 1. Hello world 這段代碼將一個(gè)一級(jí)標(biāo)題插入到指...
    ryanho84閱讀 6,221評(píng)論 0 9
  • 3. JSX JSX是對(duì)JavaScript語言的一個(gè)擴(kuò)展語法菩鲜, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,806評(píng)論 0 24
  • React簡介 (1)簡介 React 起源于 Facebook 的內(nèi)部項(xiàng)目惦积,因?yàn)樵摴緦?duì)市場上所有 JavaSc...
    魚魚吃貓貓閱讀 1,610評(píng)論 1 6