web前端RxJS初步学习

JavaScript与函数式编程库RxJS 上面的代码中,我们使用了 map 操作符将原始 Observable 中的值乘以 2,然后使用 filter 操作符过滤掉小于等于 2 的值。上面的代码中,我们使用了 mergeMap 操作符将 observable2 中的每个值都与 observable1 中的每个值合并,最后订阅新的 Observable 并在控制台打印出合并后的值。上面的代码中,我们使用了 filter 操作符过滤掉原始 Observable 中的奇数,并订阅了新的 Observable。最后我们在控制台打印出了发射的偶数。 阅读详情

RxJS(Reactive Extensions for JavaScript) js响应式扩展


初学RxJS
http://cn.rx.js.org/manual/overview.html 中文网
https://zhuanlan.zhihu.com/p/23464709 demo网站
https://www.gitbook.com/book/buctwbzs/rxjs/details 比较好用初学者的网站


Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。(核心类型)
Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
Subject (主体): 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他


原生写法
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));//每次点击都会出现一个Clicked!
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .subscribe(() => console.log('Clicked!'))//每次点击都会出现一个Clicked!  事件触发.subscribe


原生写法
var count = 0; //全局变量可能引起代码污染(变量冲突)
var button = document.querySelector('button');
button.addEventListener('click', () => console.log(`Clicked ${++count} times`));
Rx写法   //纯净性 (Purity)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .scan(count => count + 1, 0) //类似与reduce 获取上次的count 继续进行下一次操作 默认值0      
  .subscribe(count => console.log(`Clicked ${count} times`));


原生写法 一秒钟最多点一次
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;//刚加载时记录时间
var button = document.querySelector('button');
button.addEventListener('click', () => {
  if (Date.now() - lastClick >= rate) {
    console.log(`Clicked ${++count} times`);
    lastClick = Date.now();//点击时记录时间作为下一次点击时判断时间
  }
});
Rx写法(RxJS 提供了一整套操作符来帮助你控制事件如何流经 observables ) //流动性 (Flow)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .throttleTime(1000)//一秒只能点击一次
  .scan(count => count + 1, 0)//每次回调函数运行后的返回值会作为下次回调函数运行时的参数。
  .subscribe(count => console.log(`Clicked ${count} times`)); //点击时触发


原生写法 (获取值) //限制每秒只能点击一次并且 计算conut的值
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;
var button = document.querySelector('button');
button.addEventListener('click', (event) => {
  if (Date.now() - lastClick >= rate) {
    count += event.clientX;
    console.log(count)
    lastClick = Date.now();
  }
});
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .throttleTime(1000) //限制每秒一次
  .map(event => event.clientX) //计算值
  .scan((count, clientX) => count + clientX, 0)
  .subscribe(count => console.log(count));


func.call() 意思是 "同步地给我一个值"
observable.subscribe() 意思是 "给我任意数量的值,无论是同步还是异步"


创建 Observables   Rx.Observable.create 
var observable = Rx.Observable.create(function subscribe(observer) {
  var id = setInterval(() => {
    observer.next('hi')
  }, 1000);
});
订阅 Observables
observable.subscribe(x => console.log(x));
执行 Observables
"Next" 通知: 发送一个值,比如数字、字符串、对象,等等。
"Error" 通知: 发送一个 JavaScript 错误 或 异常。
"Complete" 通知: 不再发送任何值。
清理 Observables
Subscription 表示进行中的执行,它有最小化的 API 以允许你取消执行。想了解更多订阅相关的内容,
请参见 Subscription 类型。使用 subscription.unsubscribe() 你可以取消进行中的执行:
var observable = Rx.Observable.from([10, 20, 30]);
var subscription = observable.subscribe(x => console.log(x));
// 稍后:
subscription.unsubscribe();


Subject (主体)多播 
它允许将值多播给多个观察者,所以 Subject 是多播的,而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。


在下面的示例中,我们为 Subject 添加了两个观察者,然后给 Subject 提供一些值:
var subject = new Rx.Subject();
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});
subject.next(1);
subject.next(2);
observerA: 1
observerB: 1
observerA: 2
observerB: 2


因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法,如下面的示例所展示的:
var subject = new Rx.Subject();
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});
var observable = Rx.Observable.from([1, 2, 3]);
observable.subscribe(subject); // 你可以提供一个 Subject 进行订阅
observerA: 1
observerB: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3


引用计数


手动调用 connect() 并处理 Subscription 通常太笨重。通常,当第一个观察者到达时我们想要自动地连接,
而当最后一个观察者取消订阅时我们想要自动地取消共享执行。
请考虑以下示例,下面的列表概述了 Subscriptions 发生的经过:
第一个观察者订阅了多播 Observable
多播 Observable 已连接
next 值 0 发送给第一个观察者
第二个观察者订阅了多播 Observable
next 值 1 发送给第一个观察者
next 值 1 发送给第二个观察者
第一个观察者取消了多播 Observable 的订阅
next 值 2 发送给第二个观察者
第二个观察者取消了多播 Observable 的订阅
多播 Observable 的连接已中断(底层进行的操作是取消订阅)
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var multicasted = source.multicast(subject);
var subscription1, subscription2, subscriptionConnect;


subscription1 = multicasted.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
// 这里我们应该调用 `connect()`,因为 `multicasted` 的第一个
// 订阅者关心消费值
subscriptionConnect = multicasted.connect();//第一个观察者到达时连接
setTimeout(() => {
  subscription2 = multicasted.subscribe({
    next: (v) => console.log('observerB: ' + v)
  });
}, 600);
setTimeout(() => {
  subscription1.unsubscribe();
}, 1200);
// 这里我们应该取消共享的 Observable 执行的订阅,
// 因为此后 `multicasted` 将不再有订阅者
setTimeout(() => {
  subscription2.unsubscribe();
  subscriptionConnect.unsubscribe(); // 用于共享的 Observable 执行
}, 2000);


如果不想显示调用 connect(),我们可以使用 ConnectableObservable 的 refCount() 方法(引用计数),这个方法返回 Observable,
这个 Observable 会追踪有多少个订阅者。当订阅者的数量从0变成1,它会调用 connect() 以开启共享的执行。当订阅者数量从1变成0时,
它会完全取消订阅,停止进一步的执行。
refCount 的作用是,当有第一个订阅者时,多播 Observable 会自动地启动执行,而当最后一个订阅者离开时,多播 Observable 会自动地停止执行。
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var refCounted = source.multicast(subject).refCount();
var subscription1, subscription2, subscriptionConnect;
// 这里其实调用了 `connect()`,
// 因为 `refCounted` 有了第一个订阅者
console.log('observerA subscribed');
subscription1 = refCounted.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
setTimeout(() => {
  console.log('observerB subscribed');
  subscription2 = refCounted.subscribe({
    next: (v) => console.log('observerB: ' + v)
  });
}, 600);
setTimeout(() => {
  console.log('observerA unsubscribed');
  subscription1.unsubscribe();
}, 1200);
// 这里共享的 Observable 执行会停止,
// 因为此后 `refCounted` 将不再有订阅者
setTimeout(() => {
  console.log('observerB unsubscribed');
  subscription2.unsubscribe();
}, 2000);
observerA subscribed//刚进入就被调用
observerA: 0//500ms
observerB subscribed//1000ms
observerA: 1//1000ms
observerB: 1/1000ms
observerA unsubscribed//1500ms
observerB: 2//1500ms
observerB unsubscribed//2000ms




Subject 的其中一个变体就是 BehaviorSubject,它有一个“当前值”的概念。它保存了发送给消费者的最新值。
并且当有新的观察者订阅时,会立即从 BehaviorSubject 那接收到“当前值”。
在下面的示例中,BehaviorSubject 使用值0进行初始化,当第一个观察者订阅时会得到0。第二个观察者订阅时会得到值2,尽管它是在值2发送之后订阅的。
var subject = new Rx.BehaviorSubject(0); // 0是初始值
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);


subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});
subject.next(3);
observerA: 0
observerA: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3


ReplaySubject 记录 Observable 执行中的多个值并将其回放给新的订阅者。
当创建 ReplaySubject 时,你可以指定回放多少个值:
var subject = new Rx.ReplaySubject(3); // 为新的订阅者缓冲3个值
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);


subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});
subject.next(5);
observerA: 1
observerA: 2
observerA: 3
observerA: 4
observerB: 2
observerB: 3
observerB: 4// 2 3 4 缓冲的三个值
observerA: 5
observerB: 5




Scheduler (调度器)
什么是调度器? - 调度器控制着何时启动 subscription 和何时发送通知。它由三部分组成:


调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
调度器是执行上下文。 它表示在何时何地执行任务(举例来说,立即的,或另一种回调函数机制(比如 setTimeout 或 process.nextTick),或动画帧)。
调度器有一个(虚拟的)时钟。 调度器功能通过它的 getter 方法 now() 提供了“时间”的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。


var observable = Rx.Observable.create(function (observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
})
.observeOn(Rx.Scheduler.async);
console.log('just before subscribe');
observable.subscribe({
  next: x => console.log('got value ' + x),
  error: err => console.error('something wrong occurred: ' + err),
  complete: () => console.log('done'),
});
console.log('just after subscribe');
just before subscribe
just after subscribe
got value 1
got value 2
got value 3
done
async 调度器操作符使用了 setTimeout 或 setInterval,即使给定的延迟时间为0。
 

掌握RxJS中的Subject和BehaviorSubject 本文深入探讨了RxJS中的Subject和BehaviorSubject的概念和实际应用。通过分析currentUser流的设置、新用户的添加方法以及MessagesService中的流管理,揭示了如何利用RxJS的响应式编程特性来构建和维护数据流。文章详细解释了Subject与BehaviorSubject的区别及其在数据流管理中的优势,同时提供了两种更新当前用户状态的方法,并探讨了操作流模式在消息服务中的应用,最后强调了流的可共享性以及如何在多个订阅者之间共享流。 阅读详情

相关推荐

高效实时Web应用构建与RxJS优化技巧

本文讨论了如何将冷Observable转换为热Observable以提高Web应用的效率,使用了RxJS的publish、share和bufferTime等操作符。通过实例展示了如何优化DOM操作和事件处理,以及如何通过Node.js获取Twitter实时数据流,提升用户体验。

weixin_35835018的博客 396

RxJS——异步数据流的响应式编程库(适合新手入门)

文章目录RxJS概述Redux VS RxJSRxJS核心概念解析热观察和冷观察merge/combine合流RXJS6 的变化 RxJS概述 RxJS 全称 Reactive Extensions for JavaScript RxJS 结合了函数式编程、观察者模式(例如 DOM EventListener)、迭代器模式(例如 ES6 Iterater) RxJS 官方是这样说的: Think of RxJS as Lodash for events. 把 RxJS 想像成针对 events 的 loda

萌萌哒的瑞萌萌的博客 1万+

gm/ID设计方法实践指南:从理论曲线到电路优化的关键步骤

本文详细介绍了gm/ID设计方法在模拟IC设计中的实践指南。该方法通过直接利用工艺模型数据,将设计焦点从盲目调整晶体管尺寸转向选择关键的gm/ID工作点,从而在先进工艺下实现功耗、增益和带宽等性能的精准权衡与优化。文章从理论曲线生成到具体电路设计步骤,提供了完整的实战流程。

pandas7gardener的博客 480

RxJS基本概念入门

RxJS代表响应式扩展JavaScript。它是一个用于处理事件流和异步数据流的库,可以将这些流组合起来以产生更复杂的结果。

X01动力装甲的专栏 1863

手把手教你用示波器抓取MIPI D-PHY波形:从LP11到HS Burst的完整信号解析

本文详细介绍了使用示波器精准捕获MIPI D-PHY信号的关键技巧,包括探头选择、示波器参数设置、信号状态解析及高级触发配置。通过实战案例和波形分析,帮助工程师快速识别从LP11到HS Burst的各种信号状态,解决常见的信号完整性问题,提升调试效率。

weixin_30471561的博客 563

ByteTrack参数调优全攻略:从原理到实战(含YOLOv8示例)

本文深入解析了ByteTrack多目标跟踪算法的核心原理与参数调优策略。通过拆解其独特的两阶段关联机制,并结合YOLOv8检测器,提供了针对不同应用场景(如拥挤行人、高速车辆)的精细化参数调整指南与实战示例,旨在帮助开发者解决ID切换、目标丢失等工程落地难题,提升跟踪系统的鲁棒性与实用性。

cheese的博客 323

RxJS:前端开发的未来

RxJS提供了丰富的操作符,可以对数据流进行各种转换和处理。例如,我们可以使用map操作符将一个数据流中的每个值映射为另一个值,使用filter操作符过滤出符合条件的值,使用merge操作符将多个数据流合并为一个等等。RxJS的操作符具有良好的可组合性,可以将多个操作符串联起来形成一个复杂的数据处理流程。这种可组合性使我们能够以一种模块化的方式构建应用程序,将复杂的问题分解为简单的问题,并将它们逐步组合起来解决。通过使用RxJS,我们可以更好地处理复杂的异步场景,并以一种简洁而灵活的方式构建应用程序。

Sun_blog 938

CH340以及CH系列USB转串口驱动下载

在之前使用USB转串口时,很多时候大家可能会不知道去哪下载驱动,然后百度随便下载一个,但往往鱼龙混杂且版本不一,所以今天特意整理一下CH340驱动以及CH系列的官方驱动下载地址,方便大家进行下载也方便自己后期查找,所有链接皆指向官方下载链接,每次下载都可获取官方当前最新驱动。 CH340/CH341 Windows驱动下载链接:CH341SER.EXE下载链接 Linux驱动下载链接:CH341SER_LINUX.ZIP下载链接 Andr...

OIDCAT的博客 4万+

【前端必学】RxJS,一个“神秘”的前端技术

RxJS 是一个 JavaScript 库,它使用可观察对象来编写异步和基于事件的程序。它可以帮助开发人员更轻松地管理复杂的异步代码,并提供了许多操作符来处理可观察对象。RxJS 可以用于多种应用程序,包括 Web 应用程序、移动应用程序和桌面应用程序。但是,由于它有一些复杂的概念和操作符,因此有时也被认为是一种“神秘”的技术。

热爱思考、活力满满、开朗爱笑的年轻人 2181

[NoC]Outstanding和Credit的概念详解

摘要:本文详细解析了计算机体系结构中outstanding和credit两个核心概念。outstanding指已发出但未完成的请求数量,通过跟踪未决事务实现并发和乱序执行,常见于AXI总线等场景;credit则是基于信用令牌的流控机制,通过控制发送速率防止接收端缓冲溢出,多用于NoC网络。二者在目的、机制上存在差异:outstanding侧重提升并发度,credit关注流控保护。文章通过AXI协议实例和SystemC代码示例展示了二者的应用与结合方式,并探讨了在SoC设计中参数优化的方法,包括性能/资源权衡

元直的博客 2285

昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子

【代码】昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子。

william_myq的博客 509

RxJS介绍

RxJS介绍

在所有的事情背后,要有一颗坚定的的本心,要有一颗应对变革和提升自我的本心,世界瞬息万变,本心要坚持到底,保持学习,时刻复盘 1821

YOLOv4目标检测算法——通俗易懂的解析

YOLOv4目标检测算法——通俗易懂的解析

chase 7135

Rxjs学习

Rxjs学习参考:http://www.open-open.com/lib/view/open1474960866599.html这里将Observable当作异步数组。理解的很到位。而且有很多的demo。

u012857153的博客 346

智能车图像处理16-进阶篇8--右环岛状态机与补线

这篇文章主要讲述智能车竞赛中如何判断右环岛并且进行状态补线。

taiyuezyh的博客 1万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

web前端学习之bootstrap初步学习

DIV:  div响应式布局class:container-fluid  12分格局    text-danger IMG  img响应式布局class:img-responsive h  text-center文本居中 Button  btn btn-block Ibtn-info I:

zjhcdns的博客 311

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Web前端学习:RxJS 库

RxJS 库 RxJS 提供了一种对Observable类型的实现 创建可观察对象(Observable)的函数 从Promise创建Observable createanobservablefromapromise(): void { // Create an Observable out of a promise //fetch方法返回一个Promi...

lionheart922的专栏 308

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

observable-webworker:简化Web Workers与RxJS集成的轻量级解决方案

observable-webworker:简化Web Workers与RxJS集成的轻量级解决方案 在现代前端开发中,Web Workers 提供了一种在后台线程中运行代码的方法,从而不会阻塞主线程,这对于复杂或耗时的任务尤其有用。但Web Workers的集成和使用有时可能显得复杂,尤其是在处理异步流时。Observable Webworker 旨在简化这一过程,通过将Web Workers与R...

gitblog_00061的博客 966

RxJS 入门指引和初步应用

感谢作者徐飞的授权发布。 作者:徐飞,网名民工精髓V,蚂蚁金服前端工程师。有十年以上大型企业应用前端架构及开发经验,熟悉AngularJS等框架,对Web组件化有一些思考。博客地址:https://github.com/xufei/blog/issues。 RxJS是一个强大的Reactive编程库,提供了强大的数据流组合与控制能力,但是其学习门槛一直很高,本次分享期望从一些特别的角...

小秋博客 1916

探索RxJS的魅力:从工作坊到实战应用

探索RxJS的魅力:从工作坊到实战应用 在前端开发的浩瀚星辰中,RxJS犹如一颗璀璨的明星,以其强大的响应式编程能力引领潮流。今天,我们不只停留在理论的表面,而是通过一个特别的工作坊——RxJS Workshop at MLOC.js,由大名鼎鼎的André Staltz主讲,带您深入浅出地掌握这门技术,并通过一系列精心设计的实践案例,让您迅速上手,领略其无限魅力。 项目介绍 RxJS Works...

gitblog_00900的博客 639

使用RXJS实现高级缓存

在构建Web应用程序时,性能应始终是头等大事。我们可以采取许多措施来加快Angular应用程序的运行速度,例如Tree-Shaking,AoT(提前编译),懒加载模块或缓存。为了提高关于Angular应用程序性能实践方面的全面了解,我们强烈建议您查看 Minko Gechev.撰写的Angular Performance Checklist。 在这篇文章中,我们专注于缓存。 ...

liujiawei00的博客 1432

探索响应式编程的宝典:《深入浅出RxJS》代码实践库

探索响应式编程的宝典:《深入浅出RxJS》代码实践库 在当今快速发展的前端技术领域,响应式编程凭借其高效、灵活的特点,成为了开发者手中的利器。而《深入浅出RxJS》一书正是为此而生,它不仅是机械工业出版社的一枚瑰宝,更是每位向往响应式编程深邃世界的探索者必读之作。本篇文章将带你深入了解其配套的开源项目,一个集学习、实践于一体的宝藏仓库——dissecting-rxjs,并揭示如何通过这个项目与《进...

gitblog_00974的博客 378

学习rxjs

Hey, I am Sean, and work with a very small team of developers. We run a web application that helps a business manage their everyday Health and Safety operations. Using Angular as the client-side frame...

weixin_26723981的博客 135

rxjs-for-await:为RxJS带来async-await的便利

rxjs-for-await:为RxJS带来async-await的便利 在异步编程的世界中,async-await无疑为开发者提供了极大的便利。今天,我们将为您介绍一个开源项目——rxjs-for-await,它能让您在使用RxJS时,也能享受到async-await的简洁与直观。 项目介绍 rxjs-for-await是一个开源库,它通过AsyncIterables实现了让RxJS支持asyn...

gitblog_00482的博客 762

Effector与RxJS对比分析:函数式响应式编程的两种实现方式

在当今复杂的前端开发环境中,**函数式响应式编程**已成为管理状态和构建可预测应用的首选方法。本文将深入对比两个流行的响应式编程库:Effector和RxJS,帮助你了解它们各自的优势和适用场景。作为现代状态管理解决方案,这两种工具都提供了强大的响应式编程能力,但在实现哲学和设计理念上有着显著差异。 ## 什么是函数式响应式编程?🤔 **函数式响应式编程**是一种声明式的编程范式,它专注于数

gitblog_00413的博客 841

【响应式编程的思维艺术】 (1)Rxjs专题学习计划

【摘要】 请暂时忘掉你的对象,感受一切皆流的世界。 一. 响应式编程 响应式编程,也称为流式编程,对于非前端工程师来说,可能并不是一个陌生的名词,它是函数式编程在软件开发中应用的延伸,如果你对函数式编程还没有一些感性的认知,那么建议你先阅读我曾经写过的一篇入门文章【javascript基础修炼(8)——指向FP世界的箭头函数】,先理解一下函数式编程的基本思想以及在javascript语言中应用...

华为云官方博客 1366
上一篇: css 水平/竖直/水平竖直方法大全
下一篇: *ngif 和 显示隐藏的区别
wen_binObject
博客等级 码龄10年 51粉丝 63原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值