下载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 查看版本号
CMD 到工程目录下 利用脚手架 创建
create-react-app myapp # 项目名不能有大写
src 目录下
index.js (必须叫index.js 否者静态目录寻找不到)
所有 其他 文件可以删除
npm start
生成的文件结果及作用
|-- README.mad 使用说明
|-- node_modules 所有的依赖文件
|-- package-lock.json 锁定安装时的包版本号,保证团队一直
|-- package.json
|-- public 静态公共目录
|-- src 开发用的源代码目录
其他电脑配置相同环境可以复制除 node_modules 意外的文件
用一下命令重建环境
npm i
npm run build
npm install serve -g
serve build
报错信息:无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统中禁止执行脚本
原因分析:禁止执行脚本,那就打开权限执行脚本嘛
解决方案:
build 文件下 static 放入 Django的static
其他文件 放入 Django 的templates 文件夹夏
正常调用index.html
npm install bootstrap --save
在index.js引入Bootstrap
import 'bootstrap/dist/css/bootstrap.min.css'
//循环遍历
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
}
// 第一i中写法
{
arr.map((item, index) => {
return {item}
})
}
// 第二种写法
var str = arr.map((item, index) => {
return {item}
})
ReactDOM.render(
{str}
,
document.getElementById("root2")
)
// 第三种写法
var str=[];
for(let i=0;i{arr[i]}
// 用法一
arr.forEach((item, index) => {
......
})
// 用法二
arr.forEach((item, index) => {
return {item}
})
1.map函数返回一个新的数组,在map的回调函数里,迭代每一项的时候也必须有返回值。
2.forEach 没有返回值。
map方法处理数据之后会返回一个新的数组,同时不会改变原数组的值;
如果数组为空则无法进行遍历,所以要对数组做非空校验。
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)
索引 (下表为1的位置开始 ) 追加 元素
a.splice(1,0,'大大')
索引 (下表为e的位置开始 ) 删除 1个元素
a.splice(e,1)
合并字符串 (默认以 , 分隔)
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 (
);
}
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 (var i in info){
i // name/age i的值就是对象(字典)的key(键值)
x = info[i] //获取值
}
https://www.runoob.com/jsref/jsref-obj-math.html
function aaaa(){
...
}
aaa()
//返回 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()
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/")
}
const info = () => {
alert(window.location)
}
location 的属性和方法…
window.onload = function () {
alert("页面完成")
}
//导入 React 核心包 解释jsx语法
import React from "react"
// 导入 React虚拟DOM 把组件渲染到页面
import ReactDOM from "react-dom"
//利用 js 的document 操作选择 ID 为root的标签 在它的列表中添加
ReactDOM.render(
利用ReactDOM渲染HTML标签
,
document.getElementById("root")
)
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()
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 (
内部文件写法
);
}
}
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(内容) - 盒子的内容,显示文本和图像
https://www.runoob.com/css/css-margin.html
https://www.runoob.com/css/css-border.html
https://www.runoob.com/css/css-padding.html
盒模型详细:https://www.runoob.com/css/css-boxmodel.html
菜鸟教程 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(
// 可以单标签 也可以双标签
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 (
函数组件返回的信息
)
}
//实例化 组件
export default App
vscode 快速创建react 函数组件 rfc
import React from "react"
//箭头函数
const Bpp = () => 箭头函数送来的信息~~~~~
//导出 箭头函数
export default Bpp
自定义标签只能嵌套在 函数或者类组件定义中
import React from "react"
//箭头函数1
const Bpp1 = () => 箭头函数1送来的信息~~~~~
//箭头函数2
const Bpp2 = () => 箭头函数送2来的信息~~~~~
//箭头函数3 桥套自定义函数
const App = () =>
//导出 组件 App
export default App
使用 this.props.
children
定义插槽
import React, { Component } from 'react'
class App2 extends Component {
render() {
return (
);
}
}
export default App2
class A extends Component {
render() {
return (
这个是第一个子组件
{this.props.children}
{/* 多个插槽最少需要两个标签的使用*/}
{/*
{this.props.children[0]}
{this.props.children[1]}
{this.props.children[1]}
*/}
);
}
}
class B extends Component {
render() {
return (
第二个组件放在了插槽中
);
}
}
import React from "react"
const name = '吴博文'
const age = 10
const App = () =>
{/* 字符串运算 */}
{"年龄是:" + 10}
{/* 字符串加变量 */}
{"名字是:" + name}
{/* 数字运算 */}
{20 + 10}
{/* 数字和變量运算 */}
{age + 10}
{/* 三目运算符 */}
{10 > 20 ? "对" : "错"}
//导出 组件 App
export default App
import React from "react"
import '../css/a.css'
// 导入css 模块
定义样式变量 属性名必须改成小驼峰写法
var a = {
background: 'red',
fontSize: '50px'
}
//定义组件
const App = () =>
这个组件使用的是内联样式(React官方推荐)
这个组件使用了行内样式(React官方推荐)
这个组件使用外联样式
//导出 组件 App
export default App
a.css
.a {
background-color: rgb(149, 149, 186);
font-size: 50px;
}
单个字符串
demo
div>
多个字符串 推荐
<div className={`content ${this.state.isActive?"active":null}`}>
demo
div>
其他写法: 数组转化
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 (
{/* 点击 执行箭头函数 调用实例化对象的 add_1 (可以传递参数) */}
{/* e 获取对象(button对象本身) 传递进 函数内部 */}
);
}
}
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 (
{/* 绑定 ref对象 到 标签 */}
);
}
}
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 (
{/* 设置 引用指向 */}
);
}
}
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 (
{/* 新建一个按钮 并且绑定触发事件 */}
)
}
}
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 (
{/* 输入框数据更新 */}
this.mychange(event)} type="text" value={this.state.value} />
{/* 点击 触发函数 添加标签*/}
{/* 判断列表是否为空 */}
{this.state.list.length === 0 ? "列表空了~~~~" : ""}
{/* map循环遍历 */}
{this.state.list.map((item, index) =>
{/* 选择框 状态更新 */}
this.boxchange(index)} type="checkbox" checked={item.ax} />
{/* 状态 控制 行内样式 */}
{item.V}
{/* 点击 触发喊出 删除标签 */}
)}
);
}
}
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 (
this.sc(e)}>页面一
this.sc(e)}>页面二
this.sc(e)}>页面三
{this.state.a === '1' && }
{this.state.a === '2' && }
{this.state.a === '3' && }
);
}
}
export default App;
富文本展示 (解析HTML代码)
渲染
条件渲染
案例:同不同意
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 同意
} else {
return 不同意
}
}
render() {
return (
{this.abc()}
);
}
}
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 同意
} else {
return 不同意
}
}
}
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 (
{this.state.act ? "同意" : "不同意"}
);
}
}
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 (
{this.state.act && "不同意"}
{!this.state.act && "同意"}
);
}
}
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 (
{this.state.list.map((item, index) =>
{/* 遍历 输出内容 */}
{item.name}
{item.age}
{/* 点击 触发回调函数 传入下标 */}
)}
);
}
}
export default App2;
属性
属性的作用主要是接收数据
获取属性列表 this.props
app.js
import React, { Component } from 'react';
import App01 from './app01'
class App extends Component {
render() {
return (
{/* 设置属性 和属性值 */}
);
}
}
export default App;
app01.js
import React, { Component } from 'react';
class App01 extends Component {
render() {
return (
{/* 打印属性列表中的 某个属性的值 */}
{this.props.biaoQian}
);
}
}
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 (
{/* 打印属性列表中的 某个属性的值 */}
{this.props.biaoQian}
);
}
}
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 (
{/* 绑定 事件函数 */}
{/* 调用子组件*/}
);
}
}
export default App
// ####### 可以分割成另一文件#############################
class App01 extends Component {
x_style = {
height: "700px",
width: "500px",
margin: '15px',
padding: '10px',
border: '5px solid red',
}
render() {
return (
{/* 打印属性列表中的 某个属性的值 */}
这个框是子函数部分:
{this.props.shuJu}
);
}
}
父子组件通信
使用属性 传递数据 和 函数
import React, { Component } from 'react'
class App extends Component {
state = {
a: false
}
kaiGuan = () => {
this.setState({ a: !this.state.a })
}
render() {
return (
);
}
}
export default App
// ####### 可以分割成另一文件#############################
class App1 extends Component {
render() {
return (
{/* 利用属性 执行 函数 */}
{/* 历史属性 获取 数据 */}
{this.props.xx ? "子组件显示事件" : ""}
);
}
}
通过 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 (
)
}
}
监听 并使用
// 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 (
{this.state.A}
)
}
}
类方式 状态中心
// 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 (
)
}
}
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 (
{number}
);
}
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 (
请输入带办事项
{
list.map((itme, index) =>
-
--- {itme}---
)
}
{!list.length && "暂无代办事项"}
);
}
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 (
{T}
)
}
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 (
{/* 设置 引用指向 */}
);
}
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 (
);
}
}
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 (
)
}
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 (
);
}
}
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 (
盒子
);
}
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 (
{
this.state.list.map(
item =>
盒子
)
}
);
}
}
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 (
)
}
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 (
);
}
}
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 (
拖动
拖动
拖动
);
}
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 (
)
}
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 =>
现在的时间是 : {item.V}
))
}
return (
{makeDiv()}
);
}
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 (
计时器:{this.state.a}
)
}
}
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 (
计时器: {ST}
);
}
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 (
)
}
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 (
{/* 自上而下顺序 一个个匹配 */}
);
}
export default Luyou;
重定向 Redirect (默认模糊匹配) 加属性 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 (
);
}
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 (
{/* src 音频地址 controls 显示界面*/}
);
}
}
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 (
{/* 按钮 */}
{/* 小球 */}
{/* 方块 */}
);
}
}
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 (
);
}
}
/* ##################################################################################*/
//碰撞检测 函数
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 (
);
}
}
// 开始结束按钮
const StartStop = (e) => {
const startStkle = {
margin: '25px',
// backgroundColor: "red"
}
return (
{/* 按钮 */}
);
}
//控制按钮
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 (
左
右
);
}
}
// 板子
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 (
);
}
}
// 小球
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 (
);
}
}
// 方块
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 (
);
}
}
// 方块 组
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 (
{
this.arr.map(
(item, index) => (
)
)
}
);
}
}
临时文件
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 (
);
}
}
// 开始结束按钮
const StartStop = (e) => {
const startStkle = {
margin: '25px',
}
return (
{/* 按钮 */}
);
}
//控制按钮
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 (
左
右
);
}
}
// 板子
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 (
);
}
}
快捷键
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/
底部