初识 React

一、浏览器相关

(1) 浏览器的渲染引擎

在这里插入图片描述

(2) 渲染引擎

在这里插入图片描述

描述

  • 1 用户的请求资源通过浏览器的网络层到达渲染引擎后,渲染引擎开始工作
  • 2 每次渲染的文档不会超过 8k 的数据块
  • 3 渲染引擎的职责就是渲染,在浏览器窗口显示所有请求的内容

(3) 两个树 DOM Tree 和 Render Tree

3.1 DOM Tree

全称 document object model , 即我们所熟知的文档对象模型,我们可以把它看成 html 元素 对外的接口,有了这些接口 javascript 开发人员才能实现复杂的页面功能,DOM 树的根节点就是 document 对象.DOM Tree 基本单位是 node 节点,包含整个 html 文档的各个 tag,主要反应是 webpage 情况,是对 webpage 的一个写真.

3.2 RenderTree

由一些包含颜色大小等属性的矩形组成,它们将按照正确的顺序显示在屏幕上,Render Tree 最小的单元是 RenderObject,Render Tree 每个单元都涉及页面中某块区域的布局和渲染,因此一些不涉及区域渲染的节点在 Render Tree 中是不存在的

(4) layout

布局 RenderObject构造出来并没有立即添加在Render Tree上,它并没有位置跟大小的信息,为他确
定这些信息的过程我们称之为布局, html采取了一种流式布局的布局模型,从上到下,从左到右顺序布局,布局的起点是从Render Tree的根节点开始的,对应DOM Tree的根节点(document),初始位置坐标为(0,0 ).
流程:每个RenderObject的宽度是由父节点的RenderObject确定,父节点遍历子节点,确定子节点的位置(x,y),调用子节点的Layout方法确定其高度,父节点根据子节点的height,margin,padding确定自身的高度。

(5) 全局 layout 与增量的 layout

全局Layout 当Layout在整棵渲染树上触发时。例如:
一个全局样式改变影响所有渲染对象时,比如字号的改变
窗口Resize
增量Layout 只有标记为dirty的会重新布局(也将导致一些额外的布局)。增量Layout会在渲染对象dirty
是异步触发。例如:当网络接收到新的内容并添加到DOM树后,新的渲染对象会添加到渲染树中。

dirty bit系统 为了不因为每个小的变化都全部重新布局,浏览器使用了一个dirty bit系统,一个渲染对
象发生了变化或者被添加了,就标记它及其子元素为dirty,一一需要layout。
存在两个标示,dirty以及children are dirty,children are dirty说明即使这个渲染对象没有问题,但它至少有一个child需要layout

(6) painting

绘制阶段 遍历渲染树,并调用渲染对象的paint方法,将它们的内容显示在屏幕上,绘制使用ui基础组件css2定义的渲染顺序 一个块对象的渲染顺序是:
在这里插入图片描述
这个就是元素压入堆栈的顺序,这个顺序影响着绘制,堆栈从后向前进行绘制。

(7) 渲染引擎线程

渲染引擎是单线程的,除了网格操作外,几乎所有的事情都在单一的线程中处理,在 Firefox 和 Safari 中,就是浏览器主线程,chrome 中 是 tab 的主线程
网络操纵由几个并行线程执行,并行的链接是受限制的(通常是2-6个)
浏览器的主线程是一个事件循环,他被设计成无限循环以保持执行过程中可用,等待事件(例如layout 和 paint 事件) 并执行它们.

(8) webkit 详解渲染流程

在这里插入图片描述
以上步骤是一个渐进过程,为了提高用户体验,渲染引擎视图尽可能的把结果显示给用户,他不会等待所有 html 都被解析完才会创建并布局渲染树,它会从网络层获取文档内容的同时把已经接收的局部内容先展示出来

二、 建设高性能网站

(1) 高性能网站

  • 减少 HTTP 连接请求
  • 把部分内容压缩
  • 避免 CSS 表达式
  • 减少 DNS 查找
  • 避免重定向连接
  • 避免大量DOM操作

(2) 性能瓶颈之 DOM 操作开销

对DOM操作的代价是高昂的,这在网页应用中的通常是一个性能瓶颈。
在《高性能JavaScript》中这么比喻:“把DOM看成一个岛屿,把JavaScript(ECMAScript)看成另一个岛屿,两者之间以一座收费桥连接”。所以每次访问DOM都会交一个过桥费,而访问的次数越多,交的费用也就越多。所以一般建议尽量减少过桥次数。

(3) 减少 DOM 操作

对DOM元素的增删改查会造成页面的Repaint和Reflow,循环对DOM操作更是罪恶的行为。所以合理的使用JavaScript变量储存内容,在循环结束时一次性写入。
减少对DOM元素的查询和修改,查询时可将其赋值给局部变量。

(4) 来自 React 的革命性的创新

由于React的设计思想极其独特,性能出众,代码逻辑非常简单。被越来越多的人关注和使用,认为它将是未来Web开发的主流工具。
特点:

  • 高效: React 通过对 DOM 的模拟,最大限度地减少与DOM的交互
  • 组件化: React 采取组件化开发,极大限度的使组件得到复用,便于开发管理与维护
  • 适用多端: 一处开发,多端使用,将颠覆整个互联网行业

(5) Virtial Dom – 虚拟DOM

传统的web应用,操作DOM一般是直接更新操作的,但是我们知道DOM更新通常是比较昂贵的。而React为了尽可能减少对DOM的操作,提供了一种不同的而又强大的方式来更新DOM,避免直接操作DOM。就是Virtual DOM。一个轻量级的虚拟的DOM,就是React抽象出来的一个对象,用来描述DOM应该什么样子的,应该如何呈现。通过这个Virtual DOM去更新管理真实的DOM。
在这里插入图片描述
注意: 虚拟 DOM 有的人也翻译成 react 元素

(6) 虚拟 DOM 的实现原理

传统开发中,当 app 内部状态改变时,会直接修改 DOM,造成一定的操作开销,如果同时触发多个事件,事件就会不停的对 DOM 操作,而产生开销膨胀.
在这里插入图片描述
在 React 中,对虚拟 DOM 的操作,不会立刻映射到真实 DOM 上,这使得 React 能够等待,直至事件循环结束,在此之前完全不用操作真实的 DOM ,React 会计算出虚拟 DOM 的变化(diff),并以尽少的操作将 diff 作用到真实的 DOM 上.批量 DOM 操作以及虚拟 DOM 的变化检测将由 React 处理完成.

(7) 虚拟 DOM 的变化检测

在这里插入图片描述
当修改虚拟 DOM 的时候,React 会将修改的虚拟 DOM 节点标记为修改过(dirty) ,在 事件循环结束时,会对所有修改过的 DOM 节点进行处理,并映射到真实 DOM

(8) 虚拟 DOM 的例子

例如,在DOM处在左侧状态时,我们操作应用程序,为每一个容器设置内容,那么当虚拟DOM检测改变后不会重新创建9个容器,也不会将原来9个容器删除,因为这样开销很大,React会对比左右两种状态,发现只有容器内容发生变化了,因此它会将新的内容设置在9个容器中,减少其他操作,提高性能。
在这里插入图片描述

(9) 为什么要组件化开发

无论是前端还是后端,在产品确定情况下优化成本有两个途径:减少部署成本,提高开发效率.

  • 减少部署成本:,可以将产品迁移到开源的易替换的产品集群等,优化方式有很多.
    但对于我们前端来说提高开发效率才是最主要的优化途径.

  • 提高开发效率: 主要途径有两点: 加快开发速度,减少变更代价
    如何提高开发速度?
    我们在开发中不要重复造轮子,如果可以利用已有的产品,那么开发效率将极大提高
    如何减少变更代价?
    如果我们能够理清模块之间的关系,合理分层,每次变更只需要修改其中某个部分,如果不用修改代码,仅仅改变配置就可以,岂不是更好了

(10) 页面切割

React 的组件开发类似组合模式(先分后和),将整个页面进行细度切割,划分成一个个子组件,然后针对于一个个子组件进行开发、更新、迭代、当然对于相同功能的组件是可以复用的(例如 图中黄色组件部分),最终再由这些子组件重新组装成新的页面.
在这里插入图片描述

(11) 一个组件切割的例子

在这里插入图片描述

(12) 多端适配

多端适配: 一处开发,多端适用,将颠覆整个互联网行业,为了实现多端适配的混合开发,React 将分成两类库:
一类是 核心库:React
一类是 渲染库:浏览器
在这里插入图片描述

三、 初始使用 React

(1) 获取 React

Git 地址: https://github.com/facebook/react
获取 React

npm install react react-dom

注: 在 ES5 开发中,可以通过 bower 获取 React.js 和 react-dom.js 文件
我们使用最新版本,只能使用 ES6 开发

(2) 创建虚拟 DOM

核心库: react 提供了 createElement 方法来创建虚拟 DOM

import  {  createElement } from 'react';
import { render } from 'react-dom';

// 创建元素
let  h1 = createElement('h1',{ title:'hello' ,"创建的 h1 标题'})

// 在页面中进行渲染
render(h1,document.getElementById('app'),(...args)=>{
	consle.log(args,'success');
})
createElement('h1',{ title:'hello' ,"创建的 h1 标题'})
第一个参数表示虚拟 DOM 名称(也可以是组件名称)
第二个参数表示虚拟 DOM 的属性对象
第三个参数开始,表示子虚拟 DOM

(3) 虚拟 DOM

虚拟 DOM 是一个普通的 JS 对象,存储一些必要属性来描述 DOM
type 表示虚拟 DOM 类型
key 表示虚拟 DOM 的 id
ref 表示对真实 DOM 的 引用
props 表示虚拟 DOM 中所有属性对象
children 表示虚拟 DOM 的子虚拟 DOM
字符串 表示一个文本节点
对象 表示一个虚拟 DOM
数组 表示多个虚拟 DOM 或者文本

(4) 渲染虚拟 DOM

浏览器端渲染库 react-dom,提供了 render 方法,可以渲染虚拟 DOM
第一个参数表示虚拟 DOM
第二个参数表示真实 DOM 容器元素
第三个参数是回调函数,表示渲染完成执行的方法

// 引入创建 React 的 DOM 元素
import { createElement } from 'react';
// 引入渲染元素的方式
import { render } from 'react-dom';

// 创建元素
let h1 = createElement('h1',{ title:'hello' },'文本标题1')
// let h1 = createElement('h1', { title:'hello' },createElement('span'))
// let h1 = createElement('h1', { title:'hello' },createElement('span'),
'大闸蟹');
// 在页面中进行元素的渲染
render(h1,document.getElementById('app'),(...args)=>{
    console.log(args,"auccess");
})

(5) 让 创建的 react 项目文本在页面显示的步骤

  • 安装 webpack
npm i webpack wenpack-cli -d
  • 安装React
npm i react react-dom -d
  • 安装babel(指导webpack 如何将 JSX 文件转化为 js 语法的文件 )
npm i babel-loader @babel/core @babel/preset-env @babel/preset-react -d

前提:
注意 React 18 版本之后 DOM 的渲染方式进行改变

需要在 jsx 文件中引入
// React 18 版本后的渲染方式
import ReactDOM  from 'react-dom/client';
// 其他创建元素的方式不变

// 渲染时的改变
// ReactDOM.createRoot(app).render(<DOM/>)

5.1 在文件中创建文件

在这里插入图片描述

  • dist 文件不用创建 这是发布出来的文件
  • modules 文件可以创建几个编写 react 的 jsx 文件
    在这里插入图片描述
  • index.html 文件 创建 根文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    

    <div id="app"></div>
    <div id="app2"></div>
    <div id="app3"></div>

    <script src="./dist/01.js"></script>
</body>
</html>

-webpack.conffig.js 创建 用于编译的 jsx 文件的程序

// 接口
module.exports = {
    // 模式
    mode:'development',
    // 解决 文件后缀的问题
    resolve:{
        // 默认拓展名
        extensions:['.jsx','.js']
    },
    // 入口
    entry:{
        '01':'./modules/01.jsx',
        '02':'./modules/02.jsx',
        '03':'./modules/03.jsx',
        '04':'./modules/04.jsx',
        '05':'./modules/05.jsx',
        '06':'./modules/06.jsx',
    },
    // 发布
    output:{
        // 发布位置
        filename:'./[name].js'
    },
    // 模块:
    module:{
        // 加载机
        rules:[
            // 编译 jsx
            {
                test: /\.(js|jsx)$/,
                // 注意 这里必须 use  其他的方式会报错 具体的问题不清楚
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react']
                    }
                }
            },
            //css
            {
                test:/\.css$/,
                use:['style-loader!css-loader']
            },
            //less
            {
                test:/\.less$/,
                use:['style-loader!css-loader!less-loader']
            },
            // scss
            {
                test:/\.scss$/,
                use:['style-loader!css-loader!sass-loader']
            }
        ]
    }

}
  • 在 modules/01.jsx 中书写代码
// 引入创建 React 的 DOM 元素
import { Component, createElement } from 'react';
// 引入渲染元素的方式
import { render } from 'react-dom';


// 创建元素
let h1 = createElement('h1',{ title:'h1Title' },'文本标题1')

// 在页面中进行元素的渲染
render(h1,document.getElementById('app'),(...args)=>{
    console.log(args,"auccess");
})

此时点击webpack.config.js 文件 右击 ---- 在打开的控制台中输入 webpack -w ----- 然后在html 文件中运行即可
在这里插入图片描述

(6) 组件

虚拟DOM与页面中的真实DOM相对应,因此一个虚拟DOM对应一个真实DOM。
如果页面中有很多真实DOM,我们就要创建很多虚拟DOM。
为了复用虚拟DOM,react提供了组件技术。
定义组件就是定义一个类:

在ES5开发中,通过React.createClass方法创建组件类
在ES6开发中,通过class定义组件类

语法 class 组件类名 {}

注意:类名首字母大写

由于所有的组件都有相似的行为,所以React将这些相似的行为封装在Component组件基类中。
所以为了让我们定义的组件具有这些行为,就要继承组件基类Component。

语法: class 组件类名 extends Component {}

为了渲染虚拟DOM,我们要在类中定义render方法。
其返回值就是虚拟DOM。
返回的虚拟DOM中,最外层有且只有一个根节点

注:渲染库的render方法和组件的render方法没有任何关系

渲染库的render方法只能渲染虚拟DOM,不能渲染组件,想渲染组件,要通过createElement方法将组件转成虚拟DOM。

注意 在 html 文件中引入发布后的 js 文件 例如
在这里插入图片描述

  • modules/02.jsx 文件中书写 并在终端运行 webpack -w
// 引入创建 React 的 DOM 元素
import { Component, createElement } from 'react';
// 引入渲染元素的方式
import { render } from 'react-dom';

// 创建多个元素的渲染方式
class App extends Component{
    render(){
        return createElement(
            'ul',
            null,
            createElement('li',null,'好看视频'),
            createElement('li',null,"爱奇艺"),
            createElement('li',null,'搜狐')
        )
    }
}

// 创建元素
let app2 = createElement(App);

// 进行渲染
render(app2,document.getElementById('app2'),(...args)=>{
    console.log(args,'success');
})


// 对创建的多个元素进行复用
let app3 = createElement(App);
render(app3,document.getElementById('app3'),(...args)=>{
    console.log(args,'success');
})

(7) jsx 语法

我们创建虚拟DOM太麻烦了,不如在html页面中创建元素方便。
react团队为了让我们创建虚拟DOM更方便,提供了jsx语法:像创建XHTML元素一样,创建虚拟
目前浏览器不支持 JSX 语法,因此我们要编译 JSX 语法
在这里插入图片描述

(8) 编译 jsx 语法

我们编译ES6语法使用:es2015或env编译器
我们编译jsx语法使用:react编译器
我们既想编译ES6语法,也想编译jsx语法,就要同时使用es2015与 react编译器。
在webpack4.0中,我们要使用最新的编译器:

 [‘@babel/preset-env’, ‘@babel/preset-react’]

拓展名
为了区分ES5语法和ES6语法,我们将文件拓展名定义成.es
为了区分ES5语法和jsx语法,我们可以文件的拓展名定义成 .esx, .jsx, .tsx, .es6x …
为了语义化,react团队建议我们定义成.jsx

  • 在webpack.config.js 文件中编写
    在这里插入图片描述
  • 在modules/03.jsx文件中编写并运行即可
// 引入创建 React 的 DOM 元素
import React,{ Component } from 'react';
// 引入渲染元素的方式
import { render } from 'react-dom';


// 创建多个元素的渲染方式
class App extends Component{
   render(){
       return (
           <ul>
               <li>好看视频</li>
               <li>爱奇艺</li>
               <li>搜狐</li>
           </ul>
       )
   }
}

// 创建元素
let app2 = <App></App>;

// 进行渲染
render(app2,document.getElementById('app1'),(...args)=>{
   console.log(args,'success');
})


// 对创建的多个元素进行复用
let app3 = <App/>;
render(app3,document.getElementById('app2'),(...args)=>{
   console.log(args,'success');
})

(9) 插值

已经学过的插值语法:

 ejs模板 <%=key%>
 ES6 ${key}
 微信 {{key}} 伪js环境
 less @{key}
 scss #{$key}
 vue {{key}}

由于JSX语法不是js环境,因此不能使用变量,想使用表达式(变量等)就要通过插值语法,创建一个js
环境。
插值语法: {}
是一个真正的js环境,可以书写复杂的表达式。
由于插值语法提供的是真正的js环境。因此可以继续使用jsx语法。
注:js语法与jsx语法可以嵌套使用。

(10) 注释

jsx语法既不是html环境也不是js环境,
因此既不能使用html中的注释,也不能使用js中的注释,
插值可以提供js环境,因此可以在js环境中书写js注释
注意:不要注释掉插值闭合符号,所以工作中多行注释更常用

  • 在modules/04.jsx文件中编写并运行即可
import  React,{ Component } from 'react';
import { render } from 'react-dom';

let title = '大闸蟹';
let data = new Date();
// 三元判断
// let msg = '有值的时候显示';
let msg = '';
// 创建元素
class Dom extends Component{
    render(){
        return(
            <div>
                {
                // 单行注释 
                // 注意单行注释需要换行
                }
                {/* 多行注释 */}
                <h1>{title}</h1>
                <h1>{data.getFullYear() + '/' + (data.getMonth()+1) + '/' + (data.getDate())}</h1>
                <p>{msg ? <a href=''>{msg}</a> : <a href=''>没有数据</a>}</p>
            </div>
        )
    }
}

// 之前的渲染方式
// render(<Dom></Dom>,document.getElementById('app'))
// 现在的方式
render(<Dom></Dom>,app)

(11) 虚拟 DOM 的四类属性

虚拟 DOM 有四类属性:自定义属性、元素属性、特殊元素属性、非元素属性

  • 自定义属性: 用来存储数据的.没有特殊含义
    html5 中,自定义属性建议以 data-开头

  • 元素属性: 对于元素来说有特殊的含义,例如: id,title,style 等
    注:style的属性值只能是对象。如:style={{ key: value }}
    外面的{}表示插值符号,内部的{}表示对象符号,样式名称要使用驼峰式命名
    注:如果样式属性值表示长度单位,并且单位是像素,则像素可以省略

  • 特殊元素属性:虚拟DOM有两个常见的特殊元素属性class和for。它们命中了关键字以及保留字
    所以:class 要写成 className。for 要写成 htmlFor

  • 非元素属性: 是由React拓展的,不是DOM元素默认的属性,如:ref, dangerouslySetInnerHTML, key
    非元素属性是react提供的功能,类似vue中的指令

(12) 非元素属性 – ref

ref:允许我们在组件中获取虚拟DOM对应的真实DOM元素(也可以是自定义组件)。
例如:在
componentDidMount(组件创建完成)方法中获取

分成两步:第一步 为元素设置ref属性,第二步 在组件中,通过this.refs获取对应的元素

注意:如果获取的是元素,则是源生的DOM元素,因此要通过源生的DOM API操作。
通常在一些第三方插件中使用
我们直接操作真实DOM元素就跳过了虚拟DOM环节,因此这些操作会被React忽略。无法被虚拟DOM优化,工作中慎用

(13) 非元素属性 – dangerouslySetInnerHTML

用危险的(不合法的)方式设置元素的内容。
不合法的方式有:
1 不能使用行内式样式字符串。
2 不能直接使用特殊元素属性。
3 不能渲染标签等等 … …
我们可以借助dangerouslySetInnerHTML属性实现这些功能。属性值是对象,通过__html设置内容。

注意:
1 该属性也是直接对真实DOM元素设置innerHTML属性,因此跳过了虚拟DOM优化环节,工作中慎
用。

2 设置的内容要保证是安全的。否则可能会被攻击。

(14) 非元素属性—key

为列表中的虚拟DOM设置id。
虚拟DOM可以包含一个子虚拟DOM或者文本,也可以包含多个子虚拟DOM(是数组)
当包含多个子虚拟DOM的时候,就是一个数组,
此时要为每一个成员设置key属性。
注意:每一个数组中,key属性值要唯一并且稳定、可预测。

  • modules/04.jsx 文件中书写


import React,{ Component } from 'react';

// import { render } from 'react-dom';

// import { createRoot } from 'react-dom/client';

// React 18 版本后的渲染方式
import ReactDOM from 'react-dom/client';

let msg = '<a href="javascript:alert(1)">a 标签元素</a>';

// 定义数组的数据
let data = ['爱奇艺',"腾讯","优酷"];

// 第四步
class DOM extends Component{
    // 组件的生命周期 --- 组件创建完成
    // 报错  说 React18 已经不支持这种写法
    componentDidMount(){
        // console.log(this);
        // 修改ref 绑定的 元素 样式
        this.refs.dzx.style.color="yellow"
    }
    // 定义创建列表的方法
    createList(){
        // return [1,2,3]
        // return [
        //     <li key="0">腾讯</li>,
        //     <li key="1">爱奇艺</li>,
        //     <li key="2">优酷</li>
        // ]

        // 第四步  重新进行熏染
        // return data.map((item,index)=>{
        //     return <li key={index}>{item}</li>
        // })

        // 第四步 方法的简写方式
        return data.map((item,index)=> <li key={index}>{item}</li>)
    }
    // 渲染
    render(){
        console.log(this.createList());
        return(
            <div>
                {/* 自定义数据属性 */}
                <h1 data-dzx="title">自定义的标题</h1>
                {/* 定义多个元素属性 */}
                <h3 style={{
                    color:'red',
                    // 驼峰式命名样式
                    backgroundColor:'pink',
                    // 可以省略 单位 
                    fontSize:50
                }}>h3 定义多个样式显示</h3>

                {/* 特殊元素属性 */}
                {/* class  要写成 className   */}
                {/* label 的 for 属性 要写成 htmlFor  */}
                <p className='hello'>大闸蟹定义的  class</p>
                <p>
                    <label htmlFor="username">用户名</label>
                    <input type="text" id='username' />
                </p>

                {/* 非元素属性---工作中慎用 */}
                <h1 data-name="200" ref="dzx"></h1>
                
                {/* 非元素属性 --- 工作中慎用 --- 避免造成攻击*/}
                {/* 双 下划线   通过这样的方式能渲染出标签元素*/}
                <h5 dangerouslySetInnerHTML={{ __html:msg }}></h5>
                {/*  而通过这样的方式不能渲染标签元素  */}
                <h3>{msg}</h3>


                {/* 渲染数组的数据   */}
                {/* 第一步  最初始的方法*/}
                {/* <ul>
                    <li>爱奇艺</li>
                    <li>腾讯</li>
                    <li>优酷</li>
                </ul> */}

                {/* 第二部  数组的方式渲染  必须加 key 值 也是唯一的值 不可重复 */}
                {/* <ul>
                    {[
                        <li key="0">腾讯</li>,
                        <li key="1">爱奇艺</li>,
                        <li key="2">优酷</li>
                    ]}
                </ul> */}

                {/* 第三步 通过方法创建数组 */}
                {/* <ul>
                    {this.createList()}
                </ul> */}

                {/* 第四步 */}
                <ul>
                    {this.createList()}
                </ul>

            </div>
        )
    }
}


// 注意 React 18 版本后需要修改成 这一样的方式进行渲染
ReactDOM.createRoot(app).render(<DOM/>)

// 之前采用的这种方式目前被弃用了
// render(<DOM/>,app)

// 之前传统的 定义样式的方式
// render(React.createElement('h3',{
//     style:{
//         color:'blue',
//     }
// },"h3 定义样式"),app)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大闸蟹~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值