框架前置课笔记

一.AJAX阶段

AJAX是异步的JavaScript和XML(Asynchronous JavaScript And XML)。
XML可扩展标记语言,被设计用来传输和存储数据,现已经被JSON取代了。
简单点说,就是使用XMLHttpRequest对象与服务器通信。
通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据
优点
(1)可以无需刷新页面而与服务器端进行通信
(2)允许你根据用户时间来更新部分页面内容
缺点:
(1)没有浏览历史,不能回退
(2)存在跨域问题(同源)
(3)SEO不友好

请求报文

响应报文

1.axios

1.1 axios入门案例

	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <p class="my-p"></p>
    <script>
        axios({
            url: 'http://hmajax.itheima.net/api/province'

        }).then(result=>{
            document.querySelector('.my-p').innerHTML=result.data.list.join('<br>');
            
        })
    </script>

1.2 url:协议、域名、资源路径

url查询参数:语法:http://xxx.com/xxx/xxx?参数名1=值1&参数名2=值2

	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <p class="my-p"></p>
    <script>
        axios({
            url: 'http://hmajax.itheima.net/api/area',
            params:{
                pname: '江西省',
                cname: '九江市'
            }

        }).then(result=>{
            document.querySelector('.my-p').innerHTML=result.data.list.join('<br>');
            
        })
    </script>

常用请求方法和数据提交
GET:获取数据
POST:提交数据
PUT:修改数据
DELETE:删除数据
PATCH:修改数据(部分)

1.3 数据提交

场景:当数据需要在服务器上保存时

注册数据提交

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <button>注册</button>
    <script>
        document.querySelector('button').addEventListener('click',()=>{
            axios({
            url: 'http://hmajax.itheima.net/api/register',
            method: 'post',
            data: {
                username: 'hekdkfksd',
                password: '23145325132'
            }

        }).then(result=>{
            console.log(result);            
        })
        })
       
    </script>

1.4 axios的核心配置:

url,data,method,params

1.4.1 GET
axios({
	url: 'XXXX'.
	method: 'GET',      //可以省略
	params: {        //携带查询参数
		参数名: 值
	}
})
1.4.2POST
axios({
	url: 'XXXX'.
	method: 'POST',     
	data: {        /
		参数名: 值
	}
})

1.5 axios错误处理

语法:在then方法的后面,通过点语法调用catch方法,传入回调函数并定义形参

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <button>注册</button>
    <script>
        document.querySelector('button').addEventListener('click',()=>{
            axios({
            url: 'http://hmajax.itheima.net/api/register',
            method: 'post',
            data: {
                username: 'hekdkfksd',
                password: '23145325132'
            }

        }).then(result=>{
            console.log(result);             
        }).catch(error => {           //错误处理
            console.log(error);
            alert(error.response.data.message);
        })
        })
       
    </script>

1.6 HTTP协议

HTTP协议:规定了浏览器发送及服务器返回内容的格式

1.6.1 请求报文

请求报文的组成部分有:
1.请求行:请求方法,URL,协议
2.请求头:以键值对的格式携带的附加信息
3.请求体:发送的资源

可以通过查看请求报文来进行排错

请求头
在这里插入图片描述
请求体:
在这里插入图片描述

1.6.2 响应报文

响应报文的组成:
1.响应行(状态行):协议,HTTP响应状态码,状态信息
2.响应头:以键值对的格式携带的附加信息,比如:Content-Type
3.响应体:返回的资源

状态码:
1XX:信息
2XX: 成功
3XX:重定向信息
4XX:客户端错误
5XX: 服务端错误
比如:404(服务端找不到资源)

响应头:
在这里插入图片描述
响应体:
在这里插入图片描述

1.7接口文档

由后端提供的描述接口的文档
FD

黑马接口文档

登录:
在这里插入图片描述
Body参数=>data里面的参数
application/json表明传的是json字符串,但是在data中的键值对会自动转换成json字符串

登录案例

<input type="text" class="username"> <br>
    <input type="password" class="password"><br>
    <button>登录</button>
    <script>
        document.querySelector('button').addEventListener('click',
        ()=>{
            username = document.querySelector('.username').value;
            password = document.querySelector('.password').value;
            if(username.length<8){
                alert('用户名需不小于8位');
                return;
            }
            if(password.length<6){
                alert('密码需不小于6位');
                return;
            }
            axios({
                url: 'https://hmajax.itheima.net/api/login',
                method: 'post',
                data: {
                    username,
                    password
                }
            }).then(response=>{
                console.log(response.data.message);
            }).catch(error=>{
                console.log(error.response.data.message);
            })
        })
       
    </script>

2.AJAX原理

XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL。这允许网页在不影响用户操作的情况下,更新页面的局部内容。
axios内部采用XMLHttpRequest与服务器交互

2.1XMLHttpRequest对象实例

	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

    <script>
        //1.创建xhr对象
        const xhr = new XMLHttpRequest();
        //2.调用open方法,设置url和请求方法
        xhr.open('get','https://hmajax.itheima.net/api/province');
        //3.监听loadend事件,接收结果
        xhr.addEventListener('loadend',()=>{
            console.log(xhr.response)
            //将JSON字符串转化成JS对象
            const data=JSON.parse(xhr.response)
            console.log(data.list);
        })
        //调用send方法,发送请求
        xhr.send()
    </script>

XMLHttprRequest查询参数: xhr.open('get','https://hmajax.itheima.net/api/city?pname=河北省');

2.2XMLHttpRequest数据提交

请求头设置Content-Type:application/json
请求体携带JSON字符串

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

    <script>
        const xhr = new XMLHttpRequest();
        xhr.open('post','https://hmajax.itheima.net/api/register');
        xhr.addEventListener('loadend',()=>{
            console.log(xhr.response);
        })
        //设置请求头
        xhr.setRequestHeader('Content-Type','application/json');
        const userObj = {
            username: 'hk666666',
            password: '123456'
        }
        //将对象转换成JSON字符串
        const userStr = JSON.stringify(userObj);
        xhr.send(userStr)
    </script>

2.3promise

表示(管理)一个异步操作最终状态和结果值的对象
优点:
1.逻辑更清晰
2.了解axios函数内部运作机制
3.能解决回调函地狱问题

resolve(value):

当异步操作成功完成时,调用 resolve 函数,并传递操作的结果或值作为参数。这会将 Promise 对象的状态从 “Pending”(进行中)改变为 “Fulfilled”(已成功)状态。在 .then() 方法中注册的回调函数将会被执行,并且可以访问到传递给 resolve 函数的值。

reject(reason):

当异步操作遇到错误或失败时,调用 reject 函数,并传递一个错误原因作为参数。这会将 Promise 对象的状态从 “Pending”(进行中)改变为 “Rejected”(已失败)状态。在 .catch() 方法中注册的回调函数将会被执行,并且可以访问到传递给 reject 函数的错误原因。

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

    <script>
        //1.创建Promise对象
        const p = new Promise((resolve,reject) => {
            //2.执行异步代码
            setTimeout(()=>{
                // resolve('模拟AJAX请求成功')
                reject(new Error('模拟AJAX请求失败'))
            },2000)
        })
        //3.获取结果
        p.then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error)
        })
    </script>

也可以都放到then中:

<script>
          //1.创建Promise对象
          const p = new Promise((resolve, reject) => {
              //2.执行异步代码
              setTimeout(() => {
                //   resolve('模拟AJAX请求成功')
                  reject(new Error('模拟AJAX请求失败'))
              }, 2000)
          })
          //3.获取结果
          p.then(result => {
              console.log(result);
          },error => {
            console.log(error)
          })
</script>

同步代码和异步代码
同步代码:逐行执行,需原地等待结果后,才继续向下执行
异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数

回调函数地狱:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
缺点:可读性差,异常无法捕获,耦合性严重

2.4async函数和await

async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需可以地链式调用promise
async 的全称是 Asynchronous,发音是 /əˈsɪŋkrənəs/

	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <div class="province"></div>
    <div class="city"></div>
    <div class="area"></div>

    <script>
        //函数前加async
        async function getData(){
            //try包裹可能产生错误的代码
            try{
                    //在promise对象前加await
                const pObj=await axios({url:'https://hmajax.itheima.net/api/province'})
                pname = pObj.data.list[0]
                const cObj=await axios({url:'https://hmajax.itheima.net/api/city',params:{
                    pname}})
                cname = cObj.data.list[0]
                const aObj=await axios({url:'https://hmajax.itheima.net/api/area',params:{
                    pname,cname
                }})
                aname = aObj.data.list[0]
                document.querySelector('.province').innerHTML=pname
                document.querySelector('.city').innerHTML=cname
                document.querySelector('.area').innerHTML=aname
            }catch(error){
                //接着调用catch块,接收错误信息
                console.dir(error)
            }
        }
        getData()
    </script>

2.5事件循环

执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环
原因:JS是单线程的,为了不阻塞JS引擎,设计执行代码的模型
执行流程
1.执行同步代码,遇到异步代码交给宿主浏览器环境执行
2.异步有了结果后,把回调函数放入任务队列排队
3.当调用栈空闲时,反复调用任务队列里的回调函数

宏任务与微任务
在这里插入图片描述
在这里插入图片描述
微任务队列比宏任务队列更先执行
p.then()本身是同步的,但里面的回调函数是异步的,且只有等p有了成功的状态,状态改变之后才会将回调函数推到微任务队列中去
p.then(result=>{
console.log(result);
})

执行流程:
(1)执行第一个script脚本事件宏任务里面的同步代码
(2)遇到宏任务/微任务交给宿主环境,有结果回调函数进入对应队列
(3)当执行栈空闲时,先清空微任务队列,再执行下一个宏任务,从1再来

Promise.all静态方法
Promise.all 是一个静态方法,它接收一个可迭代的对象(比如数组)作为参数,并返回一个新的 Promise 对象。这个新的 Promise 对象在传入的所有 Promise 对象都已经解决(resolved)时才会解决。如果传入的任何一个 Promise 被拒绝(rejected),那么 Promise.all 返回的 Promise 对象会立即被拒绝,其拒绝原因是第一个被拒绝的 Promise 的拒绝原因。

二 .Node.js

Node.js是一个跨平台JS运行环境,使开发者可以搭建服务器端的JS应用程序
作用:使用Node.js编写服务器端程序
(1)编写数据接口,提供网页资源浏览功能等等
(2)前端工程化:为后续学习Vue和React等框架做铺垫
**前端工程化:**开发项目直到上线,过程中集成的所有工具和技术,有打包工具、格式化工具、压缩工具、转换工具、脚手架工具等等

Node.js为何能执行JS:
首先:浏览器能执行JS代码,依靠的是内核中的V8引擎(c++程序)
其次:Node.js是基于Chrome V8引擎进行封装
注意: Node.js环境没有DOM和BOM,取而代之的是fs和path

Node.js运行js文件

在这里插入图片描述

fs模块-读写文件

const fs = require('fs')
fs.writeFile('./test.txt','Hello World!',(err)=>{
    if(err) console.log(err)
    else console.log('写入成功');
})
fs.readFile('./test.txt',(err,data)=>{
    if(err) console.log(err)
    //这里返回的data是十六进制的序列
    else console.log(data)
    //通过toString()方法转成字符串
    // else console.log(data.toString())
})

path模块-路径处理

在Node.js代码中,相对路径是根据终端所在路径来查找的
建议:使用绝对路径

说明: path_test.js在path_test文件夹下,需要访问的test.txt与path_test文件夹同级

const fs = require('fs')
const path = require('path')
//__dirname的输出结果为  C:\Users\12345\Desktop\js\path_test
//console.log(__dirname);
fs.readFile(path.join(__dirname,'../test.txt'),(err,data)=>{
    if(err) console.log(err)
    else console.log(data.toString())
})

压缩前端html

步骤:
(1)读取源html文件内容
(2)正则替换字符串
(3)写入到新的html文件中

去掉html中的\t\n
在这里插入图片描述

const { log } = require('console');
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname,'../index.html'),(err,data)=>{
    if(err) console.log(err);
    else{
        const htmlStr = data.toString();
        const resultStr = htmlStr.replace(/[\r\n]/g,'')
        console.log(resultStr);
        fs.writeFile(path.join(__dirname,'../result.html'),resultStr,err=>{
            if(err) console.log(err);
            else console.log('写入成功');
        })
    }
})

编写Web服务程序

端口号:标记服务器里不同功能的服务程序
范围:0-65535之间的任意整数
0-1023和一些特定端口号被占用,我们自己编写服务程序时避开使用
http协议默认访问80端口
web服务程序:用于提供网上信息浏览功能

http模块-创建Web服务

//加载http模块,创建Web服务对象
const http = require('http')
const server = http.createServer()
//监听request请求事件,设置响应头和响应体
server.on('request',(req,res)=>{
    //设置响应头-内容类型-普通文本以及编码格式
    res.setHeader('Content-Type','text/plain;charset=utf-8')
    //设置响应体内容,结束本次请求与响应
    res.end('欢迎使用node.js创建的Web服务')
})
//配置端口号并启动Web服务
server.listen(3000,()=>{
    console.log('Web服务已启动');
})

web服务程序提供html网页案例

const fs = require('fs')
const path = require('path')
const http = require('http')
const server = http.createServer()
//监听request请求事件,设置响应头和响应体
server.on('request',(req,res)=>{
    if(req.url==='/index.html'){
        fs.readFile(path.join(__dirname,'index.html'),(err,data)=>{
            if(err) console.log(err)
            else{
                res.setHeader('Content-Type','text/html;charset=utf-8')
                res.end(data.toString())
            }
        })
    }
    else{
        res.setHeader('Content-Type','text/html;charset=utf-8')
        res.end('访问的数据不存在')
    }
})
//配置端口号并启动Web服务
server.listen(3000,()=>{
    console.log('Web服务已启动');
})

Node.js模块化

在Node.js中,每个文件都被视为一个单独的模块
项目是由很多个模块文件组成的
使用:需要标准语法导出和导入进行使用

CommonJS语法-导入导出模块语法:
被导出模块:

// baseURL和getArraySum是需要对外暴露的两个属性
const baseURL='http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
//使用基于CommonJS标准语法,封装属性和方法并导出
module.exports = {
    url: baseURL,
    arraySum: getArraySum
}

导入模块:

const obj = require('./utils.js')
const result = obj.arraySum([2,3,45,52,23])
console.log(result);

ECMAScript标准-默认导出和导入
(1)默认被导出模块:

// baseURL和getArraySum是需要对外暴露的两个属性
const baseURL='http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
//默认导出
export default {
    url: baseURL,
    arraySum: getArraySum
}

(2)package.json

{
    "type": "module"
}

(3)需导入模块

import obj from './utils.js'
console.log(obj)

ECMAScript标准-命名导出和默认导出
如何选择:
按需加载,使用命名导出和导入
全部加载:使用默认导出和导入
utils.js:

export const baseURL='http://hmajax.itheima.net'
export const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)

01.js:

import {baseURL,getArraySum} from './utils.js'
console.log(baseURL,getArraySum)

包的概念

包:将模块、代码、其他资料聚合成一个文件夹

包分类:
项目包:主要用于编写项目和业务逻辑
软件包:封装工具和方法进行使用
要求:根目录中,必须有package.json文件(记录包的清单信息)
注意:导入软件包时,引入的默认是index.js模块文件/main属性指定的模块文件

目录结构
(1)04文件夹下有utils文件夹和server.js文件
(2)utils文件夹下有lib文件夹和index.js
(3)lib文件夹有最终的arr.js和str.js文件
流程
(1)在index.js中将arr.js和str.js导入,最后统一导出所有函数
(2)server.js文件导入utils软件包,使用里面封装的工具函数

//arr.js
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
module.exports={
    getArraySum
}

//str.js
const checkUserName = username => {
    return username.length >=8
}
const checkPassWord = password => {
    return password.length >=6
}
module.exports = {
    checkUser: checkUserName,
    checkPwd:   checkPassWord
}

//index.js
//本文件是tuils工具包的唯一出口
//作用:把所有工具模块方法集中起来,统一向外暴露
const {getArraySum} = require('./lib/arr.js')
const {checkUser,checkPwd} = require('./lib/str.js')

//统一导出所有函数
module.exports = {
    getArraySum,
    checkUser,
    checkPwd
}

//server.js
// 目标:导入utils软件包,使用里面封装的工具函数
const obj = require('./utils')
console.log(obj)
console.log(obj.getArraySum([23,532,234]))

npm-软件包管理器

npm是Node.js标准的软件包管理器
在这里插入图片描述

使用npm下载dayjs软件包来格式化日期时间

步骤:
(1)初始化项目清单文件,命令:npm init -y
在这里插入图片描述

(2)下载软件包到当前项目,命令:npm i dayjs
在这里插入图片描述

(3)使用软件包

//server.js文件:
//使用软件包
const dayjs = require('dayjs')
console.log(dayjs().format('YYYY-MM-DD'));

在这里插入图片描述

npm安装所有依赖

场景:当从网上下载了一个项目,项目中不包含node_modules所以不能运行。
之所以不包含node_modules是 因为自己用npm下载依赖比磁盘传递拷贝要快得多
解决办法:项目终端输入命令: npm i 下载package.json中记录的所有软件包

npm-全局软件包nodemon

本地软件包:当前项目内使用,封装属性和方法,存在与node_modules
全局软件包:本机所有项目使用,封装命令和工具,存在与系统设置的位置
nodemon作用:替代node命令,检测代码更改,自动重启程序
nodemon的安装:npm i nodemon -g

三.Webpack

Webpack中文文档
webpack是一个用于现代JS应用程序的静态模块打包工具。
静态模块指的是编写代码过程中的html、css、js图片等固定内容的文件
打包:把静态模块内容,压缩,整合,转译等(前端工程化)

webpack体验
(1)npm init -y 初始化package.json文件
在这里插入图片描述
(2)在package.json中配置webpack

在这里插入图片描述(3)编写check.js

export const checkPhone = phone => phone.length === 11
export const checkCode = code => code.length === 6

(4)npm i webpack webpack-cli --save-dev (准备webpack打包环境)
在这里插入图片描述
(5)index.js中导入check.js里封装的属性和函数

import {checkPhone,checkCode} from './utils/check.js'
console.log(checkPhone('1347329324'))
console.log(checkCode('234234'));

(6)运行自定义命令打包观察效果(npm run 自定义命令),得到dist文件夹
在这里插入图片描述

修改Webpack打包入口和出口

Webpack打包入口默认是src/index.js 出口默认的是dist/main.js
修改步骤:

(1)在项目根目录下新建webpack.config.js配置文件
在这里插入图片描述
(2)导出配置对象,配置入口、出口文件路径

const path = require('path')

module.exports = {
    //入口
    entry: path.resolve(__dirname,'src/login/index.js'),
    //出口
    output: {
        path: path.resolve(__dirname,'dist'),
        filename: './login/index.js',
        clean: true //生成打包后内容之前,清空输出目录
    }
}

(3)使用 npm run 自定义命令 打包观察
在这里插入图片描述

Webpack自动生成html文件

(1)下载html-webpack-plugin本地软件包
在这里插入图片描述
(2)配置webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    //入口
    entry: path.resolve(__dirname,'src/login/index.js'),
    //出口
    output: {
        path: path.resolve(__dirname,'dist'),
        filename: './login/index.js',
        clean: true //生成打包后内容之前,清空输出目录
    },
    plugins: [
        new HtmlWebpackPlugin({
            //模版文件
          template: path.resolve(__dirname,'./public/login.html'),
          filename: path.resolve(__dirname,'dist/login/index.html')
        })
    ]
}

(3)重新打包观察

webpack打包css代码

使用css-loader、style-loader来完成
(1)准备css代码,并引入到js中
(2)下载css-loader和style-loader本地软件包
(3)配置webpack.config.js,让webpack拥有该加载器功能

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

(4)打包观察效果

优化-提取css代码

使用mini-css-extract-plugin来提取css代码
style-loader和mini-css-extract-plugin不能一起用
(1)下载mini-css-extract-plugin本地软件包
(2)配置webpack.config.js让webpack拥有该插件功能

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
};

(3)打包后观察效果

优化-压缩过程

问题:css代码提取后没有压缩
解决:使用css-minimizer-webpack-plugin插件

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
       `...`,
      new CssMinimizerPlugin(),
    ],
  },
};

webpack打包less代码

加载器less-loader:把less代码编译为css代码
(1)新建less代码并引入到src/login/index.js中
(2)下载less和less-loader本地软件包

npm install less less-loader --save-dev

(3)配置webpack.config.js

 {
        test: /\.less$/i,
        use: [
          // compiles Less to CSS
          MiniCssExtractPlugin.loader,           
          'css-loader',
          'less-loader',
        ],
      },

webpack打包图片

资源模块:webpack5内置资源模块(字体、图片等)打包,无需额外loader
注意: 判断临界值默认为8KB,当大于8KB时,发送一个单独的文件并导出URL地址,
当小于8KB时,导出一个data URI(base64字符串)
步骤:
(1)配置webpack.config.js让Webpack拥有打包图片功能

module.exports = {
	module: {
        rules: [
            {
                test: /\.(png|jpg|jpeg|gif)$/i,
                type: 'asset,
                generator: {
                    filename: 'assets/[hash][ext][query]'
                }
            }
        ] 
	}
};

优化-CDN使用

CDN定义:内容分发网络,指的是一组分布在各个地区的服务器
作用:把静态资源文件、第三方库放在CDN网络中各个服务器中,供用户就近请求获取
需求:开发模式使用本地第三方库,生产模式下使用CDN加载引入

webpack搭建开发环境

问题:之前改代码,需重新打包才能运行查看,效率低
开发环境:配置webpack-dev-server快速开发应用程序
作用:启动web服务,自动检测代码变化,热更新到网页

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值