React-前端技術的旗幟

React兩大核心:

(1)虛擬Dom:用js對象來模擬頁面中Dom元素及嵌套關係

(2)Diff算法:tree diff、component diff、element diff

webpack初始化項目:

創建文件夾
在文件夾中 npm init -y
          根目錄新建文件夾 src (源代碼目錄)
          根目錄新建文件夾 dist (產品目錄)
          在src中新建index.html  main.js
安裝webpack  npm i webpack -D
            npm i webpack-cli -D
           根目錄創建配置文件 webpack.config.js

webpack.config.js

module.exports={
  mode:'development', //必選項 development  production 區別:是否壓縮代碼
  //在webpack 4.x中,有一個很大的特性,就是約定大於配置,約定默認的打包入口路徑是:src->index.js
  //所以將main.js更改爲index.js
  //默認打包的輸出文件路徑是dist->main.js
}

解決更改實時更新打包編譯

1、npm i webpack-dev-server -D
2、在package.json->scripts中加上"dev":"webpack-dev-server --open --port 3000 --hot --host 127.0.0.1"

將首頁放到內存中

1、npm i html-webpack-plugin -D
2、在webpack.config.js中導入插件:
           const path = require('path')
           //導入在內存中自動生成index頁面的插件
           const HtmlWebPackPlugin = require('html-webpack-plugin')
3、創建一個插件的實例對象: //可以將打包的js文件追加到內存的html文件中,不用手動添加script標籤
           const htmlPlugin = new HtmlWebPackPlugin({
           template:path.join(_dirname,'./src/index.html'),  //源文件
           filename:'index.html'
})
4、將插件放置exports中

module.exports={
  mode:'development', //必選項 development  production 區別:是否壓縮代碼
  //在webpack 4.x中,有一個很大的特性,就是約定大於配置,約定默認的打包入口路徑是:src->index.js
  //所以將main.js更改爲index.js
  //默認打包的輸出文件路徑是dist->main.js
  plugins:[
    htmlPlugin
 ],
  module:{  //所有的第三方模塊的配置規則
     rules:[
       {test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
    ]
  }
}

項目中使用React

//1、npm i react react-dom -S
//react:專門用於創建組件,同時組件的生命週期都在這個包裏
//react-dom:專門進行DOM操作,最主要的應用場景就是,ReactDOM.render()
//2、在index.html頁面中,創建容器
<div id="app"></div>
//3、在index.js中導入包:
import React from 'react'
import ReactDOM from 'react-dom'
//4、創建虛擬DOM元素
//參數1:創建的元素的類型,字符串,表示元素的名稱
//參數2:一個對象或者null,表示這個DOM元素的屬性
//參數3:子節點(包括其他虛擬DOM獲取文本子節點)
//參數n:其他子節點
//<h1 id="myH1" title="this is a h1">這是一個H1</h1>
const myh1 = React.createElement('h1',{id:'myH1',title:'this is a h1'},'這是一個H1')
//5、使用ReactDOM吧虛擬DOM渲染到頁面上
//參數1:要渲染的那個虛擬DOM元素
//參數2:指定頁面上一個容器(一個DOM元素)
ReactDOM.render(myh1,document.getElemntById('app'))

//採用上面的渲染方式太麻煩,而html是最優秀的標記語言
//在js文件中默認不能寫類似於HTML的標記,否則打包失敗
//可以用babel來轉換js中的標籤
//這種在js中混合寫入類似於HTML的語法,叫做jsx語法
const myDiv= <div id="myDiv" title="aaa"><div>

安裝babel插件 

// 安裝babel插件
npm i babel-core babel-loader babel-plugin-transform-runtime -D
npm i babel-preset-env babel-preset-stage-0 -D
// 安裝能夠識別轉換jsx語法的包babel-preset-react-D
npm i babel-preset-react -D
//在webpack.config.js配置文件中增加module
// 添加配置文件.babelrc
{
   "presets":["env","stage-0","react"],
   "plugins":["transform-runtime"]
}
//添加配置項
module.exports={
  mode:'development', //必選項 development  production 區別:是否壓縮代碼
  //在webpack 4.x中,有一個很大的特性,就是約定大於配置,約定默認的打包入口路徑是:src->index.js
  //所以將main.js更改爲index.js
  //默認打包的輸出文件路徑是dist->main.js
  plugins:[
    htmlPlugin
 ],
  module:{  //所有的第三方模塊的配置規則
     rules:[
       {test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
    ]
  },
  resolve:{
   extensions:['.js', '.jsx', '.json'], //表示這幾個文件的後綴名可以省略不寫
   alias:{
       '@':path.join(__dirname, './src') //這樣,@就表示項目根目錄中src這層路徑
    }
  }
}

 

jsx語法

let a = 10
//使用{}佔位符
ReactDOM.render(<div>{a}</div>, document.getElementById('app'))

創建組件,組件的名稱首字母必須大寫

//第一種創建組件的方式
//使用構造函數來創建組件,如果要接收外界傳遞的數據,
//需要在構造函數的參數列表中使用props來接收,必須向外return一個合法的JSX創建的虛擬DOM

function Hello(){
   //在組件中,必須返回一個合法的JSX虛擬DOM元素
   return ...
}
//直接把組件名稱,以標籤形式,放到頁面上
<Hello></Hello>

//爲組件傳遞數據
<Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello>
//使用展開運算符
<Hello {...dog}></Hello>
const dog = {
 name:'大黃',
 age:'3',
 gender:'雄'
}
//使用props形參,在構造函數接受外界傳過來的屬性值
function Hello(props){
   //props.name='zs' 會報錯:不論是Vue還是React,組件中的props永遠都是隻讀的,不能被重新賦值
   //return null
   return <div>這是Hello組件--{props.name}--{props.age}--{props.gender}</div>
   
}

//第二種創建組件的方式,使用class關鍵字來創建組件
//通過new出來的實例訪問到的屬性,叫實例屬性
//通過構造函數直接訪問到的屬性,叫靜態屬性
//在class{}中,只能寫構造器、靜態方法、靜態屬性和實例方法
class Animal{
  //constructor(){}  每個類中都有一個默認的無參構造器
    constructor(name,age){
      this.name=name //實例屬性
      this.age=age //實例屬性
    }
    static info='aaa' //靜態屬性
    say(){}       //Animal的實例方法,掛載到原型對象上prototype
    static show(){}  //Animal的靜態方法
}

const a1=new Animal('大黃',3)
a1.name  //實例屬性
Animal.info  //靜態屬性


//class繼承,使用extends實現子類繼承父類,擁有父類的構造函數
//子類構造函數中需要調用super()
//子類獨有的,可以在自己的構造器中體現
class Dog extends Animal{
  constructor(name,age,id){
    super()
    this.id=id //在子類中,this只能放到super之後使用
  }
}
//基於class創建組件的方式
class 組件名稱 extends React.Component{
  constructor(){
     super()
     this.state={
       msg:'我是私有數據'
     }  //等價於Vue中的data(){return {}}
  }
  //組件內部必須要有render函數,用於渲染當前組件所對應的虛擬DOM元素
  render(){ 
     //必須返回合法的DOM元素
     //在class關鍵字創建的組件中,如果想使用外界傳遞過來的props參數
     //不需要接受,直接通過this.props.***訪問
     return <div>這是class創建的組件--{this.props.name}--{this.props.age}</div>
  }
}

//構造函數和class關鍵字創建的組件的區別
//用構造函數創建的組件:叫做無狀態組件,無自己的私有數據,只有props,無生命週期函數
//用class創建的組件:叫做有狀態組件,有自己的私有數據(this.state)和生命週期函數
//有狀態組件和無狀態組件的本質區別:有無state屬性
//this.state中的數據時可讀可寫的

將組件抽離:創建.jsx文件,將創建組件的構造函數放到jsx文件中

Hello.jsx

//使用props形參,在構造函數接受外界傳過來的屬性值
export default function Hello(props){
   //props.name='zs' 會報錯:不論是Vue還是React,組件中的props永遠都是隻讀的,不能被重新賦值
   //return null
   return <div>這是Hello組件--{props.name}--{props.age}--{props.gender}</div>
   
}

//export default Hello 將組件暴露出去

//使用組件的時候,直接導入
import Hello from './../Hello.jsx'

解決導入組件時,統一.jsx後綴

//在webpack.config.js配置文件的導出對象中增加resolve
resolve:{

   extensions:['.js', '.jsx', '.json'] //表示這幾個文件的後綴名可以省略不寫
}

解決文件路徑問題

import Hello form './../Hello'

//在配置文件的導出對象中,extension的同級配置alias
alias:{
       '@':path.join(__dirname, './src') //這樣,@就表示項目根目錄中src這層路徑
}

JSX中CSS等樣式的寫法

//以樣式對象的形式
//在樣式中,數值類型不需單引號包裹,字符串須單引號包裹
//如果關鍵字有‘-’,則也須要單引號包裹
<h1 style={{color:'red',fontSize:'35px'}}>這是評論列表組件</h1>

//樣式表的形式,className=''
//1、安裝加載器
npm i style-loader css-loader -D
//2、在webpack.config.js配置文件中配置加載器,打包處理css樣式表的第三方loader
{test:/\.css$/, use:['style-loader','css-loader?modules']}
//3、導入樣式表
import cssObj from '@/../css/xxx.css'

//直接導入的樣式表默認在全局,沒有作用域,整個項目上都生效
//解決css樣式表全局有效,導致樣式衝突的問題
//css-loader啓用模塊化,在配置文件的css-loader加載器中追加參數
{test:/\.css$/, use:['style-loader','css-loader']}
//開啓之後,CSS樣式表導入之後就是對象了,樣式需要通過樣式對象去訪問
//只對類選擇器和Id選擇器生效
import cssObj from '@/../css/xxx.css'

<div className={cssObj.xx}></div>

//取消模塊化,使用全局樣式,全局生效,模塊化:local()(默認)
//在樣式表中使用:global(.title){}
:global(.title){
   fontSize:'25px'
}
//使用複合樣式
<div className={cssObj.xx + ' 樣式2'}></div>
<div className={[cssObj.xx,'樣式2'].join(' ')}></div>

//安裝字體loader
npm i url-loader -D
npm i file-loader -D
{test:/\.ttf|woff|woff2|eot|svg$/, use:'url-loader'}

//安裝.scss .less的loader
npm i sass-loader node-sass -D
{test:/\.scss$/, use:['style-loader','css-loader?modules','sass-loader']}

解決第三方樣式表的模塊化問題

//導入第三方樣式表
//如果在引用某個包的時候,這個包被安裝到了node_modules目錄中,則可以省略node_modules這一層目錄
//直接以包名開始引入自己的模塊或者樣式表
import 'bootstrap/dist/css/bootstrap.css'
//取消了第三方樣式表的模塊化,就不用按照 import xx from 'path'的形式導入
//導入方式對比自己的樣式表
import cssObj from '@/../css/xxx.scss'


//一般第三方的樣式表都是以.css文件結尾,所以可以將自己的樣式文件定義爲.scss或者.less文件
//只對.scss .less文件啓用模塊化
{test:/\.scss$/, use:['style-loader','css-loader?modules','sass-loader']}
{test:/\.css$/, use:['style-loader','css-loader']}

React中綁定事件

//爲事件提供的處理函數,注意:函數後不帶'()',以下均爲class內部
onClick={function}
<button onClick={this.show}>按鈕</button>
show(){
   console.log('show方法')
}

//用的最多的事件綁定形式
//匿名函數this指向外層作用域的調用者
<button onClick={()=>this.show('傳參')}>按鈕</button>
//事件的處理函數,把匿名函數的引用賦給show
show = (arg1)=>{
   console.log('show方法'+arg1)
}

//React中,如果想爲state中的數據重新賦值,不要使用this.state.msg='123'
//應該使用this.setState({msg:'123'})
//推薦使用this.setState({}),只會把對應的state狀態更新,而不會覆蓋其他的state狀態
//注意:this.setState()方法是異步的
//如果想在更新完state狀態的時候拿到最新的值,可以使用this.setState({},callback)
this.setState({},function(){ //回調函數
  console.log()
})

//綁定文本框和state中的值
//改變的state狀態值能自動同步到頁面上-> 單向數據流
//頁面的值同步到state中 -> react不提供,所以需要程序員手動監聽文本框的onChange事件,
//調用this.setState({})手動同步
//當爲文本框綁定value值以後,要麼同時提供一個readonly,要麼提供一個onChange()處理函數
<input type="text" value={this.state.msg} readonly/>
<input type="text" value={this.state.msg} onChange={()=>this.txtChanged()}/>
txtChange = ()=>{
  console.log()
}
//onChange事件中,獲取文本框的值,有兩種方案
//1.通過事件參數e來獲取
e.target.value
//2.this.refs
<input type="text" value={this.state.msg} onChange={()=>this.txtChanged()} ref="txt"/>
this.refs.txt.value

React組件生命週期

React路由:react-router

npm install react-router-dom

//導入路由模塊
//HashRouter表示一個路由的根容器,將來所有的路由相關的東西,都要包裹在HashRouter中,
//且一個網站中只需要使用一次HashRouter
//Route表示一個路由規則,在Route上,有兩個比較重要的屬性,path component
//Link表示路由的鏈接,類似於Vue中的<router-link>
import {HashRouter,Route,Link} from 'react-router-dom'

//當使用HashRouter把App根組件的元素包裹起來之後,網站就已經啓用路由了,訪問地址後會加上'#'
//在一個HashRouter中只能有一個唯一的根元素
import Home from '../Home.jsx'
import Moviefrom '../Movie.jsx'
import Aboutfrom '../About.jsx'

<link to='/home'>首頁</link>
<link to='/movie'>電影</link>
<link to='/about'>關於</link>

//路由規則 path表示要匹配的路由,component表示要展示的組件
//route除了是路由規則,還是一個佔位符
//默認是模糊匹配,如果需要精確匹配,加上exact屬性
//如果需要加參數,可以在匹配規則中使用':+參數',表示i這個位置匹配到是的參數
//如果想要獲取參數,可使用this.props.mathch.params.xx
//<Route path='/movie/:type/:id' component={Movie} exact>
<Route path='/home' component={Home}>
<Route path='/movie' component={Movie} exact>
<Route path='/about' component={About}>

//使用路由中的switch包裹,能夠指定,如果前面的路由優先匹配到,則放棄匹配後續路由
<Switch></Switch>

react UI框架:antd

//使用fetch API獲取數據
//第一個.then中獲取不到數據,拿到的是一個response對象
//通過response.json()獲取數據
fetch('url')
.then(response=>{
  return response.json()
})
.then(data=>{
  console.log(data)
})

//使用第三方工具解決fetch無法跨域請求問題
npm i fetch-jsonp
import fetchJSONP from'fetch-jsonp'

fetchJSONP('url')
.then(response=>{
  return response.json()
})
.then(data=>{
  console.log(data)
})

//url
const url='../${}'

鉤子函數

//在組件render之前立即調用
componentWillMount()

//所有的組件(包括子組件)在render執行完之後立即調用,並且只會被調用一次。
componentDidMount()

//在props被改變時被觸發,初始化render時不調用。
componentWillReceiveProps(nextProps)

//發生重渲染時,在render()函數調用前被調用的函數,當函數返回false時候,
//阻止接下來的render()函數的調用,阻止組件重渲染,而返回true時,組件照常重渲染。
shouldComponentUpdate(nextProps, nextState)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章