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)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值