一、几个概念
库和框架
- 库(library):小而巧,可以很方便的从一个库切换到另一个库,但是代码几乎不会改变。
- 框架(framework):大而全,框架提供了一整套完整的解决方案,在项目中间想要切换框架是困难的
模块化和组件化
- 模块化:是从代码的角度进行分析,把可复用的代码抽离为单个模块,便于项目的维护和开发
- 组件化:从UI界面的角度进行分析,把可复用的UI元素,抽离为单独的组件
二、React的基础概念
1、虚拟DOM
- DOM的本质:浏览器中的概念,用JS对象来表示页面上的元素,并提供了操作相应DOM对象的API
- 虚拟DOM:是框架的概念,是程序员用JS对象来模拟页面上的DOM和DOM嵌套
- 虚拟DOM的目的:为了实现页面中DOM元素的高效更新。
2、Diff 算法
- tree diff: 新旧两棵DOM树,逐层对比的过程。当整个DOM逐层对比完毕,则所需要被按需更新的元素,必然能够找到
- component diff :在进行tree diff的时候,每一层中,组件级别的对比。
- 对比前后,组件类型相同,则认为此组件暂时不需要被更新
- 对比前后,组件类型不同,则需要移除旧的组件,创建新的组件,并追加到页面上。
- element diff:在进行组件对比的时候,如果两组件类型相同,则需要进行元素级别的对比。
三、使用webpack4.x搭建项目
- npm init -y 初始化
- 创建src源代码目录和dist目录
- 安装:npm i webpack -D npm i webpack-cli -D
- 在webpack.config.js中配置mode
module.exports={ mode:‘development’,//development 开发环境, //在webpack 4.x中有一个很大的特性 约定大于配置 }
- 约定大于配置,打包入口路径:在src下的index.js,出口文件:dist下的main.js
- 配置实时编译 npm i webpack-dev-server -D后在package.json的scripts下
"dev":"webpack-dev-server"
--->npm run dev--->引入的js文件在根目录 - 配置html-webpack-plugin
四、使用React渲染最基本的虚拟DOM到页面上
1、下载、引入
- 下载 npm i react react-dom
- 在index.js中引入:
import React from ‘react’ import ReactDom from 'react-dom'
2、创建虚拟的dom元素
-
const myh1 = React.createElement(‘h1’,null,‘这是一个h1’)
- 参数1:创建的元素的类型,字符串,表示元素的名称
- 参数2:一个对象或者null,表示当前dom元素的属性
- 参数3:子节点(包括 其他 虚拟DOM 或者文本的子节点)
- 参数n:其他子节点
3、使用ReactDom把虚拟DOM渲染到页面上
-
ReactDom.render(myh1,document.getElementById("app"))
- 参数1:要渲染的虚拟DOM元素
- 参数2:指定页面上的一个容器
4、例子
import React from 'react'
import ReactDom from 'react-dom'
var myDiv = React.createElement('h1',null,'这是react');
ReactDom.render(myDiv,document.getElementById('box'))
五、JSX介绍和使用
- 在JS中默认不能写入html标记,否则会打包失败,可以使用babel来转换这些js标签,在js中混入类似于html的语法叫做JSX,符合xml规范
- JSX语法的本质:在运行的时候被转换成React.createElement形式来执行
1、启用JSX
- 安装babel插件
- npm i babel-core babel-loader babel-plugin-transform-runtime -D
- npm i babel-preset-env babel-preset-stage-0 -D
- 安装能够识别转换JSX语法的包
- npm i babel-preset-react -D
- 在webpack.config.js中添加babel-loader
module://所有第三方 模块的配置规则 { rules:[//第三方匹配规则 { test:/\.js|jsx$/,use:'babel-loader' , exclude:/mode_modules/} ] }
- 添加.babelrc配置文件
{ "presets" : ["env","stage-0","react"], "plugins" : ["transform-runtime"] }
2、在JSX中书写JS代码注意点
- 变量使用{a}插入
- 标签中的属性值:title={}
- 在JSX中,写注释{//}(需要换行)、{/* 这是注释 */},
- 为JSX中得元素添加class类名需要使用className来替代class,htmlFor替代for
- 在JSX语法中,标签必须成对出现,单标签则必须自闭和。
- 在JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹
- 在JSX中不能为style设置字符串的值,应该写style = {{color:‘red’}},行内样式,如果是字符串类型就需要引号包裹。
let message = '这是js中的参数'
let nameStr = ['张三','李四','王五','赵六']
let nameArr = []
nameStr.forEach((item)=>{
let nameItem = {item }
nameArr.push(nameItem)
})
{
//什么时候使用{}:当在JSX控制的区域内,写JS表达式就需要
}
ReactDom.render(
{ message }
{nameArr}
{nameStr.map( item => {item}
) }//方法二
,document.getElementById('app'))
六、组件
1、使用构造函数来创建组件:
-
创建组件
// 组件名称的首字母需要大写 function Hello (props) { //在构造函数中接收外界传入的参数,传入的prop是只读的 console.log( props )//{ name : '张三', age : 14} //如果return null表示组件是空的什么都不渲染 //组件必须ruturn,必须返回一个合法的 JSX 虚拟DOM元素 return
这是Hello组件}//还可以使用解构赋值来传递对象 var dog={ name:‘旺财’, age:12 } -
分离组件
//文件名:Hello.jsx import React from 'react' export default function Hello(props){ return
{props.name}} //在index.js中导入使用,默认不做单独配置的话,不能省略.jsx后缀 import Hello from '路径/Hello.jsx'- 使用 Person.defaultProps = { sex:'男' } 设置传递参数的默认值
- 使用 Person.propTypes = { name:PropTypes.string.isRequired }设置属性的类型和必要性
- 配置,省略后缀名,在webpack.config.js中添加
resolve:{ extension:['.js' , '.jsx' , '.jsx' ],//表示这几个文件名后缀可以省略 //配置webpack设置项目根目录 alias:{//表示别名 '@':path.join(__dirname,'./src')//这样@就表示项目根目录中src这一层路径 } }
2、基于关键字class创建组件
- 静态属性和实例属性
- 静态属性用static修饰,用类名访问
- 静态方法和实例方法
- 在class{}中只能写构造器、静态方法、静态属性、实例方法
- class关键词内部,还是用原来的配方实现,所以class称为语法糖
- 继承时,子类constructor(){需要super() }
class Movie extends React.Component{//必须继承Component render(){//必须有render函数 return
我是一个组件//必须返回合法的 JSX虚拟DOM结构 } } ReactDom.render( - 使用this.props.参数名获取参数
4、两种创建组件方式的区别
- 使用class关键字创建的组件,有自己的私有数据和生命周期数;用function创建的组件,只有props。
- 构造函数创建出来的组件叫做“无状态组件”,用class创建的组件“有状态组件”
- 两种方式之间的区别是:有无state属性和有无生命周期
5、组件中props
和state/data
之间的区别
- props中的数据都是外界传递过来的;
- state/data中的数据,都是组件私有的(通过Ajax获取回来的数据,一般都是私有数据)
- props中的数据是只读的,不能重新赋值,state/data中数据可读可写
6、在组件内使用内联样式style
- 在JSX中如果想写行内样式,不能为style设置字符串的值,而是应该写成style={ { color:‘red’ } }
- 在行内样式中,如果是数值类型的样式则不用引号包裹,如果是字符串类型的样式值,必须用引号包裹。
- 可以封装成一个样式对象通过import 引入
- 引入css,需要配置。直接导入css样式表,默认是在全局上整个项目都生效。
7、为css启用modules
- 在webpack.config.js中配置css时
-
rules:[ { test: /\.css$/, use:['style-loader','css-loader?modules']} ], //modules为普通的css启用模块化
- 启用模块化后,不会在全局生效
- css模块化,只针对 类选择器 和id选择器生效,不会将标签选择器模块化
- 使用localIdentName自定义生成类名格式,可选参数有:
- [path] 表示样式表 相对于项目根目录 所在的路径
- [name] 表示样式表 文件名称
- [local] 表示样式表 类名定义名称
- [hash:length] 表示32位的hash值
- 例子:
//在webpack.config.js中 rules:[ { test: /\.css$/, use:['style-loader','css-loader?modules&localIdentName=[path][name]'] } ] // 在cmtlist.jsx中 import cmtStyle from ‘@/css/cmtlist.style’
标题
- 被:local()包裹起来的类名,会被模块化,默认所有的类名和id都被模块化。
- :global()包裹起来的类名,不会被模块化,而是全局生效
七、在项目中启用模块化并同时使用bootstrap
- 打包处理 字体文件的loader:
{test:/\.ttf|woff|woff2|eot|svg$/,use:'url-loader'}
- 如果在引用某个包时,这个包被安装到了node_modules目录中,则可以省略node_modules这一层目录,直街以包名开始引入自己的 模块或样式表
- 自己规定:
- 把自己的样式表,定义为.scss文件或 .less文件。
- 第三方的 样式表 还是以.css结尾
- 我们只需要为自己的.scss文件或 .less文件,启用模块化
- 安装能够解析scss文件的loader: 运行
npm i sass-loader node-sass -D
//css文件无需模块化 { test: /\.css$/, use:[ 'style-loader','css-loader','sass-loader']}, //scss启用模块化 { test: /\.scss$/, use:[ 'style-loader','css-loader?modules','sass-loader']}
八、React中绑定事件
onClick = { function }
-
在方法中修改state中的值,使用this.setState({msg:})
- setState的注意点:
- setState只会把对应的state状态更新,而不会覆盖其他的state状态
- setState方法是异步的,调用完需要马上用到新值需要使用 this.setState({},callback)
- setState的注意点:
注释://#region 开始注释 //#endregion
-
获取文本框的值
- e.target.value
- this.refs.txt.value
class BtnEvent extends React.Component{ constructor(){ super() this.state = { msg:'这是测试事件的组件' } } render(){ return
{this.state.msg}
{/* 为文本框绑定value值以后,要么同时提供一个readOnly,要么提供一个onChange处理函数**/} this.changeInput(e)} ref='txt'/>
九、组件的生命周期
- 生命周期的概念:每个组件的实例从创建、运行到销毁,在这过程中,会促发一些事件,这些事件就叫做组件的生命周期函数
- 组件的三个生命周期状态:
- Mount:插入真实的DOM
- Update:被重新渲染
- Unmount:被移出真实的DOM
- 组件的创建阶段:只执行一次
- componentWillMount():将要插入回调
- render():用域插入虚拟DOM回调
- componentDidMount():已经插入回调
- 组件的运行阶段、更新
- componentWillReceiveProps():
- shouldComponentUpdate()
- componentWillUpdate():将要更新
- render():更新(重新渲染)
- componentDidUpdate():已经更新
- 组件的销毁阶段:只执行一次
- componentWillUnmount():组件将要被移除