当前位置: 首页 > news >正文

猫眼电影字体破解(图片转码方法)

问题

        随便拿一篇电影做样例。我们发现猫眼的页面数据在预览窗口中全是小方框。在当我们拿到源码以后,数据全是加密后的。所以我们需要想办法破解加密,拿到数据。

破解过程 

        1.源码获取问题与破解

        分析

        在我们刚刚请求url的时候是可以得到数据的,但是过了一段时间后就无法获得数据。虽然状态码为200,但是却没有返回页面源码

一般这种应该是和时间戳有关系,在查看请求负载的时候我们发送,浏览器向这个url不仅发送了时间戳还有一个signKey的密钥。时间戳可以很容易得到,主要问题是如何获得signKey。

        全局搜索signKey,我们发现一段js代码,它的返回值就是我们请求负载的内容。所以需要想办法还原这段js代码。

        分析后发现:

  • d:获取当前时间的函数
  • r:随机数取整
  • c:内容如下method=GET&timeStamp=1725264890773&User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0&index=8&channelId=40011&sVersion=1
    • 可以发现就是多个信息进行拼接(时间戳+User-Agent+index+channelId+sVersion)。
  • f:固定为&key=A013F70DB97834C0A5492378BD76C53A

        分析图片如下:

        同时我们还发现signKey是通过MD5加密(c+f)后得到的。因为1经过MD5加密后得到的内容就是c4ca4238a0b923820dcc509a6f75849b,所以我们可以猜测(0,a[i(_0x140e("0xe4"))])('c+f')就是一个MD5的加密。

         js编写与调用

        有了以上分析后,我们就可以拿页面原始的js代码进行适当的改动。修改后的js代码如下,我们直接返回网页负载需要的params。

        添加首页cookie

        在完成上面步骤后,我们调用js,虽然得到了params,但是还是无法获得到页面的源代码,这可能和cookie有关系,所以我们创建一个session,通过访问首页来保存首页的cookie,然后再来访问这个url看看结果。

        我们发现浏览器请求了两次https://www.maoyan.com/,且第一次存在302跳转,跳转到https://www.maoyan.com/,所以是请求了两次。在python代码中,我们只需要请求有302跳转的链接即可,因为程序会自动进行第二次跳转。

        添加cookie后,使用python程序调用js代码返回params,使用js生成的params去访问url地址运行结果如下:

        2.字体破解

        字体图片下载

        在拿到页面源码以后,我们需要对数字进行获取。直接在返回的源码中搜索,获取.woff文件。得到url://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/e3dfe524.woff,因为每一次请求得到的源码中,woff文件的链接都不同,所以我们需要使用数据提取手段,提取每一次请求得到的woff文件链接并下载保存下来。

        下载并保存woff文件,使用python代码识别woff文件,并保存为图片,识别代码如下,之后会整合到源码中:

from fontTools.ttLib import TTFont
from reportlab.graphics.shapes import Drawing, Path, Group
from reportlab.graphics import renderPM
from reportlab.lib import colors
from reportlab.graphics.shapes import Pathclass ReportLabPen(BasePen):def __init__(self, glyphSet, path=None):BasePen.__init__(self, glyphSet)if path is None:path = Path()self.path = pathdef _moveTo(self, p):(x, y) = pself.path.moveTo(x, y)def _lineTo(self, p):(x, y) = pself.path.lineTo(x, y)def _curveToOne(self, p1, p2, p3):(x1, y1) = p1(x2, y2) = p2(x3, y3) = p3self.path.curveTo(x1, y1, x2, y2, x3, y3)def closePath(self):self.path.closePath()def ttfToImage(fontName, imagePath, fmt="png"):font = TTFont(fontName)  # 打开 WOFF 字体文件gs = font.getGlyphSet()glyphNames = font.getGlyphNames()[1:]  # 排除第一个 .notdef 字形for i in glyphNames:g = gs[i]  # 获取当前字形的 Glyph 对象pen = ReportLabPen(gs, Path(fillcolor=colors.red, strokeWidth=1))  # 创建 ReportLabPen 对象,并设置相关参数g.draw(pen)  # 将当前字形通过 pen 绘制到 path 对象上# 字形的宽度和高度w, h = g.width, g.width + 300  g = Group(pen.path)g.translate(0, 100)  # 将图形向下移动 100 个像素d = Drawing(w, h)  # 创建 Drawing 对象,设置宽度和高度d.add(g)  # 将 Group 对象添加到 Drawing 对象中# 定义输出图片路径和文件名imageFile = f"{imagePath}/{i}.{fmt}"# 将 Drawing 对象渲染成图像文件并保存renderPM.drawToFile(d, imageFile, fmt)# 示例用法:将 `mao.woff` 字体文件的字形保存为图像
ttfToImage(fontName="mao.woff", imagePath='images')

        识别结果如下:

         识别图片

        识别代码如下,之后会整合到源码中:

import os
import ddddocr  # 导入 ddddocr 库def orc():# 创建一个 ddddocr 的 OCR 对象ocr = ddddocr.DdddOcr()dicts = {}  # 初始化一个空字典,用于存储识别结果lists = os.listdir('./images')  # 获取 images 目录下的所有文件列表# 遍历每个图片文件for imgs in lists:# 以二进制模式读取图片文件with open('./images/' + imgs, 'rb') as f:img_bytes = f.read()# 使用 OCR 对象的 classification 方法识别图片内容res = ocr.classification(img_bytes)# 输出文件名中提取的 Unicode 代码print(222222222222222222, imgs[3:-4])try:# 将文件名中的 Unicode 代码转换为字符,并将识别结果存入字典dicts[eval('u\'\\u' + imgs[3:-4].lower() + '\'')] = resexcept:# 如果转换或存储过程中出错,则跳过pass# 打印当前的字典内容print(dicts)# 调用 orc 函数
orc()

        字典输出结果如下:

字典替换

        拿到页面加密的源码,然后根据字典的key来替换掉对应的数字

        替换后的数字与原始页面一样

源码

        py文件

import requests
import execjs
import re
import shutil
import os
import ddddocr
from fontTools.pens.basePen import BasePen
from fontTools.ttLib import TTFont
from reportlab.graphics.shapes import Drawing, Path, Group
from reportlab.graphics import renderPM
from reportlab.lib import colors
from reportlab.graphics.shapes import Pathclass ReportLabPen(BasePen):def __init__(self, glyphSet, path=None):BasePen.__init__(self, glyphSet)if path is None:path = Path()self.path = pathdef _moveTo(self, p):(x, y) = pself.path.moveTo(x, y)def _lineTo(self, p):(x, y) = pself.path.lineTo(x, y)def _curveToOne(self, p1, p2, p3):(x1, y1) = p1(x2, y2) = p2(x3, y3) = p3self.path.curveTo(x1, y1, x2, y2, x3, y3)def closePath(self):self.path.closePath()def ttfToImage(fontName, imagePath, fmt="png"):font = TTFont(fontName)  # 打开 WOFF 字体文件gs = font.getGlyphSet()glyphNames = font.getGlyphNames()[1:]  # 排除第一个 .notdef 字形for i in glyphNames:g = gs[i]  # 获取当前字形的 Glyph 对象pen = ReportLabPen(gs, Path(fillcolor=colors.red, strokeWidth=1))  # 创建 ReportLabPen 对象,并设置相关参数g.draw(pen)  # 将当前字形通过 pen 绘制到 path 对象上# 字形的宽度和高度w, h = g.width, g.width + 300g = Group(pen.path)g.translate(0, 100)  # 将图形向下移动 100 个像素d = Drawing(w, h)  # 创建 Drawing 对象,设置宽度和高度d.add(g)  # 将 Group 对象添加到 Drawing 对象中# 定义输出图片路径和文件名imageFile = f"{imagePath}/{i}.{fmt}"# 将 Drawing 对象渲染成图像文件并保存renderPM.drawToFile(d, imageFile, fmt)def download_woff():with open('猫眼.js','r',encoding='utf-8') as f:ctx = execjs.compile(f.read())headers_home = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6","Cache-Control": "max-age=0","Connection": "keep-alive","Sec-Fetch-Dest": "document","Sec-Fetch-Mode": "navigate","Sec-Fetch-Site": "none","Sec-Fetch-User": "?1","Upgrade-Insecure-Requests": "1","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0","sec-ch-ua": "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Microsoft Edge\";v=\"128\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\""}cookies_home = {"_lxsdk_s": "191b2c23b90-602-526-0ba%7C%7C1"}url = "https://www.maoyan.com/"s = requests.session()# 访问首页,保存cookier = s.get(url, headers=headers_home, cookies=cookies_home)headers = {"Accept": "*/*","Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6","Connection": "keep-alive","Referer": "https://www.maoyan.com/films/1464004","Sec-Fetch-Dest": "empty","Sec-Fetch-Mode": "cors","Sec-Fetch-Site": "same-origin","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0","X-Requested-With": "XMLHttpRequest","sec-ch-ua": "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Microsoft Edge\";v=\"128\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\""}url = "https://www.maoyan.com/ajax/films/1464004"params = ctx.call("get_params")response = s.get(url, headers=headers, params=params).text# 保存woffwoff_url = "https:" + re.findall(r',url.*?woff', response)[0].split('"')[1]woff_res = s.get(woff_url).contentwith open('mao.woff', 'wb') as f:f.write(woff_res)f.close()result = re.findall('<span class="stonefont">(.*?)</span>', response)return resultdef clear_folder(folder_path):# 确保指定路径是一个文件夹if os.path.isdir(folder_path):# 遍历文件夹中的所有文件和子文件夹for filename in os.listdir(folder_path):file_path = os.path.join(folder_path, filename)try:# 如果是文件则删除if os.path.isfile(file_path) or os.path.islink(file_path):os.unlink(file_path)# 如果是文件夹则删除整个文件夹elif os.path.isdir(file_path):shutil.rmtree(file_path)except Exception as e:print(f"删除 {file_path} 时出错: {e}")print("删除完成")def orc():# 创建一个 ddddocr 的 OCR 对象ocr = ddddocr.DdddOcr()dicts = {}  # 初始化一个空字典,用于存储识别结果lists = os.listdir('./images')  # 获取 images 目录下的所有文件列表# 遍历每个图片文件for imgs in lists:# 以二进制模式读取图片文件with open('./images/' + imgs, 'rb') as f:img_bytes = f.read()# 使用 OCR 对象的 classification 方法识别图片内容res = ocr.classification(img_bytes)# 输出文件名中提取的 Unicode 代码print(222222222222222222, imgs[3:-4])try:# 将文件名中的 Unicode 代码转换为字符,并将识别结果存入字典dicts[eval('u\'\\u' + imgs[3:-4].lower() + '\'')] = resexcept:# 如果转换或存储过程中出错,则跳过pass# 返回字典内容return dictsif __name__ == '__main__':data = download_woff()# 指定要清空的文件夹路径folder_path = './images'clear_folder(folder_path)# 转换 TTF 字体并将字形转换为 PNG 图片ttfToImage(fontName="mao.woff", imagePath='images')# 使用ocr识别图片,返回字典res = orc()print(data)print(res)# 遍历字典并将识别结果输出for i in data:# 首先去掉所有的 &#x 和 ;cleaned_str = i.replace('&#x', '').replace(';', '')# 然后进行字符替换for key, value in res.items():cleaned_str = cleaned_str.replace(key.encode('unicode_escape').decode('ascii').replace('\\u', ''), value)print(cleaned_str)

        js文件

const CryptoJS = require('crypto-js')var r = Math["ceil"](10 * Math["random"]())
var d = (new Date)["getTime"]()
var c = "method=GET&timeStamp="+d+'&User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0&index='+r+'&channelId=40011&sVersion=1'
var f = "&key=A013F70DB97834C0A5492378BD76C53A"function get_params(){return{"timeStamp": d,"index": r,"signKey": CryptoJS.MD5(c+f).toString(),"channelId": "40011","sVersion": "1","webdriver": "false"}
}

相关文章:

猫眼电影字体破解(图片转码方法)

问题 随便拿一篇电影做样例。我们发现猫眼的页面数据在预览窗口中全是小方框。在当我们拿到源码以后&#xff0c;数据全是加密后的。所以我们需要想办法破解加密&#xff0c;拿到数据。 破解过程 1.源码获取问题与破解 分析 在我们刚刚请求url的时候是可以得到数据的&#xff…...

flink wordcount

Maven配置pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…...

组合模式(Composite Pattern)

使用组合模式&#xff08;Composite Pattern&#xff09;是一个更优雅的方式来表示菜单和菜单项。组合模式允许我们将单个对象&#xff08;如菜单项&#xff09;和组合对象&#xff08;如菜单&#xff09;以相同的方式处理。 解决方案&#xff1a; 创建组合结构&#xff1a;我…...

教你制作一本加密的样本册

在这个信息的时代&#xff0c;保护自己的隐私和知识产权变得尤为重要。你有没有想过&#xff0c;如何将自己珍贵的样本资料变成一本只有自己才能查看的加密宝典&#xff1f;今天&#xff0c;我就来教你制作一本加密的样本册 第一步&#xff0c;打开浏览器&#xff0c;搜索FLBOO…...

C语言进阶【1】--字符函数和字符串函数【1】

本章概述 字符分类函数字符转换函数strlen的使用和模拟实现strcpy的使用和模拟实现strcat的使用和模拟实现strcmp的使用和模拟实现彩蛋时刻&#xff01;&#xff01;&#xff01; 字符分类函数 字符&#xff1a; 这个概念&#xff0c;我们在以前的文章中讲过了。我们键盘输入的…...

git提交自动带上 Signed-off-by信息

为了确保在使用 Signed-off-by 签名的同时保留你的提交消息&#xff0c;你需要修改 prepare-commit-msg 钩子脚本&#xff0c;以便它不会丢失原始的提交信息。 增加prepare-commit-msg 钩子以保留提交消息 prepare-commit-msg 钩子的目的是在提交信息文件中插入额外的内容&am…...

图论(2)

一、度 度统计的是一个节点上又多少条边 度出度入度 出度&#xff1a;统计以该节点为起始点箭头指向外面的边的条数 入度&#xff1a;统计箭头指向该节点的边数 度为1的节点为悬挂节点&#xff0c;边为悬挂边 用矩阵计算节点的度 二、握手定理 比如这里第一个集合里面有三…...

ASP.NET Core 入门教学十九 依赖注入ioc

ASP.NET Core内置了对依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;的支持&#xff0c;这是一种设计模式&#xff0c;用于实现控制反转&#xff08;Inversion of Control&#xff0c;简称IoC&#xff09;&#xff0c;从而使得应用程序组件之间的耦合…...

omm kill 内存碎片化

内存频繁 OOM(Out of Memory)会导致内存碎片化,并进一步加剧无可用内存分配的问题。碎片化是内存管理中常见的问题,当系统频繁分配和释放内存时,内存空间会被分割成许多小块,虽然内存总量可能足够,但这些小块无法满足较大进程或数据的内存需求,最终导致系统无法找到足够…...

JS中给元素添加事件监听器的各种方法详解(包含比较和应用场景)

JavaScript 中给元素添加事件监听器的各种方法详解 在 JavaScript 中&#xff0c;事件处理是前端开发的一个重要部分。无论是点击按钮、提交表单&#xff0c;还是鼠标悬停&#xff0c;都涉及到事件监听。本文中&#xff0c;我将详细讲解各种给元素添加事件监听器的方法&#x…...

Python基本数据类型之复数complex

来源&#xff1a; “码农不会写诗”公众号 链接&#xff1a;Python基本数据类型之复数complex 文章目录 01 基本概念02 基本运算03 拓展1复数与向量 复数complex Python基本数据之复数(complex)即包含实部和虚部的数字。 01 基本概念 即包含实部和虚部的数字。 在Python中&am…...

第六届机器人与智能制造技术国际会议 (ISRIMT 2024)

目录 会议详情 主题 会议官网 会议详情 第六届机器人与智能制造技术国际研讨会&#xff08;ISRIMT 2024&#xff09;计划于2024年9月20-22日在常州举行。会议主要聚焦“机器人”和“智能制造技术”的研究领域&#xff0c;旨在为机器人和智能制造技术领域的专家学者、工程技术…...

鸿蒙轻内核M核源码分析系列十九 Musl LibC

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核M核源码分析系列一 数据结构-双向循环链表 轻内核M核源码分析系列二 数据结构-任务就绪队列 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表 轻…...

mysqldump备份恢复数据库

mysqldump程序可以用来备份和恢复数据库 ,默认情况mysqldump会创建drop table, create table,和insert into的sql语句. 语法 > mysqldump [options] db_name [tbl_name ...] > mysqldump [options] --databases db_name ... > mysqldump [options] --all-databases备…...

路径规划——RRT算法

路径规划——RRT算法 算法原理 RRT算法的全称是快速扩展随机树算法(Rapidly Exploring Random Tree)&#xff0c;它的思想是选取一个初始点作为根节点&#xff0c;通过随机采样&#xff0c;增加叶子节点的方式&#xff0c;生成一个随机扩展树&#xff0c;当随机树中的叶子节点…...

OPCUA-PLC

下载opcua服务器(有PLC可以直连),UaAnsiCServer下载路径 双击运行如下,Endpoint显示opcua服务路径 opc.tcp://DESKTOP-9SD7K4B:48020 下载opcua客户端(类似编写代码连接操作),UaExpert下载路径 如果连接失败,有一个授权认证,点击同意就行 java代码实现连接opcUA操作 pom.…...

在Windows系统上部署PPTist并实现远程访问

在Windows系统上部署PPTist并实现远程访问 前言PPTist简介本地部署PPTist步骤1&#xff1a;获取PPTist步骤2&#xff1a;安装依赖步骤3&#xff1a;运行PPTist 使用PPTist远程访问PPTist步骤1&#xff1a;安装Cpolar步骤2&#xff1a;配置公网地址步骤3&#xff1a;配置固定公网…...

【Grafana】Prometheus结合Grafana打造智能监控可视化平台

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

隐私计算实训营:SplitRec:当拆分学习遇上推荐系统

拆分学习的概念 拆分学习的核心思想是拆分网络结构。每一个参与方拥有模型结构的一部分&#xff0c;所有参与方的模型合在一起形成一个完整的模型。训练过程中&#xff0c;不同参与方只对本地模型进行正向或者反向传播计算&#xff0c;并将计算结果传递给下一个参与方。多个参…...

存在nginx版本信息泄露(请求头中存在nginx中间件版本信息)

在Nginx的配置文件中&#xff0c;server_tokens指令用于控制Nginx在HTTP响应头中包含的服务器版本信息&#xff0c;默认为true&#xff0c;开启状态。当设置为off时&#xff0c;Nginx将不会在响应头中包含任何服务器版本信息&#xff0c;仅显示“Server: nginx”这一行&#xf…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...