JavaScript+react笔记

开始一个工程

安装 脚手架 及工具

下载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’ 不是内部或外部命令,也不是可运行的程序 或批处理文件

  1. 卸载 npm uninstall yarn -g

  2. 安装 npm install yarn (最好不要用别的安装命令,会没效果)

  3. 添加环境变量:系统变量path添加 C:\Users\bokeyuan\node_modules\yarn\bin

  4. 重新打开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,因为在此系统中禁止执行脚本

原因分析:禁止执行脚本,那就打开权限执行脚本嘛

解决方案:

  1. 打开 powerShell 用管理员身份运行 (Win + X)
  2. 输入命令: set-ExecutionPolicy RemoteSigned
  3. 输入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:relativeposition: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/

底部

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值