【前端】特效开发

一、bootstrap

(一)入门基础

1.简介与安装

官网:https://getbootstrap.com
bootstrap是一个用于制作页面界面的框架
框架: 提供一个标准和规范,再由开发人员自行填充内容
安装
①官网下载:https://getbootstrap.com/docs/5.0/getting-started/download/
②npm 下载:npm i bootstrap

2.使用bootstrap

在html中引入css、js

    <link rel="stylesheet" href="./css/bootstrap.css">
    <script src="./js/bootstrap.bundle.min.js"></script>

使用bootstrap的容器进行响应式布局的话,需要在head标签中加入此meta

<meta name="viewport" content="width=device-width, initial-scale=1.0">

(二)结构布局

1.container布局

响应式布局:根据屏幕宽度,切换不同页面布局的一种布局方式,bootstrap 是使用断点来完成响应式布局的
断点:是 bootstrap 面向不同屏幕宽度,预制好的媒体查询
通常的讲,断点,代表的就是不同的屏幕宽度
布局容器:通常是页面的根节点,使用 class="container" 来设置布局容器
布局容器受断点影响,可以设置不同断点上的容器,具体如下表:
在这里插入图片描述
实例代码如下:

<body>
    <div class="container">
        <div class="content">container</div>
    </div>
    <div class="container-sm">
        <div class="content">container-sm</div>
    </div>
    <div class="container-md">
        <div class="content">container-md</div>
    </div>
    <div class="container-lg">
        <div class="content">container-lg</div>
    </div>
    <div class="container-xl">
        <div class="content">container-xl</div>
    </div>
    <div class="container-xxl">
        <div class="content">container-xxl</div>
    </div>
    <div class="container-fluid">
        <div class="content">container-fluid</div>
    </div>
</body>

2.display显示方式

语法:
在 xs 断点下: d-{value}
xs 以上: d-{breakpoints}-{value}
实例代码如下:

<body>
    <!-- 当屏幕宽度小于 sm 时显示 -->
    <div class="container d-block d-sm-none">小于 sm</div>
    <!-- 当屏幕宽度为 md 时 显示 -->
    <div class="container d-none d-sm-block d-md-none">md</div>
    <!-- 当屏幕宽度大于 lg 时 显示 -->
    <div class="container d-none d-md-block">大于 lg</div>
</body>

3.float-position-flex

float
float-start 左浮
float-end 右浮
clearfix 清除浮动

    <div class="clearfix">
        <div class="box bg-warning float-start"></div>
        <div class="box bg-success float-start"></div>
        <div class="box bg-danger float-end"></div>
    </div>

position
position-{value}
value: absolute relative fixed sticky

    <div style="height: 600px" class="d-flex justify-content-center">
        <div style="width: 600px; height: 500px" class="border position-relative">
            <div class="box bg-danger position-absolute top-50 translate-middle-y"></div>
            <div class="box bg-danger position-absolute start-50 translate-middle-x"></div>
            <div class="box bg-danger position-absolute end-0 top-50 translate-middle-y"></div>
            <div class="box bg-danger position-absolute start-50 bottom-0 translate-middle-x"></div>
            <div class="box bg-danger position-absolute start-0 top-0"></div>
            <div class="box bg-danger position-absolute end-0 top-0"></div>
            <div class="box bg-danger position-absolute start-0 bottom-0"></div>
            <div class="box bg-danger position-absolute end-0 bottom-0"></div>
            <div class="box bg-danger position-absolute start-50 top-50 translate-middle"></div>
        </div>
    </div>

flex
bootstrap中flex 的使用基本上就是把所有flex的属性变成了class类

    <div style="height: 400px;" class="bg-success d-flex justify-content-end align-items-center align-content-center">
        <div class="box bg-warning flex-grow-1"></div>
        <div class="box bg-primary"></div>
        <div class="box bg-primary align-self-end flex-shrink-0"></div>
        <div class="box bg-primary"></div>
        <div class="box bg-primary"></div>
        <div class="box bg-primary"></div>
    </div>

4.网格布局

行:row 列:col
bootstrap 中 一行 row 被等分为 12 分 那么col的value值代表的是占多少份
col 语法: col-{breakpoints}-{value}
value: 范围在 1~12
纵向排列方式:在 row 上可以使用flex 的 align-items 来进行竖直方向的排列
横向排列方式:在 row 上可以使用 flex 的 justify-content 来进行水平方向的排列
单元格偏移:offset 设置单元格左侧的偏移量 数字代表的含义和 col 相同
单元格间距:添加单元格间距使用 gutter 首字母为 g。可以使用 g-{value}gx-{value}gy-{value}
指定每一行显示多少列row-cols-{breakpoints}-{value} 让一行显示多少列

(三)表单

1.排列方式

label 与 表单元素上下排列

    <div class="card p-3" style="width: 300px;">
        <div class="vstack gap-2">
            <div>
                <label class="form-label">姓名</label>
                <input class="form-control" type="text" />
            </div>
    </div>

label 与 表单元素左右排列

    <div class="card p-3" style="width: 500px">
        <div class="row">
            <label class="col-3 col-form-label">姓名</label>
            <div class="col">
                <input class="form-control" type="text">
            </div>
        </div>
    </div>

2.输入框和文本域

示例代码如下:

            <div>
                <label class="form-label">年龄</label>
                <!-- 设置大小 -->
                <input class="form-control form-control-sm" type="number" />
                <input class="form-control form-control-lg" type="number" />
                <!-- 禁用 disabled -->
                <input class="form-control" type="number" disabled />
                <!-- 只读 readonly -->
                <input class="readonly form-control" type="number" readonly />
            </div>

            <div>
                <label class="form-label">邮箱</label>
                <!-- 朴素输入框 form-control-plaintext -->
                <input class="form-control form-control-plaintext" type="text" readonly value="xxx@xxx.com" />
            </div>

            <div>
                <label class="form-label">简介</label>
                <!-- form-control 相关样式都可以用在文本域上 -->
                <textarea disabled rows="4" class="form-control" type="text"></textarea>
            </div>

3.选择按钮

单选

        <div class="row">
            <label class="col-3 col-form-label">性别</label>
            <div class="col">
                <!-- 单选按钮 -->
                <div class="form-check">
                    <input class="form-check-input" id="male" type="radio" name="sex" value="male">
                    <label class="form-check-label" for="male"></label>
                </div>
                <div class="form-check">
                    <input class="form-check-input" id="female" type="radio" name="sex" value="female">
                    <label class="form-check-label" for="female"></label>
                </div>
                <div class="form-check">
                    <input class="form-check-input" id="other" type="radio" name="sex" value="other">
                    <label class="form-check-label" for="other">其他</label>
                </div>
            </div>
        </div>

多选
form-check-inline 让选项排列在一行之中

        <div class="row">
            <label class="col-3 col-form-label">爱好</label>
            <div class="col d-flex align-items-center">
                <!-- form-check-inline 让选项排列在一行之中 -->
                <div class="form-check-inline">
                    <input class="form-check-input" id="dlq" type="checkbox" name="hobbies" value="dlq">
                    <label class="form-check-label" for="dlq">打篮球</label>
                </div>
                <div class="form-check-inline">
                    <input class="form-check-input" id="tzq" type="checkbox" name="hobbies" value="tzq">
                    <label class="form-check-label" for="tzq">踢足球</label>
                </div>
                <div class="form-check-inline">
                    <input class="form-check-input" id="ymq" type="checkbox" name="hobbies" value="ymq">
                    <label class="form-check-label" for="ymq">羽毛球</label>
                </div>
            </div>
        </div>

不确定的按钮
需要给输入框添加 indeterminate 属性,但是该属性无法在html标签上直接添加,只能使用js添加

<input indeterminate id="indeterminate" class="form-check-input" type="checkbox">
<label class="form-check-label">不确定按钮</label>

开关按钮
给普通的 checkbox 添加form-switch类名即可
类似按钮的单选或多选按钮
input 中添加 btn-check
label 中添加 btn btn-outline-{color}
注意: 为了能够勾选成功 必须给label添加for 给 input 添加id

      <div class="form-check-inline">
          <!-- input 中添加 btn-check -->
          <input id="a" class="btn-check" type="radio" value="a" name="btn">
          <!-- label 中添加 btn btn-outline-{color} -->
          <!-- 注意: 为了能够勾选成功 必须给label添加for 给 input 添加id -->
              <label for="a" class="btn btn-outline-warning">a</label>
      </div>
      <div class="form-check-inline">
          <input id="b" class="btn-check" type="radio" value="bg-light" name="btn">
          <label for="b" class="btn btn-outline-warning">b</label>
      </div>

4.下拉框

<body>
    <div class="card p-3" style="width: 300px;">
        <div>
            <label class="form-label">班级</label>
            <select class="form-select">
                <option value="" disabled selected>请选择</option>
                <option value="1">一班</option>
                <option value="2">二班</option>
                <option value="3">三班</option>
            </select>
        </div>
        <div>
            <label class="form-label">班级</label>
            <!-- 输入框用 list 属性关联 datalist -->
            <input list="clazz" type="text" class="form-control">
            <!-- 通过datalist 给输入框添加待选项 -->
            <datalist id="clazz">
                <option value="1">一班</option>
                <option value="2">二班</option>
                <option value="3">三班</option>
            </datalist>
        </div>
    </div>
</body>

(四)表单验证

1.原生表单验证

表单验证:通常来说一个用户填写的表单数据都需要进行一个验证,因为用户的输入是不可信的,所以说在表单输入的时候需要对用户的输入做验证
应用场景:用户产生输入的时候
novalidate 屏蔽默认的表单提交时的验证报告,屏蔽掉自动的验证报告的目的 是为了我们自己好去控制验证报告
required 必填
pattern 正则表达式
minlength 最小长度 maxlength 最大长度
min 最小值 max 最大值
type 类型验证

<input name="name" required type="text" class="form-control">
<input name="name" pattern="[\s\S]*张三[\s\S]*" type="text" class="form-control">
<input name="name" minlength="2" maxlength="10" type="text" class="form-control">
<input name="name" min="0" max="200" type="number" class="form-control">
<input type="email" class="form-control">

通过输入框的 validity 属性 来判断用户是否输入正确
validity.valueMissing -> required 用户没填数据时为 true
validity.patternMismatch -> pattern 用户输入不满足正则 true
validity.rangeOverflow -> max 用户输入超过最大值 true
validity.rangeUnderflow -> min 用户输入小于最小值 true
validity.tooLong -> maxlength 用户输入超出长度 不会触发 true
validity.tooShort -> minlength 用户输入小于了指定长度 true
validity.valid -> 输入没有问题 验证通过 true

总结表单验证:

  1. 添加 novalidate
  2. 验证所有表单项
  3. 设置错误信息
  4. 发起验证报告
  5. 验证通过 执行后续逻辑

2.bootstrap验证

自动验证
给form添加类名 was-validated 就可以开启验证效果
验证的提示需要写在被验证的输入框下面
valid-feedback:验证通过的提示文本
invalid-feedback:验证不通过的提示文本
手动验证

<script>
    let nameInp = document.querySelector('input[name=name]')
    let ageInp = document.querySelector('input[name=age]')
    // 查询错误提示的元素
    let nameErrTip = document.querySelector('input[name=name]~.invalid-feedback')
    let ageErrTip = document.querySelector('input[name=age]~.invalid-feedback')

    let btn = document.querySelector('button')

    btn.addEventListener('click', () => {
        // 手动通过代码进行验证

        // 清空所有的 is-valid 和 is-invalid
        nameInp.classList.remove('is-valid', 'is-invalid')
        ageInp.classList.remove('is-valid', 'is-invalid')

        // 定义一个代表验证通过的变量
        let nameValid = true
        if (nameInp.value.trim() === '') {
            nameErrTip.textContent = '请输入姓名'
            nameValid = false
        } else if (nameInp.value.trim().length < 2 || nameInp.value.trim().length > 10) {
            nameErrTip.textContent = '请输入2~10个字的姓名'
            nameValid = false
        }

        let ageValid = true
        if (Number(ageInp.value) < 0 || Number(ageInp.value) > 150) {
            ageErrTip.textContent = '请输入0~150之间的年龄'
            ageValid = false
        }

        nameInp.classList.add(nameValid ? 'is-valid' : 'is-invalid')
        ageInp.classList.add(ageValid ? 'is-valid' : 'is-invalid')

        if (nameValid && ageValid) {
            // 整个表单输入正确的情况
            // 可以执行后续的网络请求
            console.log('验证通过');
        }
    })
</script>

二、react

(一)基础入门

1.简介

官网:https://zh-hans.reactjs.org
react 是一个 js核心库,如同 jquery 一样,具有大量 react 生态(围绕 react 核心开发的库)
特点:

  • 声明式
    也就是js中的数据决定页面最终渲染的结果
    声明式不是响应式,但往往都是同时出现共同作用页面
    响应式:数据变化页面会立即更新
  • 组件化
    一个包含所有外观和行为的,独立可运行的模块,称为组件
    组件化的思想可以将复杂页面,化繁为简的进行设计
    组件可提高代码复用性
  • 一次学习,跨平台编写
    使用 react 可以开发 桌面web页面,移动端页面,移动app,桌面app等

2.环境搭建

使用cdn在html引入react

<!-- react 需要引入 react 核心库 和 react-dom 库 -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<!-- 为了更方便书写 react 通常会使用 jsx 语法,为了支持该语法 需要引入 babel -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

react.js 这是框架核心库,用于解析 react 语法
eact-dom.js 这个库是用于 react 元素(也就是react的文档对象模型)的创建
babel.js 这个库用来将 jsx 语法翻译为普通的 js

3.jsx语法

jsx 语法保留了js的所有特性,在此基础上扩展了 react 的元素声明语法
采用 jsx 语法 需要在 type 处加上 text/babel
声明
使用jsx创建一个react-dom对象
react-dom 是 react 封装的类似 dom 对象的对象
作用: 用于描述页面元素

const element = <h1>Hello World</h1>

若有多行标签,可以用圆括号包裹

const element = (
    <div className="box">
        <span>hello box</span>
    </div>
)

每一个 react-dom 只能有一个根节点

const element = (
    <h1>
        Hello World
    </h1>
    // h1 和 h2 都是根节点 这个写法是错误的
    <h2>
        222
    </h2>
)

插值
将变量插入到元素中,使用大括号{}

const msg = 'hello world !!!'
const element = <h1>{msg}</h1>

花括号内的插值部分可以写入任何有效的 js 表达式
注意:插值中写注释,必须用大括号包裹并且用多行注释

    const chazhi = (
        <div>
            { /*使用花括号进行插值 插值的内容可以是js表达式*/}
            {'当前时间: ' + now.toLocaleString()}
        </div>
    )

需要注意的是 style 属性必须用花括号来插入值
不是所有的html属性名都是原始名称,例如 class 应该写为 className 并采用驼峰式命名方法 而不是html的短横线 因为本质上这里的标签是js代码

const styleObj = {backgroundColor: "green"}
const element = (
    <h1
        style={styleObj}
        className="content"> 
        Hello World
    </h1>
)

使用函数创建对象

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

// 等价于
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

jsx 中的 react-dom 内容,本质上会被 babel 翻译成 React.createElement 函数

    const fnDom = React.createElement(
        // 标签名
        'div',
        // 标签上的属性
        {id: 'myFunctionDom', className: 'my-dom', style: {width: '500px', height: '50px', backgroundColor: '#00f'}},
        // 子元素数组 或 标签体字符串
        [
            // 此处的第三个参数就是一个普通的字符串充当 span 标签的标签体
            React.createElement('span', {key: '1'}, 'hello world'),
            // 若此处 createElement 第三个参数是一个数组的话,需要给元素添加 key 属性
            // key 属性是一个唯一值 不重复即可
            React.createElement('span', {key: '2'}, 'hello world')
        ]
    )

渲染
root.render 函数可以渲染一个 react-dom 对象

    root.render((
        <div className="container">
            {/* 插值的内容 若是 react-dom 对象 那么就会被页面显示出来 */}
            {h1}
            {box}
            {element}
            {chazhi}
            {htmlAttr}
            {fnDom}
        </div>
    ))

(二)渲染

1.元素渲染

初始化渲染

    let now = new Date()
    root.render((
        <div>
            <div className="now">当前时间:</div>
            <div className="time">
                {now.toLocaleString()}
            </div>
        </div>
    ))

渲染循环

    let timer = setInterval(() => {
        // 修改渲染逻辑
        now = new Date()

        // 渲染内容
        root.render((
            <div>
                <div className="now">当前时间:</div>
                {/* react 在每次更新的时候,都会去对比每一个 react-dom 节点
                    只有发现该被对比的节点有变化时(标签体变化 子节点数量变化 节点元素变化等) 才会更新节点
                 */}
                <div className="time">
                    {now.toLocaleString()}
                </div>
            </div>
        ))
    }, 1000)

2.条件渲染

    let sex = 'male'

    ReactDOM.createRoot(document.querySelector('#root')).render((
        <div>
            {/* 使用 && 进行短路运算 前一个表达式为true时 就显示后面表达式的内容 */}
            {sex === 'male' && <div style={{color: '#00f'}}></div>}
            {sex === 'female' && <div style={{color: 'pink'}}></div>}
            {sex === 'other' && <div style={{color: '#ff0'}}>其他</div>}

            {/* 使用三元运算符 按条件显示不同的内容 */}
            {sex === 'male' ? <div style={{color: '#00f'}}></div> :
                sex === 'female' ? <div style={{color: 'pink'}}></div> :
                    <div style={{color: '#ff0'}}>其他</div>
            }
        </div>
    ))

3.循环渲染

    let students = [
        {
            name: '张三',
            sex: 'male',
            age: 17
        },
        {
            name: '李四',
            sex: 'female',
            age: 24
        },
        {
            name: '隔壁老王',
            sex: 'other',
            age: 30
        },
    ]

    ReactDOM.createRoot(document.querySelector('#root')).render((
        <div>
            <ul>
                {/* 循环渲染,使用一个数组的map函数 返回一个由 react-dom 充当成员形成的一个新数组 */}
                {students.map(item => <li>姓名: {item.name}; 性别: {item.sex === 'male' ? '男' :
                    item.sex === 'female' ? '女' : '不详'
                }; 年龄: {item.age}</li>)}
            </ul>
        </div>
    ))

(三)组件

组件是一个具备独立显示内容,独立维护状态,被当作标签使用的可复用模组
特点
1.独立显示的页面内容
2.独立维护的组件状态
3.组件被当作标签使用
应用场景:可复用的页面内容,就可以考虑封装成组件

1.声明组件

类组件
声明类组件需要继承React.Component

    class AComponent extends React.Component {

        // 可以有组件的属性
        label = 'h'

        // 构造函数中包含props参数
        // props 代表组件的 html 属性
        // props 是只读属性
        constructor(props) {
            // 由于存在父类 React.Component
            // 所以构造函数中应先调用super
            super(props)

            // render 函数中可以使用 this.props 访问此处的 props
            console.log(props)
            // 可以使用 props.children 代表组件标签体里的内容
            console.log(props.children)
        }

        // 可以有组件方法
        getTime() {
            return new Date()
        }

        // 类组件中必须包含 render 方法
        render() {
            // render 方法必须返回一个 react-dom 对象
            // 返回的 react-dom 对象用于描述组件长什么样子的
            return (
                <div>
                    {/* 组件中可以调用自己的属性和方法 */}
                    {this.label}: {this.getTime().getHours()}; m: {this.getTime().getMinutes()};
                    s: {this.getTime().getSeconds()}
                    <br/>
                    {/* 标签体的内容可以插值到 render 中 */}
                    {this.props.children}
                </div>
            )
        }
    }

函数组件

    function BComponent(props) {

        // 此处的this为 undefined
        // 之所以为 undefined 是因为函数组件没有实例对象
        console.log(this)
        console.log(props)

        // 可以在组件内声明其他函数和变量
        let count = 0

        function getCount() {
            return count
        }

        // 函数组件必须返回一个react-dom对象
        return (
            <div>
                <div>我是一个函数组件</div>
                <div>{count}: {getCount()}</div>
                <div>{props.children}</div>
            </div>
        )
    }

2.组件状态

通常指某个时刻用于描述某个对象的数据模型
class组件状态
组件的状态更新:this.setState

1.不要直接修改state,要通过setState修改
2.setState的参数不要直接依赖this.State或者this.props,应使用this.setState((state,props)=>{return{}})代替
3.setState方法是异步的,可以通过setState的第二个回调函数来执行复制成功后的代码
4.setState最终会修改this.state

若不存在组件时 更新数据的办法是 重复调用 root.render 函数
函数组件状态
在函数组件内使用 React.useState 来声明状态
useState 参数代表状态的初始值,返回值是一个数组
0 号成员是 状态的 getter 用来读取状态
1 号成员是 状态的 setter 用来赋值状态
setState 是异步的
setState 依赖自己状态的时候,使用回调函数
状态值若为对象(或数组)时,为了状态能够被修改,需要赋值一个新的对象(或数组)

3.组件生命周期

生命周期
用函数来描述对象的生老病死
阶段

生命周期有哪些阶段

  • 挂载
    constructor()
    static getDerivedStateFromProps() // https://zh-hans.reactjs.org/docs/react-component.html#static-getderivedstatefromprops
    render()
    componentDidMount()
  • 更新
    static getDerivedStateFromProps(props, state)=>{[key: string]: any} 每次调用渲染函数render前调用,返回值是希望改变的状态对象
    shouldComponentUpdate(props, state)=>boolean 判断是否应该更新,返回一个布尔值
    render()
    getSnapshotBeforeUpdate(prevProps, prevState)=>{[key: string]: any} 每次更新前调用,返回值将被传递给 componentDidUpdate 充当第三个参数
    componentDidUpdate(prevProps, prevState, snapshot)
  • 卸载
    componentWillUnmount()
  • 异常捕获
    static getDerivedStateFromError()
    componentDidCatch()

应用场景
其中 挂载和卸载的 生命周期用得比较多
constructor() 常用于初始化组件,拉取远程数据
componentDidMount() 用于页面第一次渲染完成后,查询页面元素
componentWillUnmount() 卸载组件时对事件的解绑等需要处理的事
卸载组件
root.unmount()

4.事件

绑定事件的基本流程:
​ 1.on+事件名称
​ 2.使用花括号插值一个事件处理程序
​ 3.获取事件对象
​ 4.给事件处理程序传参
react 中 无法使用 return false 直接屏蔽默认事件
class组件绑定事件
类组件中普通的事件绑定无法在事件处理程序中访问this关键字
若想希望在绑定的事件函数中使用 this 来访问组件自身
则需要在类组件的事件处理程序里赋值this关键字:
​ 1.constructor 中使用 bind
​ 2.在绑定事件插值时使用箭头函数
​ 3.在绑定事件插值时使用bind

  • 方法1:constructor 中使用 bind
constructor(props) {
	super(props);
	this.clickHandler = this.clickHandler.bind(this)
}

clickHandler(ev) {
	console.log('click')
	console.log(ev)
	console.log(this)
	this.setState(state => ({count: state.count + 1}))
}

<button onClick={this.clickHandler}>点击</button>
  • 方法2:在绑定事件插值时使用箭头函数
clickHandler(ev) {
	console.log('click')
	console.log(ev)
	console.log(this)
	this.setState(state => ({count: state.count + 1}))
}

<button onClick={ev => {this.clickHandler(ev)}}>点击</button>
  • 方法3:在绑定事件插值时使用bind
clickHandler(ev) {
	console.log('click')
	console.log(ev)
	console.log(this)
	this.setState(state => ({count: state.count + 1}))
}

<button onClick={this.clickHandler.bind(this)}>点击</button>

函数组件绑定事件

/* 在标签添加事件 */
<button onContextMenu={contextMenuHandler}>点击</button>

/* 使用箭头函数在调用事件处理程序的时候传递参数 */
<button onContextMenu={ev => {contextMenuHandler(ev, 5)}}>点击</button>

/* react 无法直接通过 return false 屏蔽默认事件 */
<form onSubmit="return false">
	<button>提交</button>
</form>
 /* 事件函数 */
//事件处理程序添加参数ev,ev代表事件对象
function contextMenuHandler(ev, id) {
// 屏蔽默认事件
     ev.preventDefault()
     console.log('contextMenuHandler')
     console.log(ev)
     console.log(id)
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值