名词(术语)了解--SSR/CSR

名词(术语)了解–SSR/CSR

什么是服务器端渲染(SSR)?

服务器端渲染是指由服务器生成完整的 HTML 页面,然后发送给客户端的过程。

这与客户端渲染(CSR)形成对比,后者主要依赖浏览器端的 JavaScript 来渲染页面内容。
在这里插入图片描述

客户端 服务器 数据库 1. 发送页面请求 2. 获取必要数据 3. 返回数据 4. 执行React/Vue组件代码 5. 生成HTML 6. 返回完整HTML 7. 显示内容 8. 加载JS 9. 激活(Hydration) 客户端 服务器 数据库

详情

  1. 客户端发送页面请求

    • 用户访问网站 URL
    • 浏览器向服务器发送 HTTP 请求
  2. 服务器请求数据

    // 服务器端代码
    async function fetchData() {const data = await db.query('SELECT * FROM posts');return data;
    }
    
  3. 数据库返回数据

    // 数据示例
    const data = {posts: [{ id: 1, title: '文章1' },{ id: 2, title: '文章2' }]
    };
    
  4. 服务器执行组件代码

    // React 组件
    function App({ data }) {return (<div>{data.posts.map(post => (<article key={post.id}><h2>{post.title}</h2></article>))}</div>);
    }
    
  5. 生成 HTML

    // 服务器端渲染
    const html = ReactDOMServer.renderToString(<App data={data} />
    );
    
  6. 返回完整 HTML

    <!DOCTYPE html>
    <html><head><title>SSR App</title></head><body><div id="root">${html}</div><script>window.__INITIAL_STATE__ = ${JSON.stringify(data)}</script><script src="/client.js"></script></body>
    </html>
    
  7. 客户端显示内容

    • 浏览器接收到完整的 HTML
    • 用户立即看到页面内容
    • 无需等待 JavaScript 加载
  8. 加载 JavaScript

    // 客户端 JavaScript
    const initialState = window.__INITIAL_STATE__;
    
  9. Hydration 过程

    // 客户端 hydration
    ReactDOM.hydrate(<App data={initialState} />,document.getElementById('root')
    );
    

SSR 的主要优点:

  1. 更快的首屏加载

    • 用户立即看到完整内容
    • 无需等待 JavaScript 下载和执行
  2. 更好的 SEO

    • 搜索引擎可以直接爬取完整的 HTML 内容
    • 有利于网站的搜索引擎排名
  3. 更好的性能

    • 减少客户端计算负担
    • 适合低性能设备
  4. 更好的用户体验

    • 无空白页面等待
    • 更快的内容可见时间

SSR 的挑战:

  1. 服务器负载

    • 需要更多服务器资源
    • 需要合理的缓存策略
  2. 开发复杂性

    • 需要同构代码(服务端和客户端都能运行)
    • 需要处理服务端特有的问题
  3. 部署要求

    • 需要 Node.js 环境
    • 需要更复杂的部署配置

适用场景:

  • 内容展示型网站
  • 需要 SEO 的网站
  • 首屏加载速度要求高的应用
  • 面向低端设备用户的应用

框架支持:

  • Next.js (React)
  • Nuxt.js (Vue)
  • SvelteKit (Svelte)
  • Remix (React)

什么是客户端渲染(CSR)?

在这里插入图片描述

浏览器 服务器 React应用 API服务器 1. 请求页面 2. 返回空HTML和JS包 3. 加载JS包 4. 初始化React应用 5. 组件挂载 6. 发起API请求 7. 返回数据 8. 更新状态 9. 渲染内容 10. 页面可交互 浏览器 服务器 React应用 API服务器

CSR(客户端渲染)的工作流程说明:

  1. 初始请求

    • 用户在浏览器中输入URL或点击链接
    • 浏览器向服务器发送页面请求
  2. 服务器响应

    • 服务器返回一个基本的空HTML文件
    • HTML文件中包含必要的JS包引用(React应用代码)
  3. 加载过程

    • 浏览器下载JS包
    • 这个阶段用户看到的是空白页面或加载指示器
  4. 应用初始化

    • JS包加载完成后,React应用开始初始化
    • 创建虚拟DOM和应用状态
  5. 组件挂载

    • React组件树开始挂载
    • 初始化组件生命周期
  6. 数据获取

    • 组件挂载后发起API请求
    • 向后端服务器请求需要的数据
  7. 数据响应

    • API服务器返回请求的数据
    • 数据以JSON格式传输
  8. 状态更新

    • React组件接收到数据
    • 更新组件状态(setState)
  9. 内容渲染

    • React根据新状态重新渲染组件
    • 更新实际DOM
  10. 完成显示

    • 用户最终看到完整的页面内容
    • 页面可以交互

    详情:

    1. 浏览器请求页面

      • 用户访问网站 URL
      • 浏览器向服务器发送 HTTP 请求
    2. 服务器响应

      • 返回基础 HTML 文件(通常只包含一个 root div)
      • 返回打包后的 JS 文件(包含 React 应用代码)
      <!DOCTYPE html>
      <html><head><title>React App</title></head><body><div id="root"></div><script src="/static/js/bundle.js"></script></body>
      </html>
      
    3. JS 包加载

      • 浏览器下载 JavaScript 文件
      • 解析并执行 JavaScript 代码
      • 此时用户看到空白页面
    4. React 初始化

      ReactDOM.createRoot(document.getElementById('root')
      ).render(<App />);
      
    5. 组件挂载

      function App() {useEffect(() => {// 组件挂载后执行}, []);return <div>Loading...</div>;
      }
      
    6. 数据请求

      const [data, setData] = useState(null);useEffect(() => {fetch('/api/data').then(res => res.json()).then(data => setData(data));
      }, []);
      
    7. 接收数据

      {"status": "success","data": {"items": [...]}
      }
      
    8. 更新状态

      setData(receivedData);
      
    9. 渲染内容

      return (<div>{data ? (<DataDisplay data={data} />) : (<Loading />)}</div>
      );
      
    10. 页面可交互

      • 用户可以看到完整内容
      • 可以进行点击、输入等交互操作

    CSR 的关键特点:

    1. 首次加载时需要下载完整的 JavaScript 包
    2. 所有页面路由和视图转换都在客户端处理
    3. 数据获取和页面更新都是异步进行的
    4. 适合构建单页应用(SPA)
    5. 需要考虑首屏加载优化:
      • 代码分割(Code Splitting)
      • 懒加载(Lazy Loading)
      • 预加载(Preloading)
      • 合理的缓存策略

CSR的优缺点:

优点:

  • 前后端完全分离
  • 用户体验好,切换页面快
  • 减轻服务器压力
  • 客户端缓存友好

缺点:

  • 首屏加载较慢
  • SEO不友好
  • 对JavaScript依赖性强
  • 在低性能设备上体验欠佳

适用场景:

  • 后台管理系统
  • 交互密集型应用
  • 实时数据展示
  • 不需要SEO的应用

不适用场景:

  • 需要良好SEO的网站
  • 首屏加载速度要求极高的页面
  • 低端设备用户较多的应用

SSR的主要特点

  1. 渲染过程

    • 在服务器端完成页面的渲染
    • 生成完整的HTML文档
    • 客户端接收到的是完整的页面内容
  2. 性能特征

    • 更快的首屏加载时间
    • 更好的SEO表现
    • 较高的服务器资源消耗
  3. 适用场景

    • 内容密集型网站
    • 需要良好SEO的网站
    • 首屏加载速度要求高的应用

常见SSR框架

  1. Next.js

    • React生态系统中最流行的SSR框架
    • 提供了自动静态优化
    • 支持增量静态生成(ISR)
  2. Nuxt.js

    • Vue.js的SSR框架
    • 提供自动路由配置
    • 支持静态站点生成
  3. Angular Universal

    • Angular的SSR解决方案
    • 支持预渲染
    • 提供服务器端API

使用建议

  1. 何时使用SSR

    • 网站需要优秀的SEO表现
    • 用户期望快速的首屏加载
    • 网站内容频繁更新
    • 网站有大量动态内容
  2. 何时避免使用SSR

    • 应用交互性很强
    • 服务器资源有限
    • 内容更新频率低
    • 主要面向已登录用户
  3. 性能优化建议

    • 实施缓存策略
    • 使用CDN
    • 合理配置服务器资源
    • 优化数据获取逻辑

SSR场景示例

1. 博客文章页面 (Next.js)

这是一个典型的内容展示场景,非常适合使用SSR:

id: blog-ssr
name: Blog Post with SSR
type: tsx
content: |-// pages/posts/[id].tsximport React from 'react'import { GetServerSideProps } from 'next'interface Post {id: numbertitle: stringcontent: stringauthor: stringpublishDate: string}interface BlogPostProps {post: Post}export const getServerSideProps: GetServerSideProps = async ({ params }) => {// 在服务器端获取文章数据const res = await fetch(`https://api.example.com/posts/${params?.id}`)const post = await res.json()return {props: {post}}}const BlogPost: React.FC<BlogPostProps> = ({ post }) => {return (<div className="max-w-3xl mx-auto p-6"><h1 className="text-3xl font-bold mb-4">{post.title}</h1><div className="text-gray-600 mb-4"><span>作者:{post.author}</span><span className="ml-4">发布时间:{post.publishDate}</span></div><div className="prose">{post.content}</div></div>)}export default BlogPost

2. 电商产品列表 (Next.js)

电商场景需要良好的SEO和快速的首屏加载:

id: ecommerce-ssr
name: E-commerce Product List
type: tsx
content: |-// pages/products.tsximport React from 'react'import { GetServerSideProps } from 'next'import { Select } from "@/components/ui/select"interface Product {id: numbername: stringprice: numberdescription: stringimage: string}interface ProductsPageProps {products: Product[]categories: string[]}export const getServerSideProps: GetServerSideProps = async ({ query }) => {// 获取分类和筛选条件const category = query.category || 'all'const sort = query.sort || 'default'// 在服务器端获取商品数据const productsRes = await fetch(`https://api.example.com/products?category=${category}&sort=${sort}`)const products = await productsRes.json()// 获取分类列表const categoriesRes = await fetch('https://api.example.com/categories')const categories = await categoriesRes.json()return {props: {products,categories}}}const ProductsPage: React.FC<ProductsPageProps> = ({ products, categories }) => {return (<div className="container mx-auto p-6"><div className="flex justify-between mb-6"><h1 className="text-2xl font-bold">商品列表</h1><Select className="w-48">{categories.map(category => (<option key={category} value={category}>{category}</option>))}</Select></div><div className="grid grid-cols-1 md:grid-cols-3 gap-6">{products.map(product => (<div key={product.id} className="border rounded-lg p-4"><img src={product.image} alt={product.name}className="w-full h-48 object-cover mb-4"/><h2 className="text-xl font-semibold">{product.name}</h2><p className="text-gray-600">{product.description}</p><div className="mt-4 flex justify-between items-center"><span className="text-xl text-red-600">¥{product.price}</span><button className="bg-blue-500 text-white px-4 py-2 rounded">加入购物车</button></div></div>))}</div></div>)}export default ProductsPage

3. 新闻门户首页 (Nuxt.js)

新闻网站需要实时性和SEO,很适合SSR:

id: news-ssr
name: News Portal
type: tsx
content: |-// pages/index.vue<template><div class="container mx-auto p-6"><header class="mb-8"><h1 class="text-4xl font-bold mb-4">今日头条</h1><div class="flex gap-4"><button v-for="category in categories" :key="category"class="px-4 py-2 rounded-full":class="selectedCategory === category ? 'bg-blue-500 text-white' : 'bg-gray-200'"@click="selectCategory(category)">{{ category }}</button></div></header><main><div class="grid grid-cols-1 md:grid-cols-2 gap-6"><article v-for="news in newsList" :key="news.id"class="border rounded-lg overflow-hidden"><img :src="news.image" :alt="news.title" class="w-full h-48 object-cover"><div class="p-4"><h2 class="text-xl font-bold mb-2">{{ news.title }}</h2><p class="text-gray-600 mb-4">{{ news.summary }}</p><div class="flex justify-between items-center text-sm text-gray-500"><span>{{ news.source }}</span><span>{{ news.publishTime }}</span></div></div></article></div></main></div></template><script>export default {async asyncData({ $axios }) {const [categories, newsList] = await Promise.all([$axios.$get('https://api.example.com/categories'),$axios.$get('https://api.example.com/news')])return {categories,newsList,selectedCategory: 'all'}},methods: {async selectCategory(category) {this.selectedCategory = categorythis.newsList = await this.$axios.$get(`https://api.example.com/news?category=${category}`)}},head() {return {title: '新闻门户 - 今日头条',meta: [{hid: 'description',name: 'description',content: '最新、最热门的新闻资讯'}]}}}</script>

4. 仪表盘页面 (混合渲染)

对于仪表盘这类应用,我们可以使用混合渲染策略:

id: dashboard-ssr
name: Dashboard with Hybrid Rendering
type: tsx
content: |-// pages/dashboard.tsximport React, { useEffect, useState } from 'react'import { GetServerSideProps } from 'next'import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts'interface DashboardData {summary: {totalUsers: numberactiveUsers: numberrevenue: number}historicalData: {date: stringusers: numberrevenue: number}[]}interface DashboardProps {initialData: DashboardData}export const getServerSideProps: GetServerSideProps = async () => {// 获取初始数据const res = await fetch('https://api.example.com/dashboard/initial')const initialData = await res.json()return {props: {initialData}}}const Dashboard: React.FC<DashboardProps> = ({ initialData }) => {const [realtimeData, setRealtimeData] = useState(null)useEffect(() => {// 客户端连接WebSocket获取实时数据const ws = new WebSocket('wss://api.example.com/dashboard/realtime')ws.onmessage = (event) => {setRealtimeData(JSON.parse(event.data))}return () => ws.close()}, [])return (<div className="container mx-auto p-6"><h1 className="text-2xl font-bold mb-6">运营数据仪表盘</h1><div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"><div className="bg-white rounded-lg shadow p-6"><h3 className="text-lg font-semibold mb-2">总用户数</h3><p className="text-3xl">{realtimeData?.totalUsers || initialData.summary.totalUsers}</p></div><div className="bg-white rounded-lg shadow p-6"><h3 className="text-lg font-semibold mb-2">活跃用户</h3><p className="text-3xl">{realtimeData?.activeUsers || initialData.summary.activeUsers}</p></div><div className="bg-white rounded-lg shadow p-6"><h3 className="text-lg font-semibold mb-2">营收(元)</h3><p className="text-3xl">{realtimeData?.revenue || initialData.summary.revenue}</p></div></div><div className="bg-white rounded-lg shadow p-6"><h3 className="text-lg font-semibold mb-4">历史趋势</h3><LineChartwidth={800}height={400}data={initialData.historicalData}margin={{ top: 5, right: 30, left: 20, bottom: 5 }}><CartesianGrid strokeDasharray="3 3" /><XAxis dataKey="date" /><YAxis /><Tooltip /><Line type="monotone" dataKey="users" stroke="#8884d8" /><Line type="monotone" dataKey="revenue" stroke="#82ca9d" /></LineChart></div></div>)}export default Dashboard

各场景特点说明

  1. 博客文章页面

    • 使用 getServerSideProps 在服务器端获取文章数据
    • 完全的SSR渲染,有利于SEO
    • 适合内容不经常变化的场景
  2. 电商产品列表

    • 支持动态分类和筛选
    • 服务器端预渲染商品数据
    • 结合客户端交互(分类选择、加入购物车)
  3. 新闻门户首页

    • 使用Nuxt.js的asyncData进行服务器端数据获取
    • 支持动态切换分类
    • 针对SEO优化的meta信息
  4. 仪表盘页面

    • 混合渲染策略:
      • 初始数据通过SSR加载
      • 实时数据通过客户端WebSocket更新
    • 使用Recharts进行数据可视化
    • 响应式布局设计

最佳实践建议

  1. 数据获取

    • 在服务器端获取关键数据
    • 使用适当的缓存策略
    • 考虑数据的实时性需求
  2. 性能优化

    • 实现增量静态再生成(ISR)
    • 使用适当的缓存策略
    • 优化图片和资源加载
  3. 用户体验

    • 实现平滑的客户端交互
    • 添加适当的加载状态
    • 处理错误情况
  4. SEO优化

    • 添加适当的meta标签
    • 实现结构化数据
    • 确保内容的可访问性

结论

SSR是一种强大的渲染方式,特别适合需要良好SEO和快速首屏加载的应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/459845.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有趣智力题(非编程题)

目录 赛马烧香问题 赛马 题目描述: 一共有36匹马 6个跑道 在没有计时器的情况下 请问: 最少进行多少次赛马 可以确定前三名? 答案:8次 图解思路: 注意下图写错了 注释没写错 图画错了 正确的是下图 烧香问题 题目描述: 有两根香 材质不均匀 但是每一根香 烧完都需要1h 请利用…

学习threejs,使用粒子实现下雪特效

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Points简介1.11 ☘️…

Golang | Leetcode Golang题解之第517题超级洗衣机

题目&#xff1a; 题解&#xff1a; func findMinMoves(machines []int) (ans int) {tot : 0for _, v : range machines {tot v}n : len(machines)if tot%n > 0 {return -1}avg : tot / nsum : 0for _, num : range machines {num - avgsum numans max(ans, max(abs(sum…

算法练习:209. 长度最小的子数组

题目链接&#xff1a;209. 长度最小的子数组。 这里ans来统计最小长度&#xff0c;所以初始值设置为INT_MAX.最后如果ans结果还是INT_MAX时&#xff0c;说明无此数组。 class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {if (nums.size(…

WPF+MVVM案例实战(十一)- 环形进度条实现

文章目录 1、运行效果2、功能实现1、文件创建与代码实现2、角度转换器实现3、命名空间引用 3、源代码下载 1、运行效果 2、功能实现 1、文件创建与代码实现 打开 Wpf_Examples 项目&#xff0c;在Views 文件夹下创建 CircularProgressBar.xaml 窗体文件。 CircularProgressBa…

《贪婪算法实战:寻找最短无序连续子数组的深度解析与实现》

🚀 博主介绍:大家好,我是无休居士!一枚任职于一线Top3互联网大厂的Java开发工程师! 🚀 🌟 在这里,你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人,我不仅热衷于探索一些框架源码和算法技巧奥秘,还乐于分享这些宝贵的知识和经验。 💡 无论你是刚刚踏…

堆的基本概念和插入删除方法的介绍

优先级队列的介绍&#xff1a; 1.1优先级队列&#xff1a;优先级队列是一种特殊的队列数据结构&#xff0c;每个元素都有一个与之关联的优先级&#xff0c;与普通队列不同&#xff0c;优先级队列中的元素是按照优先级顺序进行处理的&#xff0c;而不是简单的插入。 特点&…

雷军:对“雷军语音包”感到不适,希望停止使用

对于社交媒体上频繁出现的“雷军AI语音包”&#xff0c;雷军发声回应。10月29日&#xff0c;雷军发布视频表示&#xff1a;“最近两年AI特别火&#xff0c;技术进步特别得快&#xff0c;前段时间我在刷抖音的时候&#xff0c;经常看到很多人在玩‘雷军AI’&#xff0c;就是雷军…

分布式光伏是什么意思?如何高效管理?

分布式光伏系统是指在用户现场或靠近用电现场配置较小的光伏发电供电系统&#xff0c;以满足特定用户的需求。根据通知&#xff0c;分布式光伏系统主要有以下几类定义&#xff1a; 10kV以下电压等级接入&#xff0c;且单个并网点总装机容量不超过6MW的分布式电源&#xff1a;这…

项目1 yolov5鱼苗检测计数

yolov5鱼苗检测 1. yolov5鱼苗检测1.1. 环境配置1.2 Predict1.3 Validate1.4 Train1.5 生成 ONNX 2 代码解析2.1 模型2.2 数据集2.3 损失函数2.4 训练2.5 预测 之前做的项目&#xff0c;再回顾一下 环境&#xff1a;GPU1卡&#xff0c;CPU4核&#xff0c;每显卡12GB&#xff0c…

智能文档处理平台:免费体验智能化医疗信息提取

前提&#xff1a;医疗行业信息碎片化问题普遍&#xff0c;手工数据录入效率低且易错&#xff0c;导致数据管理难度大。本系统可帮助医疗机构在信息管理上迈向智能化&#xff0c;优化流程并提升效率。 系统概述&#xff1a; 思通数科推出的智能文档处理系统&#xff0c;专为解…

解决edge浏览器无法同步问题

有时候电脑没带&#xff0c;但是浏览器没有同步很烦恼。chrome浏览器的同步很及时在多设备之间能很好使用。但是edge浏览器同步没反应。 在这里插入图片描述 解决方法&#xff1a; 一、进入edge浏览器点击图像会显示未同步。点击“管理个人资料”&#xff0c;进入后点击同步&…

python代码中通过pymobiledevice3访问iOS沙盒目录获取app日志

【背景】 在进行业务操作过程中&#xff0c;即在app上的一些操作&#xff0c;在日志中会有对应的节点&#xff0c;例如&#xff0c;下面是查看设备实时视频过程对应的一些关键节点&#xff1a; 1、TxDeviceAwakeLogicHelper&#xff1a;wakeStart deviceId CxD2BA11000xxxx …

网络编程_day6

目录 【0】复习 并发服务器实现思路梳理 多进程 多线程 IO多路复用select 【1】setsockopt&#xff1a;设置套接字属性 socket属性 设置地址重用 【2】超时检测 必要性 超时检测的设置方法 1. 通过函数自带的参数设置 2. 通过设置套接字属性进行设置 3. alarm函数与sigaction函…

GPT-Sovits-1-数据处理

1.1 切割音频 将音频切割为多个10s内的片段 1.2 降噪 这一步用的是modelscope的pipeline 如果要去除背景音&#xff0c;可以用傅立叶转为为频谱&#xff0c;去除低频部分后再转回来 1.3 提取音频特征 这里用到了 funasr 库 这一步目的是输出音频样本的《文本标签文件》&am…

Linux——常见指令及其权限理解(正在更新中)

1.指令 1.1 快速了解指令 pwd 首次登录&#xff0c;默认所处的路径 whoami 当前所用的用户的名称 ls 显示当前路径下&#xff0c;文件名称 mkdir 在当前目录下&#xff0c;创建一个文件夹/目录 cd 进入一个目录 touch 新建一个文…

Kafka 物理存储机制

优质博文&#xff1a;IT-BLOG-CN 一个商业化消息队列的性能好坏&#xff0c;其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一。下面将从Kafka文件存储机制和物理结构角度&#xff0c;分析Kafka是如何实现高效文件存储&#xff0c;及实际应用效果。Kafka的基…

采用STM32CubeMX和HAL库的定时器应用实例

目录 STM32的通用定时器配置流程 定时器应用的硬件设计 定时器应用的软件设计 1. 通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下&#xff1a; 2. 通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下&#xff1a; STM32的通用定时器配置流程 通用定时器…

【优选算法篇】前缀之序,后缀之章:于数列深处邂逅算法的光与影

文章目录 C 前缀和详解&#xff1a;基础题解与思维分析前言第一章&#xff1a;前缀和基础应用1.1 一维前缀和模板题解法&#xff08;前缀和&#xff09;图解分析C代码实现易错点提示代码解读题目解析总结 1.2 二维前缀和模板题解法&#xff08;二维前缀和&#xff09;图解分析C…

Topaz Video AI for Mac 视频无损放大软件安装教程【保姆级,操作简单轻松上手】

Mac分享吧 文章目录 Topaz Video AI for Mac 视频无损放大软件 安装完成&#xff0c;软件打开效果一、Topaz Video AI 视频无损放大软件 Mac电脑版——v5.3.5⚠️注意事项&#xff1a;1️⃣&#xff1a;下载软件2️⃣&#xff1a;安装软件&#xff0c;将安装包从左侧拖入右侧文…