node笔记

node基于chrome的v8引擎的运行环境

下载安装node.js
LTS是 稳定版
Current是 实验板

模块化

module.exports和exports是一样的地址引用关系
但是已module.exports为准

第一种方式
const add = (n1,n2)=>n1+n2;
const num = 123;
exports.add = add;
exports.num = num;



const something = require('./xxx')
something.add(10,20)
something.add(something.num,50)




第二种方式
const greething = name => `hello${name}`;
module.exports.greething = greething;

const a = require('./module');
console.log(a.greething('李四'));

系统模块 node为错误优先

fs模块 文件操作

const fs = require('fs')

读取
fs.readFile('路径',['编码'],callback)
fs.readFile('./module.js','utf-8',(err,res)=>{
  console.log(err);
  console.log(res);
})



写入 使用场景为错误日志 如果没有目标文件则会创建
fs.writeFile('文件路径','数据',callback)

const str = `<h2>写入的数据</h2>`
fs.writeFile('./test.html', str, err => {
  if (err != null) {
    console.log(err);
    return
  }

  console.log("写入成功");
})

path模块 路径操作

windows 正斜杠反斜杠都可以的
Windows \ /
Linux	/

path.join('路径','路径',...)

const path = require('path')
let testPath = path.join("public","uploads","avatar")

绝对路径相对路径 __dirname

__dirname拿到当前目录的绝对路径


__dirname拿到当前目录的绝对路径


const path = require('path')
const fs = require('fs')

fs.readFile(path.join(__dirname,"index.js"), 'utf-8', (err, res) => {
  console.log("我是err",err);
  console.log("我是res",res);
})
console.log("我是pathjoin的结果",path.join(__dirname,"index.js"));
console.log("我是当前绝对路径",__dirname);

模块 全局安装 本地安装 nodemon nrm换源

npm install axios
npm uninstall axios


一般命令行会用全局安装
npm install nodemon -g
nodemon index.js

npm install nrm -g
查询 nrm ls
切换 nrm use 下载地址名称

开发依赖 项目依赖 命令别名

gulp不需要在项目依赖里所以下载时
npm i gulp --save-dev


开发环境 npm i 会下载所有依赖
运行依赖 npm i --production 只下载生产环境



命令别名
在scripts里新建
"别名" : "原名"

网站服务器 http协议

搭建基础

//引用系统模块 用于创建网站服务器的模块
const http = require('http');

//http.createServer()返回值为网站服务器对象
const app = http.createServer();

//事件驱动 所以添加事件  res == response响应
app.on('request',(req,res)=>{
  res.end('<h2>hello user</h2>')
})


app.listen(3000)
console.log("网站服务器启动成功");

判断不同的请求方式req.method

后台

//引用系统模块 用于创建网站服务器的模块
const http = require('http');

//http.createServer()返回值为网站服务器对象
const app = http.createServer();

//事件驱动 所以添加事件  res == response响应
app.on('request', (req, res) => {
  //获取前台的请求方式
  console.log(req.method);

  res.end('<h2>hello user</h2>')
})


app.listen(3000)
console.log("网站服务器启动成功");

前台

<body>
  <form method="POST" action="http://localhost:3000">
    <input type="submit">
  </form>
</body>

判断

//引用系统模块 用于创建网站服务器的模块
const http = require('http');

//http.createServer()返回值为网站服务器对象
const app = http.createServer();

//事件驱动 所以添加事件  res == response响应
app.on('request', (req, res) => {
  //获取前台的请求方式
  console.log(req.method);
  if(req.method == "POST"){
    res.end("post")
  }else if(req.method == "GET"){
    res.end("get")
  }

  // res.end('<h2>hello user</h2>')
})


app.listen(3000)
console.log("网站服务器启动成功");

判断不同的请求地址req.url 需用url.parse处理

请求什么都不写那么就是 /

let {query,pathname} = url.parse(req.url,true)

//引用系统模块 用于创建网站服务器的模块
const http = require('http');

//http.createServer()返回值为网站服务器对象
const app = http.createServer();

//事件驱动 所以添加事件  res == response响应
app.on('request', (req, res) => {
    
    
  //获取前台的请求地址
  console.log(req.url);
  这里获取的是带get请求参数的请求地址
  所以需要用url模块进行处理
	    
    
    
    
  if(req.url == "/index" || req.url == "/"){
    res.end("welcome to homepage")
  }else if(req.url == "/list"){
    res.end("welcome to list")
  }else{
    res.end("not found")
  }

  
  res.end('<h2>hello user</h2>')
})


app.listen(3000)
console.log("网站服务器启动成功");

请求报文 响应报文 状态码 end内容类型

console.log(req.headers);
console.log(req.headers["accept"]);


		状态码
		
200请求成功
404请求的资源没有被找到
500服务器端错误
400客户端请求有语法错误

const http = require('http');
const app = http.createServer();
app.on('request', (req, res) => {
  
  res.writeHead(200)      //这里设置返回码

  if(req.url == "/index" || req.url == "/"){
    res.end("welcome to homepage")
  }else if(req.url == "/list"){
    res.end("welcome to list")
  }else{
    res.end("not found")
  }
})


app.listen(3000)
console.log("网站服务器启动成功");






		内容类型
test/html
text/css
text/plain 纯文本
application/javascript
image/jpeg
application/json


const http = require('http');
const app = http.createServer();
app.on('request', (req, res) => {
  
  res.writeHead(200,{
    "content-type":"text/html;charset=utf-8",  //设置请求头
  })

  console.log(req.headers["accept"]);
  //获取前台的请求地址
  console.log(req.url);
  if(req.url == "/index" || req.url == "/"){
    res.end("<h1>你好</h1>")
  }else if(req.url == "/list"){
    res.end("welcome to list")
  }else{
    res.end("not found")
  }
})


app.listen(3000)
console.log("网站服务器启动成功");

请求参数

GET请求参数
提供了一个内置模块 用于处理url地址
const url = require('url')

url.parse(req.url)	//会把链接返回成一个对象 处理数据

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?name=zhangsan$age=20',
  query: 'name=zhangsan$age=20',
  pathname: '/index',
  path: '/index?name=zhangsan$age=20',
  href: '/index?name=zhangsan$age=20'
}

//第一个参数要解析的url地址
//第二个参数将查询参数解析成对象形式
url.parse(req.url,true)

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?name=zhangsan&age=20',
  query: [Object: null prototype] { name: 'zhangsan', age: '20' },
  pathname: '/index',
  path: '/index?name=zhangsan&age=20',
  href: '/index?name=zhangsan&age=20'
}



			所以
			
  //获取前台的请求地址
  console.log(req.url);
  //前台的请求参数
  console.log(url.parse(req.url,true).query);
  
  
  
			解构写法

const http = require('http');
const app = http.createServer();
const url = require('url')
app.on('request', (req, res) => {

  res.writeHead(200,{
    "content-type":"text/html;charset=utf-8",
  })

  //获取前台的请求地址
  console.log(req.url);
  let {query,pathname} = url.parse(req.url,true)
  console.log(query);
  console.log(pathname);

  if(pathname == "/index" || pathname == "/"){
    res.end("<h1>你好</h1>")
  }else if(pathname == "/list"){
    res.end("welcome to list")
  }else{
    res.end("not found")
  }
})

app.listen(3000)
console.log("网站服务器启动成功");


POST请求参数
const http = require('http');
const app = http.createServer();
//处理请求参数数据 而不是链接+参数数据
const querystring = require('querystring')

app.on('request', (req, res) => {
  //post参数是通过事件的方式接受的
  //data 传递时
  //end 传递完成
  //post不是一下传递的是分好几次接收的

  let postParams = "";

  req.on('data',(params)=>{ //post不是一下传递的是分好几次接收的
    postParams += params  //这里做拼接
  })
  req.on('end',()=>{
      		有一个系统模块转换 接受的值querystring
    console.log(querystring.parse(postParams)); //这里返回的就是对象了
  })

  //要做出响应否则会处于等待状态
  res.end("ok")

})

app.listen(3000)
console.log("网站服务器启动成功");
end一些api
重定向 转跳
res.write(301,{
	location:"/list"
})
res.end()

路由

const http = require('http');
const app = http.createServer();
const url = require('url')


app.on("request",(req,res)=>{

  //请求方式
  const method = req.method.toLowerCase();
  //请求地址
  const pathname = url.parse(req.url).pathname;
  //报文设置
  res.writeHead(200,{
    "content-type":"text/html;charset=utf8"
  })

  if(method == "get"){

    if(pathname == "/" || pathname == "/index"){
      res.end("首页")
    }else if(pathname == "/list"){
      res.end("列表页")
    }else{
      res.end("not found")
    }

  }else if(method == "post"){



  }

})


app.listen(3000)
console.log("启动成功");

静态 动态资源

const http = require('http');
const url = require('url')
const path = require("path")
const fs = require('fs');
const mime = require('mime')

const app = http.createServer();


app.on("request",(req,res)=>{

  let pathname = url.parse(req.url).pathname;

  //什么都不输入也是默认为index.html
  pathname = pathname == "/" ? "/index.html" : pathname;

    //将请求路径转化为硬盘路径
  let realpath = path.join(__dirname,"public",pathname)

    //mime动态改变请求
  let type = mime.getType(pathname);

  fs.readFile(realpath,(error,result)=>{

    if(error != null){
      res.writeHead(404,{
        "content-type":"text/html;charset=utf-8"
      })
      res.end("不存在的路径");
      return;
    }


    //这里输出的是html主文件 而主文件里又有不同的外链接
    //可能是css,jpg,video 所以不能写死
    //所以需要一个库npm i mime
    //新版浏览器不需要,旧版可能会出问题
    res.writeHead(200,{
      "content-type":type
    })
    res.end(result);
  })

})


app.listen(3000)
console.log("启动成功");

异步 同步的概念

有两种方式

接受返回值
const publicPath = path.join(_dirname,"public");
const urlObj = url.parse(req.url);

使用函数
fs.readFile(publicPath,(error,result)=>{
	console.log(result);
})

同步api可以从返回值拿到api的执行结果,异步的不可以

fuction sum(n1,n2){
	return n1+n2;
}
var result = sum(10,20);    //这里可以通过返回值拿到相加结果30


	异步
function sum2(n1,n2) { 
  setTimeout(() => {
    return "helloword";
  }, 2000);
 }
var b = sum2()
console.log(b);

回调函数

function sum2(cb) {     //不能通过return只能通过回调函数
  setTimeout(() => {
    cb({
      msg: "hello"
    })
  }, 2000);
}
sum2((n) => { console.log(n) })


node里的读取文件之类的用的就是回调函数
function sum2(cb) {
  setTimeout(() => {
    cb({
      msg: "hello"
    })
  }, 2000);
}
sum2((n) => {
  console.log("我是n", n)
  //修改对象
  n.msg = "修改完毕"
  console.log("改了",n);
})         


	如
fs.readFile("./demo.txt" , (err.result) => {})

执行顺序
先执行同步,在执行异步执行

同步代码执行区域 异步代码执行区域

			回调函数队列

先同步 遇到异步就放到异步执行区
等同步执行完毕在执行异步代码
异步执行完一条就给回调 回调到同步区

回调地狱

后面的异步需要前面异步的结果


回调嵌套在嵌套 回调地狱
就是一层回调在嵌套一层回调 不易维护
fs.readFile("./1.txt", "utf-8", (err, result1) => {
  console.log(result1);
  fs.readFile("./2.txt", "utf-8", (err, result2) => {
    console.log(result2);
    fs.readFile("./3.txt", "utf-8", (err, result3) => {
      console.log(result3);
    })
  })
})

es6可以用promise来解决回调地狱的问题

let p1 = new Promise((resolve, reject) => {
  fs.readFile("./1.txt", "utf-8", (err, result) => {
    if (err != null) {
      reject(err);  //如果失败就调用这个传值下面能拿到
    } else {
      resolve(result);  //如果成功就用resolve把异步结果传出去
    }
  })
})

//then这里就相当于是上面的resolve()函数
p1
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err);
  })

promise进阶

function p1() {
  return new Promise((resolve, reject) => {
    fs.readFile("./1.txt", "utf-8", (err, result) => {
      resolve(result);
    })
  })
}
	上面返回那个promise对象下面才能then
p1().then((result)=>{
  console.log(result);
})





	解决回调地狱
function p1() {
  return new Promise((resolve, reject) => {
    fs.readFile("./1.txt", "utf-8", (err, result) => {
      resolve(result);
    })
  })
}
function p2() {
  let p = new Promise((resolve, reject) => {
    fs.readFile("./2.txt", "utf-8", (err, result) => {
      resolve(result);
    })
  })

  return p;
}
function p3() {
  return new Promise((resolve, reject) => {
    fs.readFile("./3.txt", "utf-8", (err, result) => {
      resolve(result);
    })
  })
}

	链式调用
p1()
  .then((r1) => {
    console.log(r1);//第一个文件的结果
    return p2();
  })
  .then((r2)=>{
    console.log(r2);
    return p3();
  })
  .then((r3)=>{
    console.log(r3);
  })

async await es7异步函数 基于promise封装

//在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
//在异步函数默认的返回值是promise对象
async function fn(){
}
console.log(fn());
返回	Promise { undefined }


async function fn(){
  return 123
}
console.log(fn());
返回	Promise { 123 }



既然返回值是promise对象那么
async function fn(){
  return 123
}
fn().then((data)=>{
  console.log(data);
})




捕获错误
async function fn(){
  throw "发生错误";throwreturn则不起作用
  return 123;
}
fn().catch(err=>{
  console.log(err);
})

await关键字 只能出现在异步函数当中
后面跟 promise对象 它可以暂停异步函数的执行
等待promise对象返回结果后 在向下执行

后面只能跟promise对象 后面只能跟promise对象 后面只能跟promise对象
暂停异步函数向下执行 直到promise返回结果

async function p1(){
  return "p1"
}
async function p2(){
  return "p2"
}
async function p3(){
  return "p3"
}

async function run(){
  let r1 = await p1()  //可以通过返回值 不需要then了
  let r2 = await p2()   //异步代码写成了同步形式
  let r3 = await p3()	//实际就是用上面的return代替了以前的resolve,throw代替错误
  console.log(r1);
  console.log(r2);
  console.log(r3);
}
run()

node异步函数的实际使用

需要借助模块util

const fs = require('fs');
const promisify = require("util").promisify
const readFile = promisify(fs.readFile);	//用调用的api方法改造返回promise

async function run(){
  let r1 = await readFile("./1.txt","utf-8",)
  let r2 = await readFile("./2.txt","utf-8",)
  let r3 = await readFile("./3.txt","utf-8",)

  console.log(r1);
  console.log(r2);
  console.log(r3);
}
run()






捕获错误
const fs = require('fs');
const promisify = require("util").promisify
const readFile = promisify(fs.readFile);	//用调用的api方法改造返回promise

async function run(){
  let r1 = await readFile("./111.txt","utf-8",).catch(err=>{
    console.log(err);
  })
  let r2 = await readFile("./2.txt","utf-8",)
  let r3 = await readFile("./3.txt","utf-8",)

  console.log(r1);
  console.log(r2);
  console.log(r3);
}
run()

node全局对象global

浏览器中全局是window,node中全局对象是global
node全局对象下有以下方法,可以在任何地方使用,global可以省略

console.log()
setTimeout()
clearTimeout()
setInterval()	//设置间歇定时器
clearInterval()	//清除简写定时器

另一个node笔记

初识

cd ../

node ./test.js     tab补全  clear清楚历史记录

模块化开发

文件与文件依赖关系不明确
文件与文件命名冲突

就像装机一样 主机显示器键盘鼠标 一个模块坏了不会影响另一个模块

模块化开发规范

一个js文件就是一个模块
模块内部定义的变量和函数默认情况下在外部无法得到

模块内部的函数变量可以导出  exports     使用require导入



        A模块(a.js)                     B模块(b.js)
         加法函数
         减法函数                      A模块 = require(A模块)
                                        A模块.加法()
    exports.加法 = 加法

实例

//a.js
//定义变量
var version = 1.0;
//定义方法
var sayHi = function(name){return `您好${name}`};
//导出
exports.version = version;
exports.sayHi = sayHi;

模快成员导出 exports require

test1

//定义一个函数
var add = function (n1, n2) { return n1 + n2 }
exports.add = add;  //exports对象的add属性等于test1里面的add函数

test2

const a  =  require("./test1.js");      // 拿a来接             require("./test1");   .js可以省略
console.log(a);
console.log(a.add(10,20));

结果

PS C:\Node.js> node .\test2.js
{ add: [Function: add] }
30

模块成员导出 module.exports

//test1
var greeting = function (name) { return `hello ${name}!`};
module.exports.greeting = greeting;







//test2
const a = require("./test1")
console.log(a);
console.log(a.greeting("张三"));





PS C:\Node.js> node .\test2.js                                                                                          
{ greeting: [Function: greeting] }
PS C:\Node.js> node .\test2.js                                                                                          
hello 张三!                                                                                                  

两者导出区别 如果重新指向 以module.exports为准


两者默认指向用一个对象(同一块内存空间)


module.exports.greeting = greeting;
exports.greeting = greeting;            两者 指向相同


但是    如果重新指向 以module.exports为准
module.exports = {
    name:"张"
}

实例

var greeting = function (name) { return `hello ${name}!`};
var x = 100;

exports.x = x;
module.exports.greeting = greeting;




const a = require("./test1")
console.log(a);





PS C:\Node.js> node .\test2.js                                                                                          
{ x: 100, greeting: [Function: greeting] }

重新指向

var greeting = function (name) { return `hello ${name}!`};
var x = 100;

exports.x = x;
module.exports.greeting = greeting;
module.exports = {
    name:"张三"
}

const a = require("./test1")
console.log(a);

PS C:\Node.js> node .\test2.js                                                                                          
{ name: '张三' }

系统模块 Node运行环境提供的api 因为模块化的方式开发所以叫

文件模块 fs
f file文件 s system系统

//引入
const fs = require("fs");

文件模块 fs

f file文件 s system系统

读取操作

//引入
const fs = require("fs");


//读取文件内容
fs.readFile("文件路径/名称",["文件编码"],function(err,doc文件内容){})    //回调函数

fs.readFile("../css/base.css","utf-8",function(err,doc){
    //如果文件读取出错 err是一个对象 包含错误信息
    //如果文件读取正确 err是null
    //doc是文件内容 文件读取的结果
    if(err == null){
        console.log(doc);
    }
}) 




const fs = require("fs");
fs.readFile("./test2.js", "utf8", function (err, doc) {
    console.log(err);
    console.log(doc);
})

写入操作 错误日志

    //如果文件读取正确 err是null
fs.writeFile("文件名称/文件路径","数据",function(err){})






const fs = require("fs");
var error = "正在写入数据";

fs.writeFile("./testtest.txt", error, function (err) {
    if(err != null){
        console.log("写入失败");
        console.log(err);
        return;
    }
    console.log("写入成功");
})

路径操作 path Linux和windows路径写法不一样
win为/
linux为/

path.join("路径","路径",.......)





//实例
const path = require("path");
//路径为cast\a\b\c.css
var finialPath = path.join("cast","a","b","c.css")
console.log(finialPath);

//输出为cast\a\b\c.css

第三方模块 也名为 包

别人写好的具有特定功能的 因为通常是多个文件所以 也名为包

通常具有两种存在形式

  1. js文件的形式存在,提供实现项目具体功能的API接口
  2. 命令行工具形式存在,辅助项目开发

如何获取第三方模块 https://npmjs.com
npm(node package manager) node的第三方模块管理工具

下载node时已经被继承在里面了

下载 npm.install 模块名称   //默认保存位置时当前的工作位置


如下载 formidable
npm install formidable



删除模块 npm unintsall  模块名称

本地安装 全局安装 上面为本地安装

一般命令行工具全局安装 第三方本地安装

nodemon命令行工具 nodemon每次保存就会自动执行

辅助项目开发
在node.js中每次写完都要调 命令行控制台执行 非常麻烦
nodemon每次保存就会自动执行

// 步骤
npm install nodemon -g  //  -g代表全局安装

命令行里用nodemon 替代node来执行


nodemon test1.js
结束用Ctrl + c 

nrm下载地址切换工具

npm registry manager
国内阿里巴巴 等 做了国内服务器

npm install nodemon -g      安装
nrm ls                      列出可用下载地址列表
nrm use 下载地址名称         切换下载地址

* npm -------- https://registry.npmjs.org/
  yarn ------- https://registry.yarnpkg.com/
  cnpm ------- http://r.cnpmjs.org/
  taobao ----- https://registry.npm.taobao.org/
  nj --------- https://registry.nodejitsu.com/
  npmMirror -- https://skimdb.npmjs.com/registry/
  edunpm ----- http://registry.enpmjs.org/


  nrm use taobao 

第三方模块 gulp 基于node平台开发的前端构建工具

基本

将机械化的操作编写成任务,想要执行机械化操作时,执行一个命令行命令就能自动执行了
能做什么

  1. html css js 文件压缩合并
  2. 语法转换(es6,less)
  3. 公共文件抽离(将头部抽取出来 要修头部直接改
  4. 修改浏览器自动刷新

使用步骤

  1. npm install gulp 下载库文件
  2. 在项目根目录创建gulpfile.js文件 文件名不能改
  3. 重构项目文件夹结构 src目录放置源代码文件 dist放置构建后文件
  4. 在gulpfile.js文件中编写任务
  5. 在命令行中执行gulp任务下载命令 npm install gulp-cli -g
  6. 下好gulp命令行 执行命令不在是node而是gulp (在文件根目录下)
gulp中提供的一些api方法

gulp.src();     获取任务要处理的文件
gulp.dest();    输出文件
gulp.task();    建立gulp任务
gulp.watch();   监控文件的变化

实例


//引入
const gulp = require("gulp");


//使用gulp.task方法建立任务 参数 任务名字 函数
gulp.task("first",function(){

    console.log("任务执行了");

    //获取要处理的文件                      //将处理后的文件输出到dist目录
    gulp.src("./src/css/index.css")        .pipe(gulp.dest("./dist/css"));


});

gulp插件

gulp-htmlmin        html压缩
gulp-csso           css压缩
gulp-babel          JavaScript语法转化
gulp-less           less语法转化
gulp-uglify         压缩混淆JavaScript
gulp-file-include   公共文件包含 抽取公共代码
browsereync         浏览器实时同步

插件的使用

  1. 下载
  2. 在gulpfile.js引入
  3. 调用

html压缩任务

//html文件中代码的压缩操作
//抽取html文件中的公共代码


//下载命令
npm install gulp-htmlmin
npm install gulp-file-include




const htmlmin = require("gulp-htmlmin");
const fileinclude = require('gulp-file-include');


//html压缩任务//html公共代码抽离

gulp.task("htmlmin", function () {

    //所有html文件
    gulp.src("./src/*.html")


        //html公共代码抽离  同时在src下创建common文件夹放公共代码片段 同时在html里剪切到新文件 在原来文件位置@@include('./common/header.html')
        .pipe(fileinclude())



        //压缩代码         要压缩空格吗?      是
        .pipe(htmlmin({ collapseWhitespace: true }))
        //输出文件
        .pipe(gulp.dest("./dist"));

});



控制台gulp htmlmin

css压缩 less转化

npm install gulp-csso 
npm install gulp-less




const csso = require("gulp-csso");
const less = require("gulp-less");

//css任务代码压缩 less语法转换
gulp.task("cssmin", function () {
    gulp.src(["./src/css/*.less","./src/css/*.css"]) //这里多选得加[]

        .pipe(less())   //这里先转化
        .pipe(csso())   //在压缩
        .pipe(gulp.dest("./dist/css")); //在输出
})


gulp cssmin

js语法转换 代码压缩

npm install --save-dev gulp-babel @babel/core @babel/preset-env
npm install gulp-uglify

const uglify = require("gulp-uglify");
const babel = require("gulp-babel");




拷贝文件夹

// 复制文件夹

gulp.task("copy", function () {
    gulp.src("./src/img/*")
        .pipe(gulp.dest("./dist/img"));

    gulp.src("./src/favicon.ico")
        .pipe(gulp.dest("./dist"));
})

执行一个任务 都执行 构建任务

gulp.task("default",["htmlmin","cssmin","jsmin","copy"]);


控制台执行 gulp default   当任务名为default 则可以直接敲 gulp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Loveyless

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

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

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

打赏作者

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

抵扣说明:

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

余额充值