开始一个工程
安装 脚手架 及工具
下载node.js并安装 node -v检查是否安装成功
npm install create-react-app -g
安装yarn
npm install -g yarn
yarn --version
Yarn 淘宝源安装
yarn config set registry https://registry.npm.taobao.org -g
yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g
如果出现 ‘yarn’ 不是内部或外部命令,也不是可运行的程序 或批处理文件
卸载 npm uninstall yarn -g
安装 npm install yarn (最好不要用别的安装命令,会没效果)
添加环境变量:系统变量path添加 C:\Users\bokeyuan\node_modules\yarn\bin
重新打开cmd执行:yarn -v 查看版本号
创建项目 myapp
CMD 到工程目录下 利用脚手架 创建
create-react-app myapp # 项目名不能有大写
src 目录下
index.js (必须叫index.js 否者静态目录寻找不到)
所有 其他 文件可以删除
运行 react 的服务器
npm start
生成的文件结果及作用
|-- README.mad 使用说明
|-- node_modules 所有的依赖文件
|-- package-lock.json 锁定安装时的包版本号,保证团队一直
|-- package.json
|-- public 静态公共目录
|-- src 开发用的源代码目录
其他电脑配置相同环境可以复制除 node_modules 意外的文件
用一下命令重建环境
npm i
打包项目
构建项目
npm run build
安装 serve
npm install serve -g
运行 serve
serve build
运行 serve 报错 的解决方案
报错信息:无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统中禁止执行脚本
原因分析:禁止执行脚本,那就打开权限执行脚本嘛
解决方案:
- 打开 powerShell 用管理员身份运行 (Win + X)
- 输入命令: set-ExecutionPolicy RemoteSigned
- 输入A
# 搭配django
build 文件下 static 放入 Django的static
其他文件 放入 Django 的templates 文件夹夏
正常调用index.html
# 引入 bootstrap
npm install bootstrap --save
在index.js引入Bootstrap
import 'bootstrap/dist/css/bootstrap.min.css'
流程控制
循环遍历
for 循环
//循环遍历
for(var i; i < v1.length; i++){
// i = 0/1/2
}
//快速 循环遍历
var v1 = [11,22,33]
for(var i in v1){
// i = 0/1/2
}
map 循环
// 第一i中写法
<div>
{
arr.map((item, index) => {
return <div key={index}>{item}</div>
})
}
</div>
// 第二种写法
var str = arr.map((item, index) => {
return <div key={index}>{item}</div>
})
ReactDOM.render(
<div>
{str}
</div>,
document.getElementById("root2")
)
// 第三种写法
var str=[];
for(let i=0;i<arr.length;i++){
str.push(<div key={i}>{arr[i]}</div>)
}
ReactDOM.render(
str,
document.getElementById("root3")
)
forEach 循环
// 用法一
arr.forEach((item, index) => {
......
})
// 用法二
arr.forEach((item, index) => {
return <div key={index}>{item}</div>
})
遍历数组用map和forEach的区别
1.map函数返回一个新的数组,在map的回调函数里,迭代每一项的时候也必须有返回值。
2.forEach 没有返回值。
map方法处理数据之后会返回一个新的数组,同时不会改变原数组的值;
如果数组为空则无法进行遍历,所以要对数组做非空校验。
if 条件语句
if (条件) {
执行语句1
}else if (条件){
执行语句2
}else{
执行语句3
}
三元运算符
条件表达式 ? 真就执行表达式1:假就执行表达式2
//三元运算符 的变体
条件表达式 && 真就执行表达式1
数据
数据类型
查看数据类型
typeof "john"
数据类型转换
// 转换为字符串类型
String(123)
(100 + 23).toString()
// 字符串装换为数字类型
Number("3.14")
更多:https://www.runoob.com/js/js-type-conversion.html
提取数字
1.前面带数字,后面非数字,可以直接用parseFloat()函数:
var num1 = parseFloat("2.89元"); //num1 : 2.89
2.像"生于1999年"这样字符串中只含有一个整型数值的字符串,直接使用正则表达式将数字的字符删除掉就行
var str1 = '生于1999年';
var num1 = str1.replace(/[^\d]/g,' ');
3.对于字符串中含有多数值,使用字符串的match方法,通过正则表达式提取字符串的所有数字(包含整数和小数):
var str = '大米:2.57斤/元,白菜:3.65元/斤';
var arr = str.match(/\d+(.\d+)?/g); // arr: ["2.75","3.65"]
[正则表达式] 提取字符串的所有数字
1、不考虑小数
此时可以使用正则表达式(/\d+/g)来从字符串中提取数字
使用正则表达式(/\d+/g)来从字符串中提取数字
var str = '123sdfsdf456sdffs789'
var numArr = str.match(/\d+/g)
// 直接输出
console.log("直接输出:"+numArr) // => ["123", "456", "789"]
// 也可以把数字拼接起来
console.log("拼接后输出:"+numArr.join('')) // => 123456789
2、考虑小数
此时可以使用正则表达式(/\d+.\d+/g)来从字符串中提取数字
var str = '123.456sdfsdf456.789'
var numArr = str.match(/\d+\.\d+/g)
console.log(numArr) / /=> ["123.456", "456.789"]
变量
var name = "世界"
var v1 = name.length://获取字符串长度
var v2 = name.[0];//利用索引获取字符串中的字符
var v3 = name.trim(); //去除空白
var v4 = name.substring(0,2) //字符串切片 (前取后不取)
案例: 跑马灯
function s() {
var n = document.getElementById('text') //利用ID查找 获取 标签 保存到n
var x = n.innerText // 标签对象n 的字符串属性的值 保存到x
n.innerText = x.substring(1, n.length) + x[0] //改变字符串 后 赋值给 n 的 字符串属性
console.log("控制台显示x:",x)
}
setInterval(s, 200) //利用间隔函数 设置 每秒的运行次数(FPS)
数组
创建数组
//定义列表
var v1 = [11,22,33]
//用 Array函数构建列表
var v2 = Array([11,22,33])
//生成 带10个空元素的 数组
var b = new Array(10)
修改值
a[0] = '你好'
追加
返回值是列表长度
尾部追加
var l1 = a.push('奥德赛')
在列表的 头部 追加
a.unshift('达到')
删除
返回值是列表长度
删除最后一个元素
var l2 = a.pop()
删除头部
a.shift()
合并数组
返回新列表
var a = [0, 0, 0, 0, 0, 0, 0]
var b = [1, 1, 1]
var c = a.concat(b, 3, true, "字符串")
提取数组
提取 (下表为0~3的元素) 数组
返回值一个新数组
var c = a.slice(0, 3)
splice 根据 索引 操作
索引 (下表为1的位置开始 ) 追加 元素
a.splice(1,0,'大大')
索引 (下表为e的位置开始 ) 删除 1个元素
a.splice(e,1)
合并字符串 join
合并字符串 (默认以 , 分隔)
var fruits = ["Banana", "Orange", "Apple", "Mango"]
var x = fruits.join()
console.log(x)
https://www.runoob.com/jsref/jsref-obj-array.html
数字 字符串 互换 提取
import React from 'react';
const App2 = () => {
//字符串转 数字
var a = Number("023123")
// 数字转字符串
var b = String(111111)
//提取 字符串 中的数字
var c = parseInt("102元")
const xxx = () => {
console.log('字符串转为数字 a:', a)
console.log('数字转换为字符串 b:', b)
console.log('提取字符串中的数字 c:', c)
}
return (
<div>
<button onClick={xxx}>显示</button>
</div>
);
}
export default App2;
更多操作 方法
https://www.runoob.com/js/js-obj-array.html
数组 的 引用
对象 块
定义
info = {
'name':'吴博文',
'age': 10
}
// JS中的对象(字典) key(键) 可以不加引号
info = {
name:'吴博文',
age: 10
}
获取 更新 删除 值
info['age'] = 11
//简便写法
info.age = 11
//删除
delete info['name']
delete info.name
对象的for 遍历
for (var i in info){
i // name/age i的值就是对象(字典)的key(键值)
x = info[i] //获取值
}
函数
https://www.runoob.com/jsref/jsref-obj-math.html
function aaaa(){
...
}
aaa()
MATH 函数
生成 随机数
//返回 0 ~ 1 之间的随机数
Math.random()
//返回数的平方根
Math.sqrt(x)
// 返回 x 的 y 次幂
Math.pow(x, y)
//返回 x,y,z,...,n中的最低值
Math.min(x,y,z,...,n)
//四舍五入
Math.round()
BOM DOM
控制台打印
var a = "也可以打印变量"
console.log("这段文字会在控制台显示",a)
提示框
基础提示框
const info = () => {
window.alert("提示框")
}
带 确定和取消的提示框 返回布尔值
const info = () => {
var res = window.confirm("是否同意")
console.log(res)
}
带 输入内容的提示框 返回驶入内容
const info = () => {
//第二个参数为默认值
var res = window.prompt("请输入内容", 100)
console.log(res)
}
打开一个新的页面
const info = () => {
window.open("https://www.baidu.com/")
}
页面历史记录
<Button type="primary" onClick={() => window.history.back()}>
上一个页面
</Button>
<Button type="primary" onClick={() => window.history.forward()}>
下一个页面
</Button>
<Button type="primary" onClick={() => window.history.go()}>
刷新页面
</Button>
获取url
const info = () => {
alert(window.location)
}
location 的属性和方法…
页面加载完成后 onload
window.onload = function () {
alert("页面完成")
}
案例:ReactDOM 的用法
//导入 React 核心包 解释jsx语法
import React from "react"
// 导入 React虚拟DOM 把组件渲染到页面
import ReactDOM from "react-dom"
//利用 js 的document 操作选择 ID 为root的标签 在它的列表中添加
ReactDOM.render(
<div><h1>利用ReactDOM渲染HTML标签</h1></div>,
document.getElementById("root")
)
案例:ES6 类的继承
class T {
//类的初始化函数
constructor() {
;
}
// 类的方法函数
fuc_A() {
console.log("这个信息来自父类~~~~")
}
}
//定义一个类C 继承 T类
class C extends T {
//定义自己的方法函数
fuc_B() {
console.log("这个消息来自己子类~~~~~")
}
}
//创建 一个实例
var a = new C()
//调用 实例的方法
a.fuc_A()
a.fuc_B()
事件监听器
常用CSS (jsx写法)
css-in-js
https://blog.csdn.net/qq_45677671/article/details/117332040?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165336194316782425147803%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165336194316782425147803&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-117332040-null-null.142v10control,157v8control&utm_term=css+in+js&spm=1018.2226.3001.4187
npm i -S styled-components
案例:内联样式测试
import React, { Component } from 'react';
// 导入样式组件
import styled from 'styled-components';
class App2 extends Component {
aa() {
console.log("ddadf")
}
render() {
return (
<div>
<MDIV onClick={this.aa}>内部文件写法</MDIV>
</div>
);
}
}
export default App2;
// 样式
const MDIV = styled.div`
font-size: 50px;
color: red;
background-color: red;
`
自身定位
定位模式
position :'static',
HTML 元素的默认值,即没有定位,遵循正常的文档流对象
静态定位的元素不会受到 top, bottom, left, right影响
position :'fixed ',
元素的位置相对于浏览器窗口是固定位置
即使窗口是滚动的它也不会移动
position :'relative',
相对定位元素的定位是相对其正常位置
position :'absolute',
绝对定位的元素的位置相对于最近的已定位父元素
如果元素没有已定位的父元素,那么它的位置相对于
定位模式
position :'sticky ',
sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。
position: sticky; 基于用户的滚动位置来定位。
粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。
它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。
元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。
定位坐标
right:'100px',
left:'100px',
top:'100px',
bottom: '100px',
更多:https://www.runoob.com/css/css-positioning.html
相对定位
子元素对齐
//子元素 居中对齐
display: 'block',
margin: 'auto',
// 文本(子元素) 横向居中对齐 或者 左右对齐
textAlign: 'center',
textAlign: 'left',
textAlign: 'right',
//每一行被展开为宽度相等,左,右外边距是对齐(如杂志和报纸)
textAlign: 'justify',
// 文本(子元素) 垂直居中对齐
padding: '70px 0',
//子元素的行高设置
lineHeight: '100px',
更多:https://www.runoob.com/css/css-align.html
浮动
// 左浮动
float:'left',
// 右浮动
float:'right',
// 无浮动
float:'none',
// 中心浮动
float:'inherit',
//清除浮动
clear:'both',
文本
// 字体颜色
color:'blue',
// 字体大小
fontSize:'2.5em',
fontSize:'100%',
// 文本修饰
//清除默认 文本修饰
texDecoration:'none',
// 上线
textDecoration:'overline ',
// 删除线
textDecoration:'line-through',
// 下线
textDecoration: 'underline',
https://www.runoob.com/css/css-text.html
https://www.runoob.com/css/css-font.html
背景
// 背景颜色
backgroundColor:'red',
https://www.runoob.com/css/css-background.html
盒模型
// 清除边框外的区域,外边距是透明的
margin: '25px',
// 围绕在内边距和内容外的边框
border: '25px solid green',
// 清除内容周围的区域,内边距是透明的
padding: '25px',
// 盒子的内容,显示文本和图像
// Content(内容) - 盒子的内容,显示文本和图像
margin 外边距 详细
https://www.runoob.com/css/css-margin.html
border 边框 详细
https://www.runoob.com/css/css-border.html
padding 填充 详细
https://www.runoob.com/css/css-padding.html
盒模型详细:https://www.runoob.com/css/css-boxmodel.html
Bootstrap5
菜鸟教程 https://www.runoob.com/bootstrap5/bootstrap5-tutorial.html
仿官方中文文档 https://v5.bootcss.com/
组件
组件库
PC版 https://ant.design/docs/react/introduce-cn
手机版https://mobile.ant.design/zh
[Ant Design] 组件库
https://ant.design/components/button-cn/
import React from "react"
import ReactDOM from "react-dom"
//导入组件 首字母必须大写
import T from "./01-base/01-class"
//吧组件添加到 目标中
ReactDOM.render(
// 可以单标签 也可以双标签
<T></T>
document.getElementById("root")
)
类 组件
vscode 快速创建react 类组件 rcc
// 定义类
class Runoob {
constructor(name, year) {
this.name = name;
this.year = year;
}
age() {
let date = new Date();
return date.getFullYear() - this.year;
}
}
// 实例化 类
let runoob = new Runoob("菜鸟教程", 2018)
函数式 组件
普通函数
import React from "react"
//定义函数组件 首字母必须大写
function App() {
//返回值
return (
<div>
<h1>函数组件返回的信息</h1>
</div>)
}
//实例化 组件
export default App
箭头函数
vscode 快速创建react 函数组件 rfc
import React from "react"
//箭头函数
const Bpp = () => <div><h1>箭头函数送来的信息~~~~~</h1></div>
//导出 箭头函数
export default Bpp
嵌套
自定义标签只能嵌套在 函数或者类组件定义中
import React from "react"
//箭头函数1
const Bpp1 = () => <div><h1>箭头函数1送来的信息~~~~~</h1></div>
//箭头函数2
const Bpp2 = () => <div><h1>箭头函数送2来的信息~~~~~</h1></div>
//箭头函数3 桥套自定义函数
const App = () => <div>
<Bpp1></Bpp1>
<Bpp2></Bpp2>
</div>
//导出 组件 App
export default App
插槽
使用 this.props.
children
定义插槽
import React, { Component } from 'react'
class App2 extends Component {
render() {
return (
<div>
<A>
<B></B>
</A>
</div>
);
}
}
export default App2
class A extends Component {
render() {
return (
<div>
<h1>这个是第一个子组件</h1>
{this.props.children}
{/* 多个插槽最少需要两个标签的使用*/}
{/*
{this.props.children[0]}
{this.props.children[1]}
{this.props.children[1]}
*/}
</div>
);
}
}
class B extends Component {
render() {
return (
<div>
<h1>第二个组件放在了插槽中</h1>
</div>
);
}
}
表达式
import React from "react"
const name = '吴博文'
const age = 10
const App = () => <div>
{/* 字符串运算 */}
<div> {"年龄是:" + 10}</div>
{/* 字符串加变量 */}
<div> {"名字是:" + name}</div>
{/* 数字运算 */}
<div>{20 + 10}</div>
{/* 数字和變量运算 */}
<div>{age + 10}</div>
{/* 三目运算符 */}
<div>{10 > 20 ? "对" : "错"}</div>
</div>
//导出 组件 App
export default App
样式
外联样式 || 内敛样式 || 行内样式
import React from "react"
import '../css/a.css'
// 导入css 模块
定义样式变量 属性名必须改成小驼峰写法
var a = {
background: 'red',
fontSize: '50px'
}
//定义组件
const App = () => <div>
<div style={a}>这个组件使用的是内联样式(React官方推荐)</div>
<div style={{ background: 'yellow', fontSize: '50px' }}>这个组件使用了行内样式(React官方推荐)</div>
<div className="a">这个组件使用外联样式</div>
</div >
//导出 组件 App
export default App
a.css
.a {
background-color: rgb(149, 149, 186);
font-size: 50px;
}
行内 字符串
单个字符串
<div className={this.state.isActive?"active":"default"}>
demo
</div>
多个字符串 推荐
<div className={`content ${this.state.isActive?"active":null}`}>
demo
</div>
其他写法: 数组转化
<div className={["container", this.state.isActive?"active":null].join(' ')}>
demo
</div>
特殊功能组件
二维码读取
https://blog.csdn.net/weixin_43827462/article/details/119350721
获取
this 和 evt
this
指向调用它的实例对象
evt
指向 触发本函数 的实例(按钮)
import React, { Component } from 'react'
class App extends Component {
a = '属性A'
// 箭头函数中的this指向实例对象 App
// e 获取对象 给 函数体内部处理
add_1 = (e) => {
console.log("箭头函数1 调用类属性A:", this.a, e.target)
}
render() {
return (
<div>
{/* 点击 执行箭头函数 调用实例化对象的 add_1 (可以传递参数) */}
{/* e 获取对象(button对象本身) 传递进 函数内部 */}
<button onClick={(evt) => this.add_1(evt)}>确定</button>
</div>
);
}
}
export default App
引用 ref
创建一个引用对象来操作标签
案例:获取输入框中的值
import React, { Component } from 'react'
class App extends Component {
// 创建一个 ref 对象
myRef = React.createRef()
add_1 = () => {
// 调用 实例化对象 中的 对象myRef 的字典current中的value值
console.log("调用的标签的值是:", this.myRef.current.value)
}
render() {
return (
<div>
{/* 绑定 ref对象 到 标签 */}
<input type="text" ref={this.myRef} />
<button onClick={() => this.add_1()}>确定</button>
</div>
);
}
}
export default App
案例:点击按钮 盒子变色
import React, { Component } from 'react';
class App extends Component {
//创建一个引用
divRef = React.createRef()
myStyle = {
backgroundColor: 'red',
width: '100px',
height: '100px',
position: 'fixed',
left: 200,
top: 200
}
bianLan = () => {
this.divRef.current.style.backgroundColor = 'blue'
}
bianHong = () => {
this.divRef.current.style.backgroundColor = 'red'
}
render() {
return (
<div>
<button onClick={this.bianLan}>变蓝色</button>
<button onClick={this.bianHong}>变红色</button>
{/* 设置 引用指向 */}
<div ref={this.divRef} style={this.myStyle}></div>
</div>
);
}
}
export default App;
状态
类组件 状态的变化会刷新 render函数
函数组件中 状态的变化会刷新 整个函数
案例:收藏
利用 setState 间接修改 state 状态
rander函数 会等 setState 更新完状态有才会执行后面的代码
setState 不能放在rander函数中 否则会造成死循环
import React, { Component } from 'react'
class App extends Component {
state = {
at: 1
}
stc() {
this.setState({ at: !this.state.at })
if (this.state.at) {
console.log("这里是收藏的逻辑~~~")
} else {
console.log("这里是不收藏的逻辑~~~")
}
}
render() {
return (
<div>
{/* 新建一个按钮 并且绑定触发事件 */}
<button onClick={() => this.stc()}>
{this.state.at ? "收藏" : "不收藏"}
</button>
</div>
)
}
}
export default App
案例: 备忘录 (map)
import React, { Component } from 'react'
class App extends Component {
//状态
state = {
list: [
{ ID: 1, V: 'aaa', ax: false },
{ ID: 2, V: 'bbb', ax: false },
{ ID: 3, V: 'ccc', ax: false },
],
value: "初始值",
}
//选择框状态 更新
boxchange = (index) => {
let newlist = [...this.state.list]
newlist[index].ax = !this.state.list[index].ax
this.setState({
list: newlist
})
}
//文本框状态 更新
mychange = (e) => {
this.setState({
value: e.target.value
})
}
//添加 标签
myadd = () => {
//concat 展开列表
let newlist = this.state.list.concat()
// list.push(n) 给列表末尾添加一个元素 n
newlist.push({
ID: Math.random(),
V: this.state.value,
ax: false,
})
this.setState({
list: newlist,
value: ""
})
}
//删除 标签
mydel = (e) => {
// ... 展开列表
let newlist = [...this.state.list]
// splice(e,1,n) 从e到n 每隔1个 删除
newlist.splice(e, 1)
this.setState({
list: newlist
})
}
render() {
return (
<div className='container '>
{/* 输入框数据更新 */}
<input onChange={(event) => this.mychange(event)} type="text" value={this.state.value} />
{/* 点击 触发函数 添加标签*/}
<button onClick={() => this.myadd()}>添加</button>
{/* 判断列表是否为空 */}
<h1>
{this.state.list.length === 0 ? "列表空了~~~~" : ""}
</h1>
{/* map循环遍历 */}
{this.state.list.map((item, index) =>
<li key={item.ID}>
{/* 选择框 状态更新 */}
<input onChange={() => this.boxchange(index)} type="checkbox" checked={item.ax} />
{/* 状态 控制 行内样式 */}
<span style={{ textDecoration: item.ax ? "line-through" : "" }}>
{item.V}
</span>
{/* 点击 触发喊出 删除标签 */}
<button onClick={() => this.mydel(index)}>删除</button>
</li>
)}
</div>
);
}
}
export default App
案例:动态选择
import React, { Component } from 'react';
import App1 from "./app01"
import App2 from "./app02"
import App3 from "./app03"
class App extends Component {
state = { a: '0' }
sc = (e) => {
this.setState({
a: e.target.id
})
}
render() {
return (
<div className="container" >
<div className="d-flex justify-content-around mb-5 ">
<div className={`p-2 ${this.state.a === "1" ? "bg-danger" : "bg-info"}`}
id='1' onClick={(e) => this.sc(e)}>页面一
</div>
<div className={`p-2 ${this.state.a === "2" ? "bg-danger" : "bg-info"}`}
id='2' onClick={(e) => this.sc(e)}>页面二
</div>
<div className={`p-2 ${this.state.a === "3" ? "bg-danger" : "bg-info"}`}
id='3' onClick={(e) => this.sc(e)}>页面三
</div>
</div>
<div className="d-flex justify-content-around ">
{this.state.a === '1' && <App1></App1>}
{this.state.a === '2' && <App2></App2>}
{this.state.a === '3' && <App3></App3>}
</div>
</div >
);
}
}
export default App;
富文本展示 (解析HTML代码)
<div dangerouslySetInnerHTML={
{
__html:item.mytext
}
}></div>
渲染
条件渲染
案例:同不同意
import React, { Component } from 'react';
class App2 extends Component {
state = {
act: false
}
// 回调函数
aaa = () => {
this.setState({ act: !this.state.act })
}
// 条件渲染
abc = () => {
if (this.state.act) {
return <div><h1>同意</h1></div>
} else {
return <div><h1>不同意</h1></div>
}
}
render() {
return (
<div>
<button onClick={this.aaa}>点击</button>
{this.abc()}
</div>
);
}
}
export default App2;
案例:每秒更新状态(条件渲染)
import React, { Component } from 'react';
class App2 extends Component {
state = {
act: false
}
componentDidMount() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
componentDidUpdate() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
render() {
if (this.state.act) {
return <div><h1>同意</h1></div>
} else {
return <div><h1>不同意</h1></div>
}
}
}
export default App2;
案例:同不同意(三元运算符)
import React, { Component } from 'react';
class App2 extends Component {
state = {
act: false
}
componentDidMount() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
componentDidUpdate() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
render() {
return (
<div>
{this.state.act ? "同意" : "不同意"}
</div>
);
}
}
export default App2;
案例:同不同意(逻辑运算符)
import React, { Component } from 'react';
class App2 extends Component {
state = {
act: false
}
componentDidMount() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
componentDidUpdate() {
setTimeout(() => this.setState({ act: !this.state.act }), 1000)
}
render() {
return (
<div>
{this.state.act && "不同意"}
{!this.state.act && "同意"}
</div>
);
}
}
export default App2;
列表渲染map
尽量避免使用 index 设置 key
案例: 批量创建标签
import React, { Component } from 'react';
class App2 extends Component {
state = {
list: [
{ ID: 1, name: "夏红", age: 21, },
{ ID: 2, name: "冯绍峰", age: 25, },
{ ID: 3, name: "大法师", age: 20, },
]
}
// 修改状态(删除第i项)
del = (i) => {
let temp_list = [...this.state.list]
temp_list.splice(i, 1)
this.setState({ list: temp_list })
}
render() {
return (
<div>
{this.state.list.map((item, index) =>
<div key={item.ID}>
{/* 遍历 输出内容 */}
<div > {item.name}</div>
<div > {item.age}</div>
{/* 点击 触发回调函数 传入下标 */}
<button onClick={() => this.del(index)}>删除</button>
</div>
)}
</div>
);
}
}
export default App2;
属性
属性的作用主要是接收数据
获取属性列表 this.props
app.js
import React, { Component } from 'react';
import App01 from './app01'
class App extends Component {
render() {
return (
<div>
{/* 设置属性 和属性值 */}
<App01 biaoQian="首页" />
<App01 biaoQian="第二页" />
<App01 biaoQian="第三页" />
</div>
);
}
}
export default App;
app01.js
import React, { Component } from 'react';
class App01 extends Component {
render() {
return (
<div>
{/* 打印属性列表中的 某个属性的值 */}
<h1>{this.props.biaoQian}</h1>
</div>
);
}
}
export default App01;
属性类型的验证 和 默认值
app.js
import React, { Component } from 'react'
//导入属性验证模块
import kerwinPropTypes from 'prop-types'
class App01 extends Component {
//属性 类型验证
static propType = {
biaoQian: kerwinPropTypes.string
}
//属性 设置默认值
static defaultProps = {
biaoQian: "页面"
}
render() {
return (
<div>
{/* 打印属性列表中的 某个属性的值 */}
<h1>{this.props.biaoQian}</h1>
</div>
);
}
}
export default App01
{…obj} 展开列表
通信
单向控制
案例: 受控组件
利用状态控制组件
import React, { Component } from 'react'
class App extends Component {
//初始化状态
state = {
value2: "",
}
x_ref = React.createRef()
//传递数据
shangChuan = () => {
var v = this.x_ref.current.value
if (v === ('')) {
this.setState({
value2: "输入不能为空~~"
})
} else {
this.setState({
value2: v
})
}
}
//重置
chongZhi = () => {
this.x_ref.current.value = ''
this.setState({
value2: ""
})
}
render() {
return (
<div >
{/* 绑定 事件函数 */}
<input type="text" ref={this.x_ref} />
<button onClick={this.shangChuan}>确定</button>
<button onClick={this.chongZhi}>重置</button>
{/* 调用子组件*/}
<App01 shuJu={this.state.value2} />
</div>
);
}
}
export default App
// ####### 可以分割成另一文件#############################
class App01 extends Component {
x_style = {
height: "700px",
width: "500px",
margin: '15px',
padding: '10px',
border: '5px solid red',
}
render() {
return (
<div>
{/* 打印属性列表中的 某个属性的值 */}
<div style={this.x_style}>
<h1>
这个框是子函数部分:
</h1>
<h2>
{this.props.shuJu}
</h2>
</div>
</div>
);
}
}
父子组件通信
使用属性 传递数据 和 函数
import React, { Component } from 'react'
class App extends Component {
state = {
a: false
}
kaiGuan = () => {
this.setState({ a: !this.state.a })
}
render() {
return (
<div>
<button onClick={this.kaiGuan}>父组件发送给子组件</button>
<App1
// 属性的传递方式一 数据
xx={this.state.a}
// 属性的传递方式二 函数
cc={this.kaiGuan}
/>
</div>
);
}
}
export default App
// ####### 可以分割成另一文件#############################
class App1 extends Component {
render() {
return (
<div>
{/* 利用属性 执行 函数 */}
<button onClick={this.props.cc} >子组件发请求给父组件</button>
<h1>
{/* 历史属性 获取 数据 */}
{this.props.xx ? "子组件显示事件" : ""}
</h1>
</div>
);
}
}
通过 REF
获取子组件的状态
非父子通信
发布订阅模式
中心供应商模式(context)
MOBX
安装插件
npm i mobx
变量式 创建一个状态中心
// store.js
import { observable, configure, action } from 'mobx'
// 开启严格模式
configure({
enforceActions: 'always'
})
// 创建
const commonState = observable({
score: 0,
add_score(v) {
this.score += v
},
change_score(v) {
this.score = v
},
}, {
change_score: action,
})
export default commonState;
修改状态
// temp.js
import commonState from './store'
import React, { Component } from 'react'
import A from './A'
// Temp
export default class Temp extends Component {
add = () => {
// 修改 公共状态
commonState.add_score(2)
}
render() {
return (
<div>
<button onClick={this.add}>公共状态加2</button>
<A />
</div>
)
}
}
监听 并使用
// A.js
import React, { Component } from 'react'
import commonState from './store'
import { autorun } from 'mobx'
// A
export default class A extends Component {
state = {
A: 0,
}
componentDidMount() {
// 创建一个监听器 (只有公共状体改变时才会触发回调函数)
this.unAutorun = autorun(() => {
console.log(commonState.score)
// 使用 公共状体 修改自身状态
this.setState({ A: commonState.score })
})
}
componentWillUnmount() {
// 销毁监听器
this.unAutorun()
}
render() {
return (
<div>
{this.state.A}
</div>
)
}
}
类方式 状态中心
// store.js
import { observable, computed, action, makeObservable } from 'mobx'
class Store {
constructor() {
makeObservable(
//指定目标
this,
//定义当前mobx类对象中的数据类型
{
// 数据类
list: observable,
// 修改函数类
change: action,
// 获取类
total: computed,
}
)
}
list = []
//在类中,有一个getter方法,在使用的时候是一个数据
get total() {
return this.list.length;
}
change() {
this.list.push(this.list.length);
}
}
export default new Store();
修改和 监听
// temp.js
import React, { Component } from 'react'
import { autorun } from 'mobx'
import Store from './store'
setInterval(() => {
Store.change()
}, 2000)
autorun(() => {
console.log(Store.total)
})
// Temp
export default class Temp extends Component {
render() {
return (
<div>
</div>
)
}
}
https://www.cnblogs.com/cc-font/p/16046138.html
runInAction()
严格模式
详细教程:https://www.bilibili.com/video/BV1dP4y1c7qd?p=105&spm_id_from=pageDriver
插槽
生命周期
https://www.runoob.com/react/react-component-life-cycle.html
三个常用生命周期
// 组件加载完成后 运行
componentDidMount() { console.log('组件加载完成')}
//组件更新完成后
componentDidUpdate() { console.log('组件更新完成')}
//组件将要卸载前
componentWillUnmount() {console.log('组件将要卸载')}
hooks 函数
useState
案例:显示状态值
import React, { useState } from 'react';
function Example2() {
const [number, setNumber] = useState(0);
const lazy1 = () => {
// 获取点击按钮时的 state
setNumber(number + 1);
};
const lazy2 = () => {
// 每次执行时都会再去获取新的 state,而不是使用点击触发时的 state
setNumber(number => number + 1);
};
return (
<div>
<p>{number}</p>
<button onClick={() => setNumber(number + 1)}>+</button>
<br />
<button onClick={lazy1}>lazy1:只能获取点击按钮时候的状态</button>
<br />
<button onClick={lazy2}>lazy2:每次执行都会重新获取state, 所以获取的都是最新的state</button>
</div>
);
}
export default Example2;
案例:to do list
import React, { useState } from 'react';
const App = () => {
const [data, setdata] = useState("")
const [list, setlist] = useState([])
const changeText = (e) => {
setdata(e.target.value)
}
const addlist = () => {
setlist([...list, data])
setdata("")
}
const dellist = (index) => {
console.log(index)
var templist = [...list]
templist.splice(index, 1)
setlist(templist)
}
return (
<div>
<div><h3>请输入带办事项</h3></div>
<input type="text" onChange={changeText} value={data} />
<button onClick={addlist}>添加</button>
<ul>
{
list.map((itme, index) =>
<li key={index}>
--- {itme}---
<button onClick={() => dellist(index)}>删除</button>
</li>
)
}
{!list.length && "暂无代办事项"}
</ul>
</div>
);
}
export default App;
useEffect
案例: 定时器
import React, { useEffect, useState } from 'react'
const A = () => {
const [T, setT] = useState(1)
useEffect(() => {
const interval = setInterval(() => getCurrentTime(), 1000) // 定时器
return () => {
clearInterval(interval) // 销毁
}
}, [T])
//定时器的方法
const getCurrentTime = () => {
setT(T + 1)
}
const chongZhi = () => {
setT(0)
}
return (
<div >
<h1>
{T}
</h1>
<button onClick={chongZhi}>重置</button>
</div>
)
}
export default A
useRef
需要获取另一个标签或者组件的属性信息时使用
案例:点击按钮 盒子变色
import React, { useRef } from 'react';
const App = () => {
//创建 REF
const divRef = useRef()
const myStyle = {
backgroundColor: 'red',
width: '100px',
height: '100px',
position: 'fixed',
left: 200,
top: 200
}
const bianLan = () => {
divRef.current.style.backgroundColor = 'blue'
}
const bianHong = () => {
divRef.current.style.backgroundColor = 'red'
}
return (
<div>
<button onClick={bianLan}>变蓝色</button>
<button onClick={bianHong}>变红色</button>
{/* 设置 引用指向 */}
<div ref={divRef} style={myStyle}></div>
</div>
);
}
export default App
事件
事件的详细说明
https://www.runoob.com/jsref/dom-obj-event.html
键盘事件
keypress (键盘点击 按下并且弹起)
keydown (键盘按下)
keyup (键盘弹起)
键盘事件详细说明 https://www.runoob.com/jsref/dom-obj-event.html
键盘事件的对象属性
//按下的键值 字符串 式
window.event.key
//按下的键值 数值 式
window.event.keyCode
//按下的键值 数值 式(区分大小写) 只能在keypress 模式下
window.event.charCode
案例 : 键盘事件
import React, { Component } from 'react'
class A extends Component {
//添加全局事件
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown)
}
// 销毁
componentWillUnmount() {
document.removeEventListener('keydown', this.onKeyDown)
}
//按键触发函数 直接获取到事件对象 window.event
onKeyDown = (e) => {
console.log(e)
if (e.key === "1") {
console.log("按下了1键")
}
}
render() {
return (
<div >
</div >
);
}
}
export default A;
案例 :函数式 键盘事件
import React, { useEffect } from 'react';
const A = () => {
useEffect(() => {
window.addEventListener('keydown', onKeyDown); // 添加全局事件
return () => {
window.removeEventListener('keydown', onKeyDown); // 销毁
};
}, [])
// 键盘事件
const onKeyDown = (e) => {
console.log(e)
}
return (
<div >
</div>
)
}
export default A
鼠标事件
click (鼠标点击 按下并且弹起)
mousemove(鼠标移动)
mousedown(鼠标按下)
mouseup(鼠标弹起)
mouseover (鼠标移到猛哥元素上)
mouseout(鼠标移开)
…
更多鼠标事件https://www.runoob.com/jsref/dom-obj-event.html
鼠标事件的对象属性
鼠标可组合键盘快捷键
// win 键
window.event.metaKey
// shift 键
window.event.shiftKey
// alt 键
window.event.altKey
// ctl 键
window.event.ctrlKey
获取数据
// 鼠标按下的是哪个键 1 左键 2右键 4中键
window.event.buttons
//点击 位置的 坐标(相对浏览器)
window.event.clientX
//点击 位置的 坐标(对象屏幕)
window.event.screenX
//点击到的标签的坐标
window.event.offsetX
获取点击目标
//本次事件作用的 目标标签
window.event.target
案例 : 全局 鼠标点击
import React, { Component } from 'react'
class A extends Component {
//添加全局事件
componentDidMount() {
document.addEventListener('click', this.onKeyDown)
}
// 销毁
componentWillUnmount() {
document.removeEventListener('click', this.onKeyDown)
}
//按键触发函数
onKeyDown = (e) => {
console.log(e.x, e.y)
}
render() {
return (
<div >
</div >
);
}
}
export default A;
案例: 鼠标移动 并获取 坐标
import React, { useState, useEffect } from 'react'
const A = () => {
const [my_x, setx] = useState(0)
const [my_y, sety] = useState(0)
const myStyle = {
position: 'absolute',
left: my_x,
top: my_y,
backgroundColor: 'red'
}
useEffect(() => {
const interval = window.addEventListener('mousemove', handleMoveMouse)
return () => {
clearInterval(interval) // 销毁
}
}, [])
const handleMoveMouse = (e) => {
setx(e.x)
sety(e.y)
}
return (
<div>
<div style={myStyle}>盒子 </div>
</div>
);
}
export default A;
案例:鼠标拖尾
import React, { Component } from 'react';
class App extends Component {
state = {
list: [
[101, 0],
[102, 100],
[103, 200],
[104, 200],
[105, 300],
[106, 400],
[107, 500],
[108, 600],
[109, 700]]
}
myStyle = {
position: 'absolute',
backgroundColor: 'red'
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMoveMouse)
}
// 销毁
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMoveMouse)
}
handleMoveMouse = (e) => {
let b = [...this.state.list]
b[0] = [e.x, e.y]
for (var i = b.length - 1; i > 0; i--) {
b[i] = b[i - 1]
}
this.setState({ list: b })
}
render() {
return (
<div>{
this.state.list.map(
item =>
<div style={{ ...this.myStyle, left: item[0], top: item[1] }}>
盒子
</div>
)
}
</div>
);
}
}
export default App;
案例:点击 变红移动
import React, { useEffect } from 'react'
const App2 = () => {
const myStyle = {
backgroundColor: 'blue',
width: '100px',
height: '100px',
position: 'fixed',
left: 200,
top: 200
}
useEffect(() => {
//添加 鼠标点击 监听事件 执行XXX函数
window.addEventListener("click", xxx)
return () => {
//删除 鼠标点击 监听事件 和 XXX函数的调用
window.removeEventListener("click", xxx)
}
}, [])
const xxx = (e) => {
//排除无ID的标签
if (e.target.id) {
e.target.style.backgroundColor = 'red'
e.target.style.left = 0
}
}
return (
<div >
<div id="1" style={{ ...myStyle, top: 400 }}>
</div>
<div id="2" style={myStyle} >
</div>
</div>
)
}
export default App2;
案例:全局鼠标拖拽
import React, { Component } from 'react';
class App extends Component {
// 状态
state = {
status: false,
dy: 0,
dx: 0,
id: "",
}
// 定义公共样式
myStyle = {
backgroundColor: 'red',
width: '100px',
height: '100px',
position: 'fixed',
left: 200,
top: 200
}
// 开启事件监听
componentDidMount() {
window.addEventListener('mousedown', this.onMouseDown)
window.addEventListener('mousemove', this.onMouseMove)
window.addEventListener('mouseup', this.onMouseUp)
}
// 销毁
componentWillUnmount() {
window.removeEventListener('mousedown', this.onMouseDown)
window.removeEventListener('mousemove', this.onMouseMove)
window.removeEventListener('mouseup', this.onMouseUp)
}
// 开启跟随 保存 点击位置的坐标偏移值
onMouseDown = (e) => {
if (e.target.id === "") { return }
console.log("点击到了ID为 ", e.target.id, " 的东西")
this.setState({
// e.offsetX === e.clientY - e.target.offsetTop
// 也就是鼠标 在标签内部的坐标(偏移)
dx: e.offsetX,
dy: e.offsetY,
status: true,
id: e.target.id
})
}
// 跟随 鼠标
onMouseMove = (e) => {
if (this.state.status) {
// 坐标数据 偏移值修正
var ma_x = e.clientX - this.state.dx
var ma_y = e.clientY - this.state.dy
// 坐标数据 限制范围在浏览器中 innerWidth innerHeight 屏幕宽高
if (ma_x < 0) { ma_x = 0 }
if (ma_x > window.innerWidth - e.target.offsetWidth) {
ma_x = window.innerWidth - e.target.offsetWidth
}
if (ma_y < 0) { ma_y = 0 }
if (ma_y > window.innerHeight - e.target.offsetHeight) {
ma_y = window.innerHeight - e.target.offsetHeight
}
// 坐标数据 传递给样式
e.target.style.top = `${ma_y}px`
e.target.style.left = `${ma_x}px`
}
}
// 关闭跟随
onMouseUp = () => {
this.setState({
status: false,
})
}
render() {
return (
<div>
<div>
<div id='1' style={this.myStyle}>
</div>
<div id='2' style={{ ...this.myStyle, top: "0px", backgroundColor: "blue" }}>
</div>
<div id='3' style={{ ...this.myStyle, left: "0px", backgroundColor: "green" }}>
</div>
</div>
</div>
);
}
}
export default App;
案例:鼠标 吸附拖拽
import React, { useState } from 'react'
const C = () => {
const [ID, setID] = useState("xxx")
const dr = {
width: '100px',
height: '150px',
margin: '15px',
padding: '10px',
border: '1px solid #aaaaaa',
}
//所以想让一个元素可放置,需要重写 ondragover
const dragover = (e) => {
e.preventDefault()
}
//有一个对象 dataTransfer 可以用来存储拖拽数据
const start = (e) => {
setID(e.target.id)
}
//在 ondrop 获取到这个值 利用ID吧 被拖动标签加入列表 把被拖拽元素的 id 存入 e.dataTransfer
const ondrop = (e) => {
e.preventDefault()
e.target.append(document.getElementById(ID))
}
return (
<div>
<div onDrop={ondrop} onDragOver={dragover} style={dr}>
<p onDragStart={start} draggable="true" id="tuoDong1" style={{ background: "red" }}>
拖动
</p>
</div>
<div onDrop={ondrop} onDragOver={dragover} style={dr}>
<p onDragStart={start} draggable="true" id="tuoDong2" style={{ background: "blue" }}>
拖动
</p>
</div>
<div onDrop={ondrop} onDragOver={dragover} style={dr}>
<p onDragStart={start} draggable="true" id="tuoDong3" style={{ background: "green" }}>
拖动
</p>
</div>
</div>
);
}
export default C;
触摸事件
案例:触摸 拖拽
import React, { useState } from 'react'
const App = () => {
const [dxy, setDxy] = useState({
status: false,
dy: 0,
dx: 0,
})
const myStyle = {
backgroundColor: 'red',
width: '100px',
height: '100px',
position: 'fixed',
left: 200,
top: 200
}
//开启跟随 保存 点击位置的坐标偏移值
const Down = (e) => {
setDxy({
dy: e.touches[0].clientY - e.target.offsetTop,
dx: e.touches[0].clientX - e.target.offsetLeft,
status: true,
})
}
//跟随 (利用偏移值修正)
const Move = (e) => {
if (dxy.status) {
// ${xxx} 把大括号中的内容转换为 字符串
e.target.style.top = `${e.touches[0].clientY - dxy.dy}px`
e.target.style.left = `${e.touches[0].clientX - dxy.dx}px`
}
}
//关闭跟随
const Up = () => {
setDxy({
status: false,
})
}
return (
<div >
<div
style={myStyle}
onTouchStart={Down}
onTouchMove={Move}
onTouchEnd={Up}>
</div>
</div>
)
}
export default App;
计时器
案例: 计时器 自动创建DIV
import React, { useEffect, useState } from 'react';
const App2 = () => {
const [List, setList] = useState([])
const [T, setT] = useState(new Date().toLocaleString());
useEffect(() => {
//设置定时器 每1000毫秒 执行一次函数
const interval = setInterval(myadd, 1000)
return () => {
// 销毁 定时器
clearInterval(interval)
}
}, [T])
//添加列表项
const myadd = () => {
let newlist = [...List]
newlist.push({
ID: Math.random(),
V: T,
ax: false,
})
setList(newlist)
setT(new Date().toLocaleString())
}
//根据列表 创建DIV
const makeDiv = () => {
return (List.map(item =>
<div id={item.id}>现在的时间是 : {item.V}</div>
))
}
return (
<div>
{makeDiv()}
</div>
);
}
export default App2;
案例:手动控制的计时器 类
import React, { Component } from 'react'
class App extends Component {
state = { a: 0 }
timer = undefined
record = () => {
this.setState({ a: this.state.a + 1 })
}
// 开启计时器 先关闭计时器 防止开启多个
timerStart = () => {
clearInterval(this.timer)
this.timer = setInterval(this.record, 1000)
}
// 关闭计时器
timerStop = () => {
clearInterval(this.timer)
}
// 重置计时器
timerCZ = () => {
clearInterval(this.timer)
this.setState({ a: 0 })
}
render() {
return (
<div>
<div>
<button onClick={this.timerStart}>开始计时</button>
<button onClick={this.timerStop}>停止计时</button>
<button onClick={this.timerCZ}>重置</button>
<div>
<h1>计时器:{this.state.a}</h1>
</div>
</div>
</div>
)
}
}
export default App;
案例:手动控制的计时器 函数
import React, { useState, } from 'react'
let timer = undefined
const App = () => {
const [ST, setST] = useState(0)
//计时器 调用的函数
const record = () => {
//需要调用 e 更新数据 setST 本质是一个回调函数
setST(e => e + 1)
}
//先关闭计时器 再开启计时器
const timerStart = () => {
clearInterval(timer)
timer = setInterval(record, 100)
}
//关闭 计时器
const timerStop = () => {
clearInterval(timer)
}
//重置 计时器
const timerCZ = () => {
clearInterval(timer)
setST(0)
}
return (
<div>
<div>
<button onClick={timerStart}>开始计时</button>
<button onClick={timerStop}>停止计时</button>
<button onClick={timerCZ}>重置</button>
<div>
<h1>计时器: {ST}</h1>
</div>
</div>
</div>
);
}
export default App
案例:手动控制盒子移动 (无状态)
import React, { useRef } from 'react'
//初始化
let a = 0
let timer = undefined
let myStyle = {
backgroundColor: 'red',
width: '100px',
height: '100px',
position: 'fixed',
left: '0px',
top: '500px'
}
const App = () => {
const h1Ref = useRef()
const record = () => {
h1Ref.current.style.left = `${a}px`
a += 1
}
const timerStart = () => {
clearInterval(timer)
timer = setInterval(record, 10)
}
const timerStop = () => {
clearInterval(timer)
}
const timerCZ = () => {
clearInterval(timer)
a = 0
h1Ref.current.style.left = `0px`
}
return (
<div>
<button onClick={timerStart}>开始</button>
<button onClick={timerStop}>停止</button>
<button onClick={timerCZ}>重置</button>
<div ref={h1Ref} style={myStyle}></div>
</div>
)
}
export default App;
一次 计时器
myVar = setTimeout(function(){ alert("Hello"); }, 3000);
// 清理 一次 计时器
clearTimeout(myVar);
事件对象的属性和方法
https://www.runoob.com/jsref/dom-obj-event.html
目标对象(target)的 属性
console.log("高:", e.target.offsetHeight)
console.log("宽:", e.target.offsetWidth)
console.log("X:", e.target.offsetLeft)
console.log("Y:", e.target.offsetTop)
请求 数据
类组件中使用的方法
axios 请求数据
安装库
npm i axios
使用
ComponentDidMount(){
axios(this.baseUrl)
.then(res => {
const { goodlists
} = res.data;
this.setState({
list: goodlists
})
})
.catch(err => {
console.log(err)
})
}
fetch 请求数据 推荐
ComponentDidMount(){
fetch(this.baseUrl)
.then(res => res.json())
.then((result) => {
console.log(result)
const { goodlists } = result
this.setState({
list: goodlists
})
},
(error) => {
console.log(error)
}
)
}
request 请求数据
安装库
npm install -s request
npm install -s request-promise
使用
ComponentDidMount(){
rp(this.baseUrl)
.then(res => {
const { goodlists } = JSON.parse(res)
this.setState({
list: goodlists
})
})
.catch(error => {
console.log(error)
})
}
路由
安装路由
npm install react-router-dom@5
基本用法 ( /#/a)
import React from 'react';
import { Redirect } from 'react-router-dom';
import { HashRouter, Route, Switch } from 'react-router-dom'
import a from "./a"
import b from "./b"
import c from "./c"
import notfand from "./notfand"
const Luyou = () => {
return (
<div>
<HashRouter>
<Switch>
{/* 自上而下顺序 一个个匹配 */}
<Route path="/a" component={a} />
<Route path="/b" component={b} />
<Route path="/c" component={c} />
<Redirect from='/' to="/a" exact />
<Route component={notfand} />
</Switch>
</HashRouter>
</div>
);
}
export default Luyou;
重定向 Redirect (默认模糊匹配) 加属性 exact 精确匹配
<Redirect from='/' to="/a" exact/>
按钮绑定定向跳转页面函数
import { Button, Row, Col } from 'antd'
import React from "react"
import { WindowsFilled, AppleFilled, AndroidFilled } from '@ant-design/icons'
const Daohang = () => {
// 跳转函数 编程式
const link = () => {
window.location.href = "#/c"
}
return (
<div>
<Row justify="space-evenly">
<Col span={3} align="center" >
{/* a 标签方式 跳转 */}
<a href="#/a"><Button type="primary" icon={<WindowsFilled />} >一</Button></a>
</Col>
<Col span={3} align="center" >
<a href="#/b"> <Button type="primary" icon={<AppleFilled />} >二</Button></a>
</Col>
<Col span={4} align="center" >
<Button type="primary" icon={<AndroidFilled />} onClick={link}>三</Button>
</Col>
</Row>
</div>
);
}
export default Daohang;
音频 / 视频
音频
https://www.runoob.com/tags/tag-audio.html
视频
https://www.runoob.com/tags/tag-video.html
const audio = this.audio.current;
// 属性
audio.paused // 是否暂停 - 用来判断当前播放状态 渲染按钮组件
audio.duration // 歌曲时长 - 用来渲染进度条 READ ONlY
audio.currentTime // 当前时间 - 用来渲染进度条 改变播放进度
audio.volume // 音量 - 用于控制音量
// 方法
audio.play() // 播放
audio.pause() // 暂停
// 事件
audio.onpause = () => {} // 暂停触发
audio.onplay = () => {} // 播放触发
audio.onended = () => {} // 结束触发 - 用于自动播放下一首
audio.ontimeupdate = () => {} // 请特别注意这个方法:每250ms会调用一次,因为currentTime每250ms更新一次
案例:播放器
import React, { Component, createRef } from 'react';
import fly from './aaa.mp3'
// 音视频播放器
class App2 extends Component {
audioRef = createRef()
// 开始
audioPlay = () => {
this.audioRef.current.play()
}
aa = () => {
console.log(this.audioRef.current.volume)
}
//暂停
audioPause = () => {
this.audioRef.current.pause()
}
//停止
audioStop = () => {
this.audioRef.current.pause()
this.audioRef.current.currentTime = 0
}
//重新播放
audioRestart = () => {
this.audioRef.current.currentTime = 0
this.audioRef.current.play()
}
// 音量 +
volumeAdd = () => {
if (this.audioRef.current.volume >= 1) { return }
this.audioRef.current.volume += 0.1
console.log(this.audioRef.current.volume)
}
// 音量 -
volumeReduce = () => {
if (this.audioRef.current.volume <= 0.1) { return }
this.audioRef.current.volume -= 0.1
console.log(this.audioRef.current.volume)
}
render() {
return (
<div>
{/* src 音频地址 controls 显示界面*/}
<audio ref={this.audioRef} src={fly} controls></audio>
<button onClick={this.audioPlay}>运行</button>
<button onClick={this.audioPause}>暂停</button>
<button onClick={this.audioPause}>停止</button>
<button onClick={this.audioRestart}>重新播放</button>
<div>
<button onClick={this.volumeAdd}>+</button>
<button onClick={this.volumeReduce}>--</button>
</div>
<button onClick={this.aa}>查看数据</button>
</div>
);
}
}
export default App2;
教程
react 教程
react 全家桶 https://www.bilibili.com/video/BV1dP4y1c7qd?p=1
https://www.bilibili.com/video/BV1wy4y1D7JT?p=37
https://www.bilibili.com/video/BV1KS4y1h7jY?spm_id_from=333.337.search-card.all.click
JavaScript 教程
千锋教育JS全套教程500集_JavaScript零基础入门必备_Js核心技术精讲
https://www.bilibili.com/video/BV11h411U7Sh?p=130&spm_id_from=pageDriver
千锋教育JavaScript全套教程,10天JS零基础入门到精通(强烈推荐)
https://www.bilibili.com/video/BV1pJ41157z8?spm_id_from=333.999.0.0
vscode 及其插件
ESLint 代码检查插件
JS JSX Snippets
自动重命名标签Auto Rename Tag
不同的括号换上了不同的颜色 Bracket Pair Colorizer2
检查单词拼写是否错误(支持英语)Code Spell Checker
VSCODE通用插件+vue插件+react插件(2022版本)https://blog.csdn.net/happy81997/article/details/122995888
综合练习
打砖块
import React, { Component } from 'react';
class App extends Component {
dr = {
width: '400px',
height: '600px',
margin: '15px',
padding: '10px',
position: 'absolute ',
border: '2px solid #aaaaaa',
top: '50px',
}
dd = {
position: 'absolute',
right: '0px',
width: '300px',
}
dr2 = {
width: '50px',
height: '50px',
position: 'absolute ',
backgroundColor: 'red',
borderRadius: '50%',
bottom: '100px',
}
fangKuai = {
width: '60px',
height: '20px',
margin: '2px',
border: '2px solid green',
float: 'left',
}
state = {
x: 150
}
v = 0
timer = undefined
// 开始 使用计时器更新数据
timerStart = () => {
clearInterval(this.timer)
this.timer = setInterval(() => this.setState({ x: this.state.x + this.v }), 5)
}
// 结束 关闭计时器
timerStop = () => {
clearInterval(this.timer)
}
moveStart = (e) => {
// console.log(e)
if (e.key === "ArrowRight") { this.v = 2 }
if (e.key === "ArrowLeft") { this.v = -2 }
}
moveStop = () => {
this.v = 0
}
componentDidMount() {
document.addEventListener('keydown', this.moveStart)
document.addEventListener('keyup', this.moveStop)
}
componentWillUnmount() {
document.removeEventListener('keydown', this.moveStart)
document.addEventListener('keyup', this.moveStop)
}
render() {
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div>
{/* 按钮 */}
<button onClick={this.timerStart} style={{ margin: '25px' }}>开始</button>
<button onClick={this.timerStop} style={{ margin: '25px' }}>停止</button>
</div>
<div style={this.dr}>
{/* 小球 */}
<div style={{ ...this.dr2, left: `${this.state.x}px` }}></div>
{/* 方块 */}
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
<div style={this.fangKuai}></div>
</div>
</div>
);
}
}
export default App;
触摸 打砖块
import React, { Component, createRef } from 'react';
// 数据中心
let DATA = {
// 小球的移动速度
bobble_v: [10, 10],
// 板子的移动速度 初始值
block_v: [0, 0],
// 板子的速度 控制 增加值
control_v2: 10,
//帧速率 每秒刷新率
FPS: 60,
}
export default class App extends Component {
chuangKou = {
width: '400px',
height: '800px',
margin: '15px',
padding: '10px',
position: 'absolute ',
border: '2px solid #aaaaaa',
top: '100px',
}
banZiRef = createRef()
xiaoQiuRef = createRef()
pengZhuangRef = createRef()
boxGroupRef = createRef()
W = parseFloat(this.chuangKou.width)
H = parseFloat(this.chuangKou.height)
timer = undefined
// 定义计数器 启动主时间序列
yunXing = () => {
// 板子 => 运行
this.banZiRef.current.move(this.W)
// 小球 => 运行
this.xiaoQiuRef.current.move(this.H, this.W)
// 碰撞检测 => 运行
//碰撞体和被配状态 需要有状态state = { x: 0, y:, 0 h: 0, w: 0 } 和 一个ref
this.pengZhuangRef.current.obj_polygonCollision_PASV(this.xiaoQiuRef.current, this.banZiRef.current)
// 方块组 小球 碰撞检测 => 运行
let Obj = {
x: this.xiaoQiuRef.current.state.x,
y: this.xiaoQiuRef.current.state.y,
w: this.xiaoQiuRef.current.state.w,
h: this.xiaoQiuRef.current.state.h,
}
this.boxGroupRef.current.boxGroup_Collision_PASV(Obj)
}
// 开启计时器
timerStart = () => {
console.log("时间序列 启动 FPS:25")
clearInterval(this.timer)
this.timer = setInterval((this.yunXing), 1000 / DATA.FPS)
}
// 关闭计时器
timerStop = () => {
console.log("时间序列 关闭")
clearInterval(this.timer)
}
// 组件渲染
render() {
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<StartStop
start={this.timerStart}
stop={this.timerStop}
/>
<PengZhuang ref={this.pengZhuangRef} />
<div style={this.chuangKou}>
<BoxGroup ref={this.boxGroupRef} />
<XiaoQiu ref={this.xiaoQiuRef} />
<BanZi ref={this.banZiRef} />
<KongZhi />
</div>
</div>
);
}
}
/* ##################################################################################*/
//碰撞检测 函数
class PengZhuang extends Component {
activate = true
obj_polygonCollision_PASV = (obj, PASV) => {
// 点 坐标转换
let point = {
bottom: [obj.state.x + obj.state.w / 2, obj.state.y + obj.state.h],
top: [obj.state.x + obj.state.w / 2, obj.state.y],
left: [obj.state.x, obj.state.y + obj.state.h / 2],
right: [obj.state.x + obj.state.w / 2, obj.state.y + obj.state.h / 2],
}
// 多边形 坐标转换
let obj_point = {
a: [PASV.state.x, PASV.state.y],
b: [PASV.state.x + PASV.state.w, PASV.state.y],
c: [PASV.state.x + PASV.state.w, PASV.state.y + PASV.state.h],
d: [PASV.state.x, PASV.state.y + PASV.state.h],
}
// 碰撞位置 回调函数 改变速度
if (this.activate) {
// 上下 方向 进入 被动体
if (this.point_is_in(point.bottom, obj_point) || this.point_is_in(point.top, obj_point)) {
DATA.bobble_v[1] *= -1
this.activate = false
setTimeout(this.delay, 300)
}
// 左_右方向 进入 被动体
else if (this.point_is_in(point.left, obj_point) || this.point_is_in(point.right, obj_point)) {
DATA.bobble_v[0] *= -1
this.activate = false
setTimeout(this.delay, 300)
}
}
}
delay = () => { this.activate = true }
//点 是否进入 被动体
point_is_in = (point, PASV) => {
if (PASV.a[1] < point[1] && point[1] < PASV.c[1] && PASV.a[0] < point[0] && point[0] < PASV.c[0]) {
return true
}
return false
}
render() {
return (
<div>
</div>
);
}
}
// 开始结束按钮
const StartStop = (e) => {
const startStkle = {
margin: '25px',
// backgroundColor: "red"
}
return (
<div >
{/* 按钮 */}
<button onClick={e.start} style={startStkle}>开始</button>
<button onClick={e.stop} style={startStkle}>停止</button>
</div>
);
}
//控制按钮
class KongZhi extends Component {
kongZhi = {
margin: 'auto',
backgroundColor: "red",
width: '100px',
height: '100px',
position: 'absolute ',
bottom: '0px',
borderRadius: '50%',
opacity: ' 0.5',
display: 'block',
textAlign: 'center',
padding: '40px 0',
}
// 左 按钮
zuo_anXia = () => {
DATA.block_v[0] = -DATA.control_v2
}
// 右 按钮
you_anXia = () => {
DATA.block_v[0] = DATA.control_v2
}
// 弹起 按钮
tanQi = () => {
DATA.block_v[0] = 0
}
render() {
return (
<div>
<div
style={{ ...this.kongZhi, left: 0 }}
onTouchStart={this.zuo_anXia}
onTouchEnd={this.tanQi}
>左
</div>
<div
style={{ ...this.kongZhi, right: 0 }}
onTouchStart={this.you_anXia}
onTouchEnd={this.tanQi}
>右
</div>
</div>
);
}
}
// 板子
class BanZi extends Component {
state = {
x: 150,
y: 680,
h: 20,
w: 100,
}
banZi = {
width: `${this.state.w}px`,
height: `${this.state.h}px`,
position: 'absolute ',
backgroundColor: 'blue',
top: `${this.state.y}px`,
}
div_1 = createRef()
move = (W) => {
// 判断板子 是否碰到边缘
let maxW = W - parseFloat(this.banZi.width)
if (this.state.x < 0) {
this.setState({ x: 0 })
}
else if (this.state.x > maxW) {
this.setState({ x: maxW })
}
// 刷新 状态
this.setState({ x: this.state.x + DATA.block_v[0] })
}
render() {
return (
<div>
<div
ref={this.div_1}
style={{
...this.banZi,
left: this.state.x
}}>
</div>
</div>
);
}
}
// 小球
class XiaoQiu extends Component {
state = {
x: 200,
y: 400,
h: 50,
w: 50,
}
xiaoQiu = {
width: `${this.state.w}px`,
height: `${this.state.h}px`,
position: 'absolute ',
backgroundColor: 'red',
borderRadius: '50%',
}
// 判断 是否碰到边缘 后移动
move = (H, W) => {
let maxH = H - parseFloat(this.xiaoQiu.width)
let maxW = W - parseFloat(this.xiaoQiu.height)
// console.log("小球出了 左 边界")
if (this.state.x < 0) {
DATA.bobble_v[0] *= -1
this.setState({ x: 0 })
// console.log("小球出了 右 边界")
} else if (this.state.x > maxW) {
DATA.bobble_v[0] *= -1
this.setState({ x: maxW })
// console.log("小球出了 上 边界")
} else if (this.state.y < 0) {
DATA.bobble_v[1] *= -1
this.setState({ y: 0 })
// console.log("小球出了 下 边界")
} else if (this.state.y > maxH) {
DATA.bobble_v[1] *= -1
this.setState({ y: maxH })
// 移动 计算
} else {
this.setState({
x: this.state.x + DATA.bobble_v[0],
y: this.state.y + DATA.bobble_v[1],
})
}
}
render() {
return (
<div>
<div style={{
...this.xiaoQiu,
left: this.state.x,
top: this.state.y,
}}></div>
</div>
);
}
}
// 方块
class Box extends Component {
state = {
x: this.props.attribute.x,
y: this.props.attribute.y,
w: this.props.attribute.w,
h: this.props.attribute.h,
c: this.props.attribute.c,
}
fangKuai = {
margin: '2px',
border: '2px solid green',
position: 'absolute ',
backgroundColor: 'green',
}
render() {
return (
<div>
<div style={{
...this.fangKuai,
left: `${this.state.x}px`,
top: `${this.state.y}px`,
width: `${this.state.w}px`,
height: `${this.state.h}px`,
backgroundColor: this.state.c,
}} ></div>
</div>
);
}
}
// 方块 组
class BoxGroup extends Component {
constructor(props) {
// 必须在这里通过super调用父类的constructor
super(props)
this.state = { a: 0 }
this.arr = []
this.activate = true
this.init_arr()
}
// 初始化 数组
init_arr() {
let sy = 0
let sw = 60
let sh = 20
let sc = 'green'
for (var i = 0; i < 5; i++) {
let sx = 0
for (var j = 0; j < 6; j++) {
this.arr.push({ x: sx, y: sy, w: sw, h: sh, c: sc })
sx += 66
}
sy += 23
}
}
//组 碰撞计算
boxGroup_Collision_PASV = (obj) => {
for (let i in this.arr) {
// 碰撞计算
this.Collision_PASV(this.arr[i], obj, i)
}
}
// 单物体 碰撞计算
Collision_PASV = (box, obj, index) => {
// 是否 允许计算
if (!this.activate) { return }
// 如果 没有碰到 就是 碰到了
if (obj.x + obj.w < box.x || obj.x > box.x + box.w || obj.y + obj.h < box.y || obj.y > box.y + box.h) {
} else {
// 改变 数据中心的 小球速度
DATA.bobble_v[1] *= -1
// 改变 数组
// this.arr[index].c = 'red'
console.log(index)
// 停止 ??毫秒后 允许
this.activate = false
setTimeout(() => this.activate = true, 10)
}
}
render() {
return (
<div >
{
this.arr.map(
(item, index) => (
<Box attribute={item} key={index} />
)
)
}
</div>
);
}
}
临时文件
import React, { Component, createRef } from 'react';
// 主窗口
export default class App extends Component {
chuangKou = {
width: '400px',
height: '800px',
margin: '15px',
padding: '10px',
position: 'absolute ',
border: '2px solid #aaaaaa',
top: '100px',
}
// boardRef = createRef()
controlRef = createRef()
W = parseFloat(this.chuangKou.width)
H = parseFloat(this.chuangKou.height)
FPS = 60
// 定义计数器 启动主时间序列
yunXing = () => {
// 板子 => 运行
// this.boardRef.current.move(this.W, this.controlRef.current.state.speed)
}
// 开启计时器
timerStart = () => {
console.log("时间序列 启动 FPS:25",)
clearInterval(this.timer)
this.timer = setInterval((this.yunXing), 1000 / this.FPS)
}
// 关闭计时器
timerStop = () => {
console.log("时间序列 关闭")
clearInterval(this.timer)
}
// 组件渲染
render() {
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<StartStop start={this.timerStart} stop={this.timerStop} />
<div style={this.chuangKou}>
<Board />
<KongZhi ref={this.controlRef} />
</div>
</div>
);
}
}
// 开始结束按钮
const StartStop = (e) => {
const startStkle = {
margin: '25px',
}
return (
<div >
{/* 按钮 */}
<button onClick={e.start} style={startStkle}>开始</button>
<button onClick={e.stop} style={startStkle}>停止</button>
</div>
);
}
//控制按钮
class KongZhi extends Component {
state = {
speed: 0
}
kongZhi = {
margin: 'auto',
backgroundColor: "red",
width: '100px',
height: '100px',
position: 'absolute ',
bottom: '0px',
borderRadius: '50%',
opacity: ' 0.5',
display: 'block',
textAlign: 'center',
padding: '40px 0',
}
// 左 按钮
zuo_anXia = () => {
this.setState({
speed: -2
})
}
// 右 按钮
you_anXia = () => {
this.setState({
speed: 2
})
}
// 弹起 按钮
tanQi = () => {
this.setState({
speed: 0
})
}
render() {
return (
<div>
<div
style={{ ...this.kongZhi, left: 0 }}
onTouchStart={this.zuo_anXia}
onTouchEnd={this.tanQi}
>左
</div>
<div
style={{ ...this.kongZhi, right: 0 }}
onTouchStart={this.you_anXia}
onTouchEnd={this.tanQi}
>右
</div>
</div>
);
}
}
// 板子
class Board extends Component {
state = {
x: 0,
y: 0,
h: 20,
w: 100,
v: [0, 0],
}
board = {
width: `${this.state.w}px`,
height: `${this.state.h}px`,
position: 'absolute',
backgroundColor: 'blue',
top: `${this.state.y}px`,
}
// 运行 更新
move = (W, speed) => {
// // 判断板子 是否碰到边缘
// let maxW = W - this.state.w
// if (this.state.x < 0) {
// this.setState({ x: 0 })
// }
// else if (this.state.x > maxW) {
// this.setState({ x: maxW })
// }
// //跟新 状态
// this.setState({
// x: this.state.x + this.state.v[0],
// v: [speed[0], this.state.v[1]],
// })
}
render() {
return (
<div>
<div
style={{
...this.banZi,
left: this.state.x
}}>
</div>
</div>
);
}
}
快捷键
React快捷键(in VScode)
1,imr :Import React
2,imrc:Import React / Component
3,imrs:Import React / useState
4,imrse:Import React / useState useEffect
5,cc:Class Component
6,ccc:Class Component With Constructor
7,sfc:Stateless Function Component
8,cdm:componentDidMount
9,uef:useEffect Hook
10,cwm:componentWillMount
11,scu:shouldComponentUpdate
12,cwu:componentWillUpdate
13,cdu:componentDidUpdate
14,usf:Declare a new state variable using State Hook
15,clg:console.log()
16,rcredux:create redux
17,rconst:create constructor
18,rcc:react的类组件生成
颜色吸取
https://www.fontke.com/tool/pickrgb/