共计 7459 个字符,预计需要花费 19 分钟才能阅读完成。
一: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 使用创建的组件, 以标签的方式使用组件
<Hello></Hello>
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 <div> 这是一个 calss 创建的组件 </div>
}
}
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 使用【@】优化路径问题