一:react概述
二:DOM和虚拟DOM介绍
三:虚拟DOM的本质和目的
四:diff算法介绍
五:webpack4.x的基本使用【创建webpack项目】
1 新建一个文件夹 【01.webpack-base】
2 使用命令【num init -y】,快速创建一个webpack项目【快速初始化项目】,【运行后在文件夹下产生一个package.json的文件】。
3 新建一个【src】目录,存放源代码。
4 新建一个【dist】目录,存放产品打包后的文件。
5 新建首页【index.html】
6 新建js入口文件【index.js】
7 使用cnpm安装webpack【cnpm i webpack -D】
8 全局运行【npm i cnpm -g】
9 安装【cnpm-cli】,【cnpm i webpack-cli -D】
10 在【webpack.config.js】文件中配置运行环境
//向外暴露一个打包对象
module.exports = {
mode:'development'//development production
}
11 约定的打包的入口文件为【index.js】文件,【约定大于配置的规则】
12 使用【webpack】打包,打包后在【dist】目录下生成一个【main.js】的文件。
六:webpack-dev-server的基本使用
1 问题:修改代码后,【mian.js】还是上次打包的文件,不起作用,每次都要重新打包,比较麻烦
2 实时打包编译工具:【webpack-dev-server】
3 安装:【cnpm i webpack-dev-server -D】
4 在【package.json中配置】
"dev":"webpack-dev-server"
5 执行:【npm run dev】,即可完成修改代码后的自动编译
6 生成的【mian.js】是放在内存中的根目录下,引用内存中的【main.js】
7 配置编译后自动打开浏览器
"dev":"webpack-dev-server --open --port --host"
七:配置html-webpack-plugin插件
1 问题:编译后没有自动跳转到首页
2 解决:配置编译后自动跳转到首页,即配置首页到内存中
3 安装【html-webpack-plugin】插件,【cnpm i html-webpack-plugin -D】
4 在【webpack.config.js】中进行配置【html-webpack-plugin】插件
//配置插件
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') //配置在内存中自动生成index.js的插件
//创建一个插件的实例对象
const htmlPlugin = new HtmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'),
filename:'index.html'
})
//向外暴露一个打包对象
module.exports = {
mode:'development',
plugins:[
htmlPlugin
]
}
总结:完成了打包后的【mian.js】文件进内存,【index.html】进内存,并且打包好的【mian.js】自动注入到【index.html】中,使用包管理工具的基本环境设置完成。
八:使用react渲染最基本的虚拟DOM对象
1 安装react依赖【cnpm i react react-dom -S】
react:专门用于创建组件和虚拟DOM元素,同时组件的生命周期在这里
react-dom:专门用于对虚拟DOM进行操作,最主要的应用场景是:【ReactDOM.render()】。
2 在【index.html】页面中,创建容器:
3 在【index.js】中导入react。
import React from 'react'
import ReactDOM from 'react-dom'
4 在【index.js】中,使用【createelement】方法,创建虚拟DOM
参数说明:
参数1:标签
参数2:标签属性
餐宿3:其他的节点或者文本内容
5 在【index.js】中,获取容器,并将虚拟DOM放入获取到的容器中,【调用render函数渲染】
参数说明:
参数1:要渲染的元素
参数2:添加到的目标容器
九:使用createelement(),实现虚拟DOM元素的嵌套
十:在react中启用jsx语法
1 将html直接定义在js代码中。这些标签代表了一个或者多个js对象。并不是标签。这种在js中混合写入html代码的形式叫做JSX。浏览器默认不识别,可以使用第三方的工具来转换为原生的react中的方法。JSX的本质:在运行的时候被转换为了createlement()。
2 第三方的转换器,使用babel转换html标签
3 安装Babel插件
运行【cnpm i babel-core babel-loader babel-plugin-transfrom-runtime -D】
运行【cnpm i babel-preset-env babel-preset-stage-0 -D】
4 安装能识别转换JSX语法的包:
运行【cnpm i babel-preset-react -D】
5 添加【.babelrc】配置
{
"presets" :["env","stage-0","react"],
"plugins" :["transform-runtime"]
}
6 在【package.json】中加入插件的配置信息
//向外暴露一个打包对象
module.exports = {
mode:'development',
plugins:[
htmlPlugin
],
module:{ //所有第三方的loader的匹配规则
rules:[
{test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
]
}
}
7 通过以上的配置,babel的配置完成,我们可以使用JSX语法来创建虚拟DOM元素或者组件。
十一:在jsx中书写js代码
1 在JSX中书写js代码,使用大括号即可
2 渲染数字
3 渲染字符串
4 渲染布尔值【需要tostring()】
5 为属性绑定值
6 渲染JSX元素
7 渲染JSX元素数组【这里有一个key的概念需要注意】
8 将普通的字符数组转换为jsx数组渲染到页面上【俩种方法】
**javascript中分号的问题:
当下一行的代码是以:`[,(,+,-,/`开头的,则上一行必须以分号结尾。**
十二:将普通的字符串数组,转为jsx数组,并渲染到页面上
一:在外部循环:
1 方法一(foreach方式):
(1)创建一个普通的字符串数组
(2)创建一个新的字符串数组
(3)遍历【froeach(item => {...})】旧的字符串数组,将每一个item用jsx语法包裹后添加到新的字符串数组中
(4)将新的字符串数组添加到容器中
2 方法2(map的方式):
(1)数组的map方法:遍历数组,但是有返回值
(2)作用:对遍历的每一项进行操作后将操作后的对象作为返回值返回。
(3)返回一个数组
总结:不管是foreach的方式还是map的方式,最终都要返回一个数组
二:在内部循环
1 在大括号中写js代码,循环出jsx结果。
十三:react中key的作用
1 作用:虚拟dom元素的状态需要保持的时候要提供key值,否则业务逻辑可能会出错。
2 react中需要key加到循环控制的直接元素上。
十四:关于jsx的语法的注意事项
1 jsx中的注释:使用行内注释,
2 为jsx中的元素添加class:【className】
3 为jsx中的lable元素添加for:【htmlfor】
4 在JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹
十五:创建组件的第一种方式和传递propos参数
1 创建组件的第一种方式【使用构造函数创建组件】
使用构造函数创建组件:
function Hello (){//首字母大写
...
return 组件;//必须返回一个合法的jsx虚拟DOM元素
}
2 使用创建的组件,以标签的方式使用组件
3 react浏览器插件
4 传递参数【在组件中接受外界定义的数据】
(1)为渲染jsx的DOM元素中绑定属性
使用组件并传递参数。
(2)在构造函数中传入【propos】形参
(3)在组件中使用【propos】对象获取数据
(4)注意事项:propos中的所有的数据都是只读的,定义之后不能改变
十六:使用ES6的展开运算符简化传递propos数据
//使用如下语法,即可获得propos中的所有的数据
...js对象
十七::将组件抽取到单独的jsx文件中
1 新建components文件夹
2 新建hello.jsx文件
3 在jsx文件中导入react react-dom依赖
3 使用构造函数创建组件
4 向外暴露组件
> //方式1:
>
> export default Hello
>
> //方式2:
>
> 创建并向外暴露组件
5 使用组件【js中导入组件】
> import Hello from './components/Hello.jsx'
>
> 【配置文件中要配置jsx后缀】
6 配置webpack在导入组件的时候,省略后缀【.jsx】后缀名
//配置插件
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// //创建一个插件的实例对象
const htmlPlugin = new HtmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'),
filename:'index.html'
})
//向外暴露一个打包对象
module.exports = {
mode:'development',
plugins:[
htmlPlugin
],
module:{
rules:[
{test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
]
},
resolve:{
extentsions:['.js','.jsx','.json'] //表示这几个文件的后缀名可以不写
}
}
注意事项: | |
---|---|
1 | 组件的首字母小写 |
2 | 在配置文件中要配置jsx的后缀 |
十八:配置webpack设置根目录:
1 配置别名:
//配置插件
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// //创建一个插件的实例对象
const htmlPlugin = new HtmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'),
filename:'index.html'
})
//向外暴露一个打包对象
module.exports = {
mode:'development',
plugins:[
htmlPlugin
],
module:{
rules:[
{test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
]
},
resolve:{
extentsions:['.js','.jsx','.json'], //表示这几个文件的后缀名可以不写
alias:{ //表示别名
** '@':path.join(__dirname,'./src') //@表示项目根目录中**的'./src'
}
}
}
2 使用@符号映射:
import Hello form '@/component/Hello'
十九:【第二种创建组件的方式】创建类并且用过constructor挂载实例属性:
1 class的方式是ES6的新特性:
2 class的基本使用:
(1)ES6中的class关键字是实现面向对象编程的新形式
(2)创建类:
·传统方式:
function Person(name,age){
this.name = name
this.age = age
}
const p1 = new Person("sdfsd","12");
console.log(p1)
·使用class方式创建对象【创建类实例并且用过constructor挂载实例属性】
//定义类
class Animal{
//使用构造器为创建的对象赋值
//每一个类中都有一个构造器
//没有定义,会自动生成一个默认的空参构造器:constructor(){}
//手动定义构造器,会覆盖默认的空参构造器
//构造器中的作用:创建类实例的时候,会优先执行构造器中的代码
constructor(name,age){
this.name=name
this.age=age
}
}
const a1 = new Animal("大黄","23");
console.log(a1)
(3)实例属性:
通过new的实例访问到的属性,叫做实例属性
(4)静态属性:
通过构造函数直接访问到的属性叫做静态属性【直接挂载给构造函数的属性】
即直接通过类名访问的属性
在class中,与构造函数平级,使用static修饰的属性
(5)实例方法,【挂载到原型实例上的方法】
//传统的对象
//可以被类的实例访问的方法:
person.prototype.say = function(){
...
}
//class对象
//与构造方法平级
jiao(){
...
}
(6)静态方法:【挂载给构造函数的方法】
//传统类对象
//对象实例访问不到
person.show=function(){
...
}
//class类对象,在构造方法上挂载静态方法
//使用static关键字修饰
static show() {
...
}
二十:总结class的基本用法和俩个注意事项:
基本用法:
(1)class内部只能写构造器,属性【静态,实例】,方法【静态,实例】
(2)本质还是构造函数的方式,【语法糖】
(3)
二十一:使用extends实现子类继承父类
1 创建父类
2 创建子类
3 在class类中使用extends实现继承,并且访问实例属性
4 子类访问父类的实例方法
4.1父类定义实例方法
4.1子类访问父类的实例方法
5 constructor构造器中的super函数的使用说明:
5.1 使用super访问父类的构造函数
5.2 在子类的构造器中使用super()方法访问父类的构造方法
5.3 问题:
(1)为什么要在子类的构造器中调用super()方法
答:因为,如果一个子类通过extends关键字继承了父类,那么在子类的构造函数中必须优先使用super()方法。
(2)什么是super()
答:super()是一个函数,而且是父类的构造器,子类中的super()其实是构造器的一个引用。
(3)为什么调用了super(),方法,实例的属性都变为了undefined
答:需要将参数通过构造器传递给真正给属性赋值的构造器上
6 为子类挂载独有的实例属性和实例方法:
答:使用this关键字为子类独有的实例属性赋值,【语法规范,子类中this只能放在super()方法之后】。
二十二:使用class关键字创建组件【创建组件的第二种方式】
1 最基本的组件结构
calss 组件名称 extends React.component{//必须继承React.component类
//在组件的内部,必须要有render函数
//作用:渲染当前的组件所对应的虚拟的DOM元素
//是class的一个实例方法
render(){
//必须返回合法的JSX虚拟DOM元素
return 这是一个calss创建的组件
}
}
2 为class创建的组件传递propos参数并直接使用this.propos来访问
(1)使用组件的时候从外部接受参数
(2)组件内部获取参数,【在class创建的组件中如果想使用外部传入的参数,不需要接受,只需要使用【{ths.propos.属性}】即可接受参数】
(3)使用ES6中的扩展方式接受参数
二十三:介绍react中的this.state
1 props只读的特性
2 俩种创建组件方式的区别(对比):
(1)使用class创建的组件有自己的私有的数据和生命周期,使用function创建的组件只有propos,没有生命周期。
有状态组件的私有数据:
constuctor(){
//调用父类的构造方法
super()
//保存有状态组件的私有数据
this.state={
//state中的数据可读可写
msg:"......."
}
}
render(){
rerurn ......
}
返回组件的是时候,通过【this.state.shuxing】访问私有数据。
(2)用构造函数创建的组件叫做【无状态组件】,使用class创建的组件叫做【有状态组件】,无状态组件一般用的不多。
3 什么情况下使用有状态组件,什么情况下使用五状态组件?
(1)如果一个组件需要自己的私有的数据,使用有状态组件
(2)如果一个组件不需要自己的私有的数据,使用无状态组件
(3)无状态组件由于没有私有数据,运行的效率较高
4 有状态组件和无状态组件的本质区别?
答:(1)有无state属性(2)有无生命周期函数
5 组件中的props和是state(data)之间的区别?
(1)propos中的数据都是外界传递进来的,只读,不能赋值
(2)state(data)中的数据都是组件私有的,(通过ajax获取到的数据,一般都是私有数据),可读可写。
二十四:评论列表案例
1 通过for循环生成多个组件
//数据
CompentList:[
{id:1,user:'张1',content:'哈哈,沙发1'},
{id:2,user:'张2',content:'哈哈,沙发2'},
{id:3,user:'张3',content:'哈哈,沙发3'},
{id:4,user:'张4',content:'哈哈,沙发4'},
{id:1,user:'张5',content:'哈哈,沙发5'},
]
2 创建父组件
3 在父组件的state【私有数据区】挂载数据
4 在返回值的部分循环数据并创建子组件。
二十五:将评论的item抽离为单独的CmItems组件
二十六:将评论列表和评论项抽取为单独的组件
1 抽取独立的组件的时候注意组件的引用关系,导入组件的路径问题,
二十七:抽取独立的组件之后的路径问题的优化
1 使用【@】优化路径问题