angular 4版本小知识点----方便自己看

  1. 使用 Angular CLI 创建一个名为 heroes 的新组件。
    ng generate component hero-detail
    这个命令会做这些事:

创建目录 src/app/hero-detail。

在这个目录中会生成四个文件:

  • 作为组件样式的 CSS 文件。
  • 作为组件模板的 HTML 文件。
  • 存放组件类 HeroDetailComponent 的 TypeScript 文件。
  • HeroDetailComponent 类的测试文件。

该命令还会把 HeroDetailComponent 添加到 src/app/app.module.ts 文件中 @NgModule 的 declarations 列表中。

  1. CLI 自动生成了三个元数据属性:
    selector— 组件的选择器(CSS 元素选择器)
    templateUrl— 组件模板文件的位置。
    styleUrls— 组件私有 CSS 样式表文件的位置。
    ngOnInit 是一个生命周期钩子,Angular 在创建完组件后很快就会调用 ngOnInit。这里是放置初始化逻辑的好地方
  2. *ngFor
    *ngFor 是一个 Angular 的复写器(repeater)指令。 它会为列表中的每项数据复写它的宿主元素。
<li *ngFor="let hero of heroes">
  1. 添加 click 事件绑定
 <li *ngFor="let hero of heroes" (click)="onSelect(hero)">

click 外面的圆括号会让 Angular 监听这个元素的 click 事件。
添加 click 事件处理器

selectedHero: Hero;
onSelect(hero: Hero): void {
  this.selectedHero = hero;
}
  1. 使用 *ngIf 隐藏空白的详情

  2. 使用ngModel
    [(ngModel)] 是 Angular 的双向数据绑定语法。
    虽然 ngModel 是一个有效的 Angular 指令,不过它在默认情况下是不可用的。
    它属于一个可选模块 FormsModule,你必须自行添加此模块才能使用该指令。
    有些元数据位于 @Component 装饰器中,你会把它加到组件类上。 另一些关键性的元数据位于 @NgModule 装饰器中。

最重要的 @NgModule 装饰器位于顶级类 AppModule 上。
Angular CLI 在创建项目的时候就在 src/app/app.module.ts 中生成了一个 AppModule 类。 这里也就是你要添加 FormsModule 的地方。
导入 FormsModule
打开 AppModule (app.module.ts) 并从 @angular/forms 库中导入 FormsModule 符号。

import { FormsModule } from '@angular/forms';

app.module.ts文件

 import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms'//插入的FormModule
    import { AppComponent } from './app.component';
    import { HeroesComponent } from './heroes/heroes.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        HeroesComponent
      ],
      imports: [
        BrowserModule,
        FormsModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

  1. 使用 Angular CLI 创建一个名叫 hero 的服务。
ng generate service hero
  1. 添加 AppRoutingModule
    在 Angular 中,最好在一个独立的顶级模块中加载和配置路由器,它专注于路由功能,然后由根模块 AppModule 导入它。

按照惯例,这个模块类的名字叫做 AppRoutingModule,并且位于 src/app 下的 app-routing.module.ts 文件中。

ng generate module app-routing --flat --module=app

–flat 把这个文件放进了 src/app 中,而不是单独的目录中。
–module=app 告诉 CLI 把它注册到 AppModule 的 imports 数组中。

  1. 内存 Web API
npm install angular-in-memory-web-api --save

导入 HttpClientInMemoryWebApiModule 和 InMemoryDataService 类,在/app.module.ts

  1. angular 4 中@Input()、@Output()父子组件之间的传值
    @Input()、@Output()父子组件之间的传值
    在这里插入图片描述
    在这里插入图片描述1、child组件内有一个Output customClick的事件,事件的数据类型是number;
    2、child组件内有一个onClicked方法,这个是应用在html中button控件的click事件中,通过(click)="onClicked()"进行方法绑定;
    3、parent组件内有一个public的属性showMsg,Angular的ts类默认不写关键字就是public;
    4、parent组件内有一个onCustomClicked方法,这个也是要用在html中的,是和child组件内的output标记的customClick事件进行绑定的;
    5、步骤为child的html的button按钮被点击->onClicked方法被调用->emit(99)触发customClick->Angular通过Output数据流识别出发生变化并通知parent的html中(customClick)->onCustomClicked(event)被调用, event)被调用,event)被调用,event为数据99->改变了showMsg属性值->影响到了parent的html中的显示由1变为99
    ————————————————
    版权声明:本文为CSDN博主「FlyWine」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/wf19930209/article/details/79349164
  2. angular 4 中共享服务在多个组件中数据通信的示例
    在这里插入图片描述
    不同组件中操作统一组数据,不论哪个组件对数据进行了操作,其他组件中立马看到效果https://www.jb51.net/article/137456.htm
    如下图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. Angular 响应式Form 表单
    ①表单验证
    目前 Angular 支持的内建 validators 如下:
    1.required - 设置表单控件值是非空的。
    2.email - 设置表单控件值的格式是 email。
    3.minlength - 设置表单控件值的最小长度。
    4.maxlength - 设置表单控件值的最大长度。
    5.pattern - 设置表单控件的值需匹配 pattern 对应的模式。
    如:
this.itFormGroup = this.fb.group({
       lxnameCtr: ["", [Validators.required]],
       remarkCtr: [""]
     });
createForm() {
	this.heroForm =  this.fb. group({
		name: ['',  Validators.required ],
		street: '',
		city: '',
		state: '',
		zip: '',
		power: '',
		sidekick: ''
	});
}

FormBuilder.group 是一个用来创建 FormGroup 的工厂方法,它接受一个对象,对象的键和值分别是
FormControl 的名字和它的定义
更多的可以参考网址:https://segmentfault.com/a/1190000010064866
②响应式表单的更新值 setValue、patchValue
创建响应式表单是需要在app.module.ts中导入ReactiveFormsModule模块
在这里插入图片描述

  • patchValue
    借助 patchValue() ,你可以通过提供一个只包含要更新的控件的键值对象来把值赋给 FormGroup 中的指定
    控件。patchValue() 不会检查缺失的控件值,并且不会抛出有用的错误信息。
this.heroForm.patchValue({
name:  this.hero.name
});
  • setValue
    跟 patchValue 有一点不一样,当我们提供一个 FromGroup 中并不存在的字段时,会抛出一个错误;setValue() 方法会在赋值给任何表单控件之前先检查数据对象的值。
this.heroForm.setValue({
name: this.hero.name,
address:  this.hero.addresses[0] ||  new  Address()
});
  1. navigator.userAgent.toLowerCase()
    toLowerCase()方法:用于把字符串转化为小写;语法:stringObject.toLowerCase();
    toUpperCase() 方法:用于把字符串转换为大写;语法:stringObject.toUpperCase();
    navigator对象:包含有关浏览器的信息,所有浏览器都支持该对象
    navigator属性:
    在这里插入图片描述
    Navigator 对象方法:
    在这里插入图片描述
    我们这里所用的userAgent属性是一个只读属性,声明了浏览器用于HTTP请求的用户代理头的值
    所有主要浏览器都支持 userAgent 属性
  • 判断移动端设备,区分android,iphone,ipad和其它
    
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/android/i)) == "android") {
	alert("android");
}
if(ua.match(/iPhone/i)) == "iPhone") {
	alert("iPhone");
}
if(ua.match(/iPad/i)) == "iPad") {
	alert("iPad");
}
  • 判断移动端用的是不是特定类型的浏览器,比如新浪weibo客户端内置浏览器,qq客户端内置浏览器(而非qq浏览器),微信内置浏览器(并且区分版本是否大于等于6.0.2)(特定类型浏览器可能会存在,无法下载,无法跳转和自己的客户端app的特定协议等等,所以需要区分)(由于微信在6.0.2的时候做了新的策略,使得微信的分享功能在新版本变得不一样,为了兼容新旧版本,这里做了区分操作)
    新浪weibo客户端返回1,qq客户端返回2,微信小于6.0.2版本返回3,微信大于等于6.0.2版本返回4,其它返回0
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/weibo/i) == "weibo") {
	return 1;
} else if(ua.indexOf('qq/') != -1) {
	return 2;
} else if(ua.match(/MicroMessenger/i) == "micromessenger") {
	var v_weixin = ua.split('micromessenger')[1];
	v_weixin = v_weixin.substring(1, 6);
	v_weixin = v_weixin.split(' ')[0];
	if(v_weixin.split('.').length == 2) {
		v_weixin = v_weixin + '.0';
	}
	if(v_weixin < '6.0.2') {
		return 3;
	} else {
		return 4;
	}
} else {
	return 0;
}
  • 把他们统一起来判断登陆端是pc还是手机
var sUserAgent = navigator.userAgent.toLowerCase();
var bIsIpad = sUserAgent.match(/ipad/i) == "ipad"; 
var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os"; 
var bIsMidp = sUserAgent.match(/midp/i) == "midp"; 
var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb"; 
var bIsAndroid = sUserAgent.match(/android/i) == "android"; 
var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
if(bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
	alert("您是手机登录");
} else {
	alert("您是电脑登录");
}
  • 判断是否是ie浏览器
    isIE(): boolean {
    return !(/(msie\s|trident.*rv:)([\w.]+)/.exec(navigator.userAgent.toLowerCase()) == null);
    }
    或者:
    var isIE = /mise|trident/g.test(window.navigator.userAgent.toLowerCase());
    网上更全的:
function isIE(){
    var userAgent = navigator.userAgent, 
    rMsie = /(msie\s|trident.*rv:)([\w.]+)/, 
    rFirefox = /(firefox)\/([\w.]+)/, 
    rOpera = /(opera).+version\/([\w.]+)/, 
    rChrome = /(chrome)\/([\w.]+)/, 
    rSafari = /version\/([\w.]+).*(safari)/; 
    var browser; 
    var version; 
    var ua = userAgent.toLowerCase(); 

    var match = rMsie.exec(ua);    
    if (match != null) {  
        ieVersion = { browser : "IE", version : match[2] || "0" };
        return true; 
    }  
    var match = rFirefox.exec(ua);  
    if (match != null) {  
        var ffVersion = { browser : match[1] || "", version : match[2] || "0" };
        return false; 
    }  
    var match = rOpera.exec(ua);  
    if (match != null) { 
       var opVersion =  { browser : match[1] || "", version : match[2] || "0" };
       return false;
    }  
    var match = rChrome.exec(ua);  
    if (match != null) {  

        var chVersion = { browser : match[1] || "", version : match[2] || "0" };
        return false;
    }  
    var match = rSafari.exec(ua);  
    if (match != null) {  

       var sfVersion = { browser : match[2] || "", version : match[1] || "0" }; 
       return false;
    }  
    if (match != null) {  
        var ohterVersion = { browser : "", version : "0" }; 
        return false;
    }
}
  1. 创建动态组件并使用
先创建一个弹框组件ggMsg.component
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { MyhttpService } from "../myhttp.service";
declare var $: any;

@Component({
    template: `
    <div id="toast-container" aria-live="polite" role="alert">
        <div class="toast toast-info" >
            <button class="toast-close-button" role="button" (click)="clsoe()">×</button>
            <div class="toast-title">提示信息</div>
            <div class="toast-message" id="toast-message">
                <span style="line-height: 50px;">未读公告:</span><span style="line-height: 50px;">{{wdcount}}</span>&nbsp;&nbsp;&nbsp;&nbsp;
                <span style="line-height: 50px;">已读公告:</span><span style="line-height: 50px;">{{ydcount}}</span>
            </div>
        </div>
    </div>
    `,
    styles: [
        ".toast-title{font-weight:bold;font-size:16px;}",
        ".toast-message{-ms-word-wrap:break-word;word-wrap:break-word}",
        ".toast-message a,.toast-message label{color:#fff}",
        ".toast-message a:hover{color:#ccc;text-decoration:none}",
        ".toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#fff;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:alpha(opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:alpha(opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}",
        "#toast-container{position:fixed;z-index:999999;right:12px;bottom:-150px;}",
        "#toast-container>div{margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.8;-ms-filter:alpha(opacity=80);filter:alpha(opacity=80)}",
    ],
    providers: [MyhttpService]
})
export class GgmsgComponent implements OnInit, OnDestroy {
 @Input() data: any
 @Output() outer: EventEmitter<any> = new EventEmitter<any>();
 ngOnInit() {
       
    }
    ngOnDestroy() {
        
    }
clsoe(): void {
        this.outer.emit({
            type: "closeggmsg" //约定一个,这里告诉父组件要关闭了
        });
    }
}

@Input():父组件将数据传过来,子组件接收
@Output():

将创建的动态组件放到存放所有动态组件文件中

我这里是dynamaner.component.ts

import {GgmsgComponent} from "./ggMsg.component";
const CompMap = {
'ggmsg':GgmsgComponent,
}
const DynaCompArr = [
GgmsgComponent
]
export {
  CompMap,
  DynaCompArr,
}
创建组件容器

在 Angular 中放置组件的地方称为 container 容器。这里我放置在app.component组件中,为了方便以后每个页面都显示

import {Component, ViewContainerRef, ViewChild, ComponentFactoryResolver} from '@angular/core';
import {NavigationEnd, NavigationError, NavigationStart, Router} from "@angular/router";
import {CompMap} from "./dynacomponent/dynamaner.component"; //将存放动态组件的文件引进来
<div class="pubMsg">
        <ng-container #pubMsgRoom></ng-container>
 </div>
export class AppComponent {
 @ViewChild("pubMsgRoom", {read: ViewContainerRef}) rRoom: ViewContainerRef;
}
	  this.rRoom.remove(0); //清空组件(有没有都先清空)每次我们需要创建组件时,我们需要删除之前的视图,否则组件容器中会出现多个视图
      const ggmsgcomponent : ComponentFactory= this.cfr.resolveComponentFactory(CompMap['ggmsg']); //**resolveComponentFactory()** 方法接受一个组件并返回如何创建组件的 **ComponentFactory** 实例。
      const ggmsgcomp : ComponentRef = this.rRoom.createComponent(ggmsgcomponent); //我们调用容器的 **createComponent()** 方法,该方法内部将调用 **ComponentFactory** 实例的 **create()** 方法创建对应的组件,并将组件添加到我们的容器
      ggmsgcomp.instance.data = {}; //我们已经能获取新组件的引用,即可以我们可以设置组件的输入类型
      ggmsgcomp.instance.outer.subscribe((resp) => {} //同样我们也可以订阅组件的输出属性
完整示例

ggMsg.component.ts

import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { MyhttpService } from "../myhttp.service";
declare var $: any;

@Component({
    template: `
    <div id="toast-container" aria-live="polite" role="alert">
        <div class="toast toast-info" >
            <button class="toast-close-button" role="button" (click)="clsoe()">×</button>
            <div class="toast-title">提示信息</div>
            <div class="toast-message" id="toast-message">
                <span style="line-height: 50px;">未读公告:</span><span style="line-height: 50px;">{{wdcount}}</span>&nbsp;&nbsp;&nbsp;&nbsp;
                <span style="line-height: 50px;">已读公告:</span><span style="line-height: 50px;">{{ydcount}}</span>
            </div>
        </div>
    </div>
    `,
    styles: [
        ".toast-title{font-weight:bold;font-size:16px;}",
        ".toast-message{-ms-word-wrap:break-word;word-wrap:break-word}",
        ".toast-message a,.toast-message label{color:#fff}",
        ".toast-message a:hover{color:#ccc;text-decoration:none}",
        ".toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#fff;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:alpha(opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:alpha(opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}",
        "#toast-container{position:fixed;z-index:999999;right:12px;bottom:-150px;}",
        "#toast-container>div{margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.8;-ms-filter:alpha(opacity=80);filter:alpha(opacity=80)}",
    ],
    providers: [MyhttpService]
})
export class GgmsgComponent implements OnInit, OnDestroy {
    loginuseruuid: string = "";
    //已读未读
    wdcount: string = "--";
    ydcount: string = "--";
    tmid: any;
    @Input() data: any
    @Output() outer: EventEmitter<any> = new EventEmitter<any>();
    constructor(private itservice: MyhttpService) {

    }
    ngOnInit() {
        clearTimeout(this.tmid);
        this.getLogmsg();
    }
    ngOnDestroy() {
        clearTimeout(this.tmid);
    }
    clsoe(): void {
        this.outer.emit({
            type: "closeggmsg"
        });
    }
    getLogmsg(): void {
        this.itservice.requstUrl("security_client/auth/getLoginUser", null).subscribe(resp => {
            const retflag = resp.result;
            if (retflag == "success") {
                this.loginuseruuid = resp.rows[0].user_uuid;
                this.getMsg();
            }

        });
    }
    getMsg() {
        this.itservice.requstUrl("owner_client/owner/OaGwtz/JsrUuidByGwtzZtCount", {
            jsruuid: this.loginuseruuid,
            randomv: Math.random(),
        }).subscribe(resp => {
            const retflag = resp.result;
            if (retflag == "success") {
                $("#toast-container").stop();
                $("#toast-container").animate({
                    bottom: '10px'
                }, "slow");
                const rowobj = resp.rows;
                this.wdcount = rowobj.wck;
                this.ydcount = rowobj.yck;
                clearTimeout(this.tmid)
                this.tmid = setTimeout(function () {
                    $("#toast-container").fadeOut()
                }, 5000);
            }

        });

    }
}

app.component.ts

import {Component, ViewContainerRef, ViewChild, ComponentFactoryResolver} from '@angular/core';
import {NavigationEnd, NavigationError, NavigationStart, Router} from "@angular/router";
import {LocalStorageService} from "./local-storage-service";
import {CommService} from "./comm-service";
import {CompMap} from "./dynacomponent/dynamaner.component";

declare var $: any;

@Component({
  selector: 'app-root',
  template: `
    <!--Metrnic提供的三个点的动画-->
    <div [class.page-spinner-bar]="hasanima">
      <div class="bounce1"></div>
      <div class="bounce2"></div>
      <div class="bounce3"></div>
    </div>
    <div class="main_out">
      <router-outlet></router-outlet>
      <div id="myMask"></div>
      <div class="pubMsg">
        <ng-container #pubMsgRoom></ng-container>
      </div>
    </div>
  `,
  styles: [
    ".page-spinner-bar>div{margin: 0 5px;width: 18px;height: 18px;background: orange;border-radius: 100% !important;display: inline-block;-webkit-animation: bounceDelay 1.4s infinite ease-in-out;animation: bounceDelay 1.4s infinite ease-in-out;-webkit-animation-fill-mode: both;animation-fill-mode: both;}",
    ".page-spinner-bar .bounce1{-webkit-animation-delay: -0.32s;animation-delay: -0.32s;}",
    ".page-spinner-bar .bounce2{-webkit-animation-delay: -0.16s;animation-delay: -0.16s;}",
    ".main_out{position: relative}",
    '#myMask{display: none;position:absolute;left: 0px;top: 0px;z-index: 1000;background-color: grey;opacity: .1}',
    ".pubMsg{position:absolute;right:5px;bottom:5px;width:auto;height:auto}",
  ],
})

export class AppComponent {
  hasanima: boolean = false;
  setTm: any;
  @ViewChild("pubMsgRoom", {read: ViewContainerRef}) rRoom: ViewContainerRef;

  constructor(private router: Router,
              private localstorage: LocalStorageService,
              private commservice: CommService,
              private cfr: ComponentFactoryResolver) {
    this.router.events.subscribe(event => {
      //路由开始切换
      if (event instanceof NavigationStart) {
        this.hasanima = true;
        //显示三个点
        const token = this.commservice.getToken();
        const localtoken = this.localstorage.get("token");
        const url = event.url;
        if (!token) { //刷新操作  或者 第一次进入系统登入页面
          if (url == "/" || url == "/login") {
            //第一次进入系统登入页面不处理
          } else {
            if (!localtoken) {
              //清空缓存后刷新操作
              this.router.navigate(["login"]);
            } else {
              //简单的刷新操作
              this.commservice.setToken(localtoken);
              clearInterval(this.setTm);
              this.setTm = setTimeout(() => {
                this.createComponent(url);
              }, 2000)
            }
          }

        } else {
          this.createComponent(url);
        }


      }
      //路由切换结束
      if (event instanceof NavigationEnd) {
        //隐藏三个点
        this.hasanima = false;
      }
      //路由切换出错
      if (event instanceof NavigationError) {
        this.hasanima = false;
        console.log('路由切换出错');
      }
    });
  }

  createComponent(url: any) {
    // 公告的提示信息
    if (url == "/taskpanelM/workcenter/mygg") {
      this.rRoom.remove(0);
      const ggmsgcomponent = this.cfr.resolveComponentFactory(CompMap['ggmsg']);
      const ggmsgcomp = this.rRoom.createComponent(ggmsgcomponent);
      ggmsgcomp.instance.data = {};
      ggmsgcomp.instance.outer.subscribe((resp) => {
        const typev = resp.type;
        if (typev == "closeggmsg") {
          this.rRoom.remove(0);
        }
      });

    } else {
      this.rRoom.remove(0);
    }
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值