20200531react01

65次阅读

共计 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 使用【@】优化路径问题

正文完
 0