QQ登录

只需一步,快速开始

Angular笔记:组件间通讯

依梦瑶 发表于 2019-5-23 14:11:28 | 显示全部楼层 |阅读模式

一、输入属性

这里以主组件(AppComponent)和子组件(GoodsComponent)为例。

输入属性是一个单向绑定,父组件向子组件传值,可改变子组件里面的值,而子组件自身改变值的时候,父组件则不受影响。

父组件中的控制器代码:

  1. import {Component} from '@angular/core';
  2. @Component({
  3.   selector: 'app-root',
  4.   templateUrl: './app.component.html',
  5.   styleUrls: ['./app.component.css']
  6. })
  7. export class AppComponent {
  8.   private search: string;
  9.   constructor() {
  10.   }
  11. }
复制代码

父组件中的模板代码:

  1. <div>
  2.   <input placeholder="请输入搜索关键字" [(ngModel)]="search">
  3. </div>
  4. <app-goods [keyword]="search"></app-goods>
复制代码

子组件中接收传值的控制器代码:

  1. import {Component, Input, OnInit} from '@angular/core';
  2. @Component({
  3.   selector: 'app-goods',
  4.   templateUrl: './goods.component.html',
  5.   styleUrls: ['./goods.component.css']
  6. })
  7. export class GoodsComponent implements OnInit {
  8.   @Input()
  9.   private keyword: string;
  10.   constructor() {
  11.   }
  12.   ngOnInit() {
  13.     /**
  14.      * 在子组件中定时改变 keyword 的值,却不影响父组件
  15.      */
  16.     setInterval(() => {
  17.       this.keyword = 'IBM';
  18.     }, 3000);
  19.   }
  20. }
复制代码

子组件中的模板代码:

  1. <p>
  2.   goods works!
  3. </p>
  4. <p>
  5.   您搜索商品的关键字是:{{keyword}}
  6. </p>
复制代码

二、输出属性

继续用上两个组件,现在反过来,由子组件向父组件传值

父组件中的控制器代码:

  1. import {Component} from '@angular/core';
  2. import {GoodsInfo} from "./goods/goods.component";
  3. @Component({
  4.   selector: 'app-root',
  5.   templateUrl: './app.component.html',
  6.   styleUrls: ['./app.component.css']
  7. })
  8. export class AppComponent {
  9.   private search: string;
  10.   private price: number;
  11.   constructor() {
  12.   }
  13.   searchResultHandler(goodsInfo: GoodsInfo) {
  14.     this.price = goodsInfo.price;
  15.   }
  16. }
复制代码

父组件中的模板代码:

  1. <div>
  2.   <input placeholder="请输入搜索关键字" [(ngModel)]="search">
  3. </div>
  4. <p>
  5.   您搜索商品的关键字是:{{search}},它的价格是:{{price | number:'2.2-2'}}
  6. </p>
  7. <app-goods [keyword]="search" (searchResult)="searchResultHandler($event)"></app-goods>
复制代码

子组件中接收传值的控制器代码:

  1. import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
  2. @Component({
  3.   selector: 'app-goods',
  4.   templateUrl: './goods.component.html',
  5.   styleUrls: ['./goods.component.css']
  6. })
  7. export class GoodsComponent implements OnInit {
  8.   @Input()
  9.   private keyword: string;
  10.   private price: number;
  11.   // 向父组件发射
  12.   @Output()
  13.   searchResult: EventEmitter<GoodsInfo> = new EventEmitter();
  14.   constructor() {
  15.   }
  16.   ngOnInit() {
  17.     setInterval(() => {
  18.       // 随机产生价格
  19.       let goodsInfo: GoodsInfo = new GoodsInfo(this.keyword, 100 * Math.random());
  20.       this.price = goodsInfo.price;
  21.       this.searchResult.emit(goodsInfo);
  22.     }, 3000);
  23.   }
  24. }
  25. export class GoodsInfo {
  26.   constructor(public name: string,
  27.               public price: number) {
  28.   }
  29. }
复制代码

子组件中的模板代码:

  1. <p>
  2.   goods works!
  3. </p>
  4. <p>
  5.   您搜索商品的关键字是:{{keyword}},它的价格是:{{price | number:'2.2-2'}}
  6. </p>
复制代码

另外 Output 这里可以改变输出的接收名,比如:

  1. // 向父组件发射
  2. @Output('lastPrice')
  3. searchResult: EventEmitter<GoodsInfo> = new EventEmitter();
复制代码

那么父组件的接收端这里就要改成:

  1. <app-user-search [keyword]="search" (lastPrice)="searchResultHandler($event)"></app-user-search>
复制代码

三、中间人模式

在中间人模式这里,还是继续用上两个组件,增加一个购物车(ShopCartComponent)的组件,而 ShopCartComponent 和  GoodsComponent 则并不知彼此存在的情况下,通过  AppComponent 这个中间人的角色来传递数据。

GoodsComponent 控制器:

  1. import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
  2. @Component({
  3.   selector: 'app-goods',
  4.   templateUrl: './goods.component.html',
  5.   styleUrls: ['./goods.component.css']
  6. })
  7. export class GoodsComponent implements OnInit {
  8.   @Input()
  9.   private keyword: string;
  10.   private price: number;
  11.   // 向父组件发射
  12.   @Output()
  13.   searchResult: EventEmitter<GoodsInfo> = new EventEmitter();
  14.   @Output()
  15.   addCart: EventEmitter<GoodsInfo> = new EventEmitter();
  16.   constructor() {
  17.   }
  18.   ngOnInit() {
  19.     setInterval(() => {
  20.       // 随机产生价格
  21.       let goodsInfo: GoodsInfo = new GoodsInfo(this.keyword, 100 * Math.random());
  22.       this.price = goodsInfo.price;
  23.       this.searchResult.emit(goodsInfo);
  24.     }, 3000);
  25.   }
  26.   buyGoods() {
  27.     this.addCart.emit(new GoodsInfo(this.keyword, this.price));
  28.   }
  29. }
  30. export class GoodsInfo {
  31.   constructor(public name: string,
  32.               public price: number) {
  33.   }
  34. }
复制代码

GoodsComponent 模板:

  1. <p>
  2.   goods works!
  3. </p>
  4. <p>
  5.   您搜索商品的关键字是:{{keyword}},它的价格是:{{price | number:'2.2-2'}}
  6. </p>
  7. <p>
  8.   <button (click)="buyGoods()">buy</button>
  9. </p>
复制代码

ShopCartComponent 控制器:

  1. import {Component, Input, OnInit} from '@angular/core';
  2. import {GoodsInfo} from "../goods/goods.component";
  3. @Component({
  4.   selector: 'app-shop-cart',
  5.   templateUrl: './shop-cart.component.html',
  6.   styleUrls: ['./shop-cart.component.css']
  7. })
  8. export class ShopCartComponent implements OnInit {
  9.   @Input()
  10.   private goodsInfo: GoodsInfo;
  11.   constructor() {
  12.   }
  13.   ngOnInit() {
  14.   }
  15. }
复制代码

ShopCartComponent 模板:

  1. <div>
  2.   shop-cart works!
  3. </div>
  4. <div *ngIf="goodsInfo">
  5.   要购买的商品是:{{goodsInfo.name}},购买的价格是:{{goodsInfo.price}}
  6. </div>
复制代码

AppComponent 控制器:

  1. import {Component} from '@angular/core';
  2. import {GoodsInfo} from "./goods/goods.component";
  3. @Component({
  4.   selector: 'app-root',
  5.   templateUrl: './app.component.html',
  6.   styleUrls: ['./app.component.css']
  7. })
  8. export class AppComponent {
  9.   private goodsInfo: GoodsInfo;
  10.   addCartHandler(goodsInfo: GoodsInfo) {
  11.     this.goodsInfo = goodsInfo;
  12.   }
  13. }
复制代码

AppComponent 模板:

  1. <div>
  2.   <input placeholder="请输入搜索关键字" [(ngModel)]="search">
  3. </div>
  4. <app-goods [keyword]="search" (addCart)="addCartHandler($event)"></app-goods>
  5. <app-shop-cart [goodsInfo]="goodsInfo"></app-shop-cart>
复制代码

四、 组件生命周期钩子

4.1、观察各钩子的执行顺序

在这里用新的项目来演示效果,用的是主组件(AppComponent)和子组件(LifeComponent)。在 LifeComponent 组件中输入以下的代码,而在 AppComponent 中只需在模板放上 app-life 就可以了(这里就不多写了)。

  1. import {
  2.   AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, Input, OnChanges,
  3.   OnDestroy,
  4.   OnInit
  5. } from '@angular/core';
  6. let logIndex: number = 1;
  7. @Component({
  8.   selector: 'app-life',
  9.   templateUrl: './life.component.html',
  10.   styleUrls: ['./life.component.css']
  11. })
  12. export class LifeComponent implements OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {
  13.   @Input()
  14.   name: string;
  15.   logIt(msg: string) {
  16.     console.log(`#${logIndex++} ${msg}`);
  17.   }
  18.   constructor() {
  19.     this.logIt("name 属性在 constructor 里的值是:" + name);
  20.   }
  21.   ngOnInit() {
  22.     this.logIt("ngOnInit");
  23.   }
  24.   ngOnChanges(changes: SimpleChanges): void {
  25.     let name = changes['name'].currentValue;
  26.     this.logIt("name 属性在 ngOnChanges 里的值是:" + name);
  27.   }
  28.   ngDoCheck(): void {
  29.     this.logIt("ngDoCheck");
  30.   }
  31.   ngAfterContentInit(): void {
  32.     this.logIt("ngAfterContentInit");
  33.   }
  34.   ngAfterContentChecked(): void {
  35.     this.logIt("ngAfterContentChecked");
  36.   }
  37.   ngAfterViewInit(): void {
  38.     this.logIt("ngAfterViewInit");
  39.   }
  40.   ngAfterViewChecked(): void {
  41.     this.logIt("ngAfterViewChecked");
  42.   }
  43.   ngOnDestroy(): void {
  44.     this.logIt("ngOnDestroy");
  45.   }
  46. }
复制代码

运行之后的效果图:

1.png

4.2、观察变更检测机制:ngOnChanges、ngDoCheck

在 angular2 中变量检测机制是由 zone.js 来实现的,它的主题是保证属性的变化和页面的变化是同步的,浏览器里面发生的任何异步事件都会触发变更检测。

在这里也用新的项目方案来演示,主要用到两个组件分别是主组件(AppComponent)和子组件(ChildComponen)。

AppComponent 控制器代码:

  1. import { Component } from '@angular/core';
  2. @Component({
  3.   selector: 'app-root',
  4.   templateUrl: './app.component.html',
  5.   styleUrls: ['./app.component.css']
  6. })
  7. export class AppComponent {
  8.   greeting: string = "Hello";
  9.   user: {name: string} = {name: "IBM"};
  10. }
复制代码

AppComponent 模板代码:

  1. <div>
  2.   Parent Works!
  3. </div>
  4. <div>
  5.   问候语:<input type="text" [(ngModel)]="greeting">
  6. </div>
  7. <div>
  8.   姓名:<input type="text" [(ngModel)]="user.name">
  9. </div>
  10. <app-child [greeting]="greeting" [user]="user"></app-child>
复制代码

ChildComponen 控制器代码:

  1. import {Component, DoCheck, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
  2. @Component({
  3.   selector: 'app-child',
  4.   templateUrl: './child.component.html',
  5.   styleUrls: ['./child.component.css']
  6. })
  7. export class ChildComponent implements OnInit, OnChanges, DoCheck {
  8.   @Input()
  9.   greeting: string;
  10.   @Input()
  11.   user: { name: string };
  12.   message: string = "初始化消息";
  13.   // 用来保存在变更之前老的值
  14.   oldGreeting: string;
  15.   oldUserName: string;
  16.   // 用来标识当前的属性是否发生了变化
  17.   greetingChangeDetected: boolean;
  18.   userNameChangeDetected: boolean;
  19.   // 用来记录当前改变变更检测 ngDoCheck 方法被调用的次数
  20.   greetingChangeCount: number = 0;
  21.   userNameChangeCount: number = 0;
  22.   constructor() {
  23.   }
  24.   ngOnInit() {
  25.   }
  26.   /**
  27.    * 当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit之前。
  28.    * @param {SimpleChanges} changes
  29.    */
  30.   ngOnChanges(changes: SimpleChanges): void {
  31.     console.log(JSON.stringify(changes, null, 2));
  32.   }
  33.   /**
  34.    * 变更检测发生时会被调用
  35.    * 变量检测不一定是 user.name 发生变化,有可能是其他事件发生变化,包括鼠标点击、或者是按键盘都会发生。
  36.    */
  37.   ngDoCheck(): void {
  38.     if (this.greeting !== this.oldGreeting) {
  39.       // greetingChangeDetected 发生了变化
  40.       this.greetingChangeDetected = true;
  41.       console.log(`DoCheck: greeting 从${this.oldGreeting}变为:${this.greeting}`);
  42.       this.oldGreeting = this.greeting;
  43.     }
  44.     if (this.user.name !== this.oldUserName) {
  45.       // user name 发生了变化
  46.       this.userNameChangeDetected = true;
  47.       console.log(`DoCheck: user.name 从${this.oldUserName}变为:${this.user.name}`);
  48.       this.oldUserName = this.user.name;
  49.     }
  50.     if (this.greetingChangeDetected) {
  51.       // 如果变了调用次数就清零
  52.       this.greetingChangeCount = 0;
  53.     } else {
  54.       // 如果没有发生改变
  55.       this.greetingChangeCount += 1;
  56.       console.log(`DoCheck: greeting 没有变化时,ngDoCheck方法被调用了${this.greetingChangeCount}次`);
  57.     }
  58.     // 复位
  59.     this.greetingChangeDetected = false;
  60.     if (this.userNameChangeDetected) {
  61.       // 如果变了调用次数就清零
  62.       this.userNameChangeCount = 0;
  63.     } else {
  64.       // 如果没有发生改变
  65.       this.userNameChangeCount += 1;
  66.       console.log(`DoCheck: user.name 没有变化时,ngDoCheck方法被调用了${this.userNameChangeCount}次`);
  67.     }
  68.     // 复位
  69.     this.userNameChangeDetected = false;
  70.   }
  71. }
复制代码

ChildComponen 模板代码:

  1. <p>
  2.   child works!
  3. </p>
  4. <div>
  5.   问候语:{{greeting}}<br>
  6.   姓名:{{user.name}}<br>
  7.   消息(非输入属性):<input type="text" [(ngModel)]="message">
  8. </div>
复制代码

运行之后的效果:

GIF-3.gif

4.3、观察变更检测机制:ngAfterViewInit 和 ngAfterViewInit

这里将演示的是父组件调用子组件里面的方法。

和上一节一样也采用主要用到两个组件分别是主组件(AppComponent)和子组件(ChildComponen)。

ChildComponen 控制器代码:

  1. import {AfterViewChecked, AfterViewInit, Component, OnInit} from '@angular/core';
  2. @Component({
  3.   selector: 'app-child',
  4.   templateUrl: './child.component.html',
  5.   styleUrls: ['./child.component.css']
  6. })
  7. export class ChildComponent implements OnInit, AfterViewInit, AfterViewChecked {
  8.   constructor() {
  9.   }
  10.   ngOnInit() {
  11.   }
  12.   ngAfterViewInit(): void {
  13.     console.log("子组件的视图初始化完毕");
  14.   }
  15.   ngAfterViewChecked(): void {
  16.     console.log("子组件的视图变更检测完毕");
  17.   }
  18.   getUserName(name: string) {
  19.     console.log(`Hello ${name}`);
  20.   }
  21. }
复制代码

ChildComponen 模板代码:

  1. <div>
  2.   child works!
  3. </div>
复制代码

AppComponent 控制器代码:

  1. import {AfterViewChecked, AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
  2. import {ChildComponent} from "./child/child.component";
  3. @Component({
  4.   selector: 'app-root',
  5.   templateUrl: './app.component.html',
  6.   styleUrls: ['./app.component.css']
  7. })
  8. export class AppComponent implements OnInit, AfterViewInit, AfterViewChecked {
  9.   @ViewChild('child1')
  10.   child1: ChildComponent;
  11.   message: string;
  12.   ngOnInit(): void {
  13.     // 在这里 angular 通过模板变量的名字,找到了相应的子组件
  14.     setInterval(()=>{
  15.       this.child1.getUserName("Ali");
  16.     }, 5000);
  17.   }
  18.   ngAfterViewInit(): void {
  19.     console.log("父组件的视图初始化完毕");
  20.     /**
  21.      * 在 ngAfterViewInit 和 ngAfterViewChecked 直接改变属性的这个写法量错误的。
  22.      * 在变更检测期中 angular 是禁止在视图已经被组装好之后再被去更新这个视图的。
  23.      * 这里 angular 自身的规定。
  24.      * ngAfterViewInit 和 ngAfterViewChecked 是在视图组合好去触发的。
  25.      */
  26.     // this.message = "hello";
  27.     /**
  28.      * 要解决上个问题,要把这个改变放到另一个循环里头去。
  29.      * 让它在另一个 javascript 运行周期中去运行就好了。
  30.      */
  31.     setTimeout(()=>{
  32.       this.message = "Hello";
  33.     }, 0);
  34.   }
  35.   ngAfterViewChecked(): void {
  36.     console.log("父组件的视图变更检测完毕");
  37.   }
  38. }
复制代码

AppComponent 模板代码:

  1. <app-child #child1></app-child>
  2. <app-child #child2></app-child>
  3. <!--在父组件的模板中调用子组件的方法-->
  4. <button (click)="child2.getUserName('google')">调用child2的greeting方法</button>
复制代码

运行之后的效果图:

2.png

需要注意的几点:

  • 上图中的“A”,从执行的顺序来看,如果父组件的视图想要被完全的组装好,那么首先所有子组件的视图也需要事先先被组装好。
  • ngAfterViewInit 只会首次执行初始化时被调用,只被调用一次。如上图中的“B”,后面的执行都是 ngAfterViewChecked
  • ngAfterViewChecked 这里代码尽量做到精简,以免影响性能。

五、ngContent 指令

ngContent 指令是一个投影的效果,它的作用就是在运行时动态的去改变组件模板里边的内容的这种效果。

5.1、简单的做法

这里也使用两个组件分别是主组件(AppComponent)和子组件(ChildComponen)来演示。

AppComponent 模板代码:

  1. <app-child>
  2.   <div>父组件里面的自定义内容</div>
  3. </app-child>
复制代码

ChildComponen 模板代码:

  1. <div>
  2.   child works!
  3. </div>
  4. <div style="border: 1px solid red;">
  5.   <ng-content></ng-content>
  6. </div>
复制代码

3.png

图 5.1、例5.1实例运行效果图

5.2、有多个的情况

AppComponent 模板代码:

  1. <app-child>
  2.   <div class="red">父组件里面的自定义内容</div>
  3.   <div class="green">父组件里面的自定义内容</div>
  4. </app-child>
复制代码

ChildComponen 模板代码:

  1. <div>
  2.   child works!
  3. </div>
  4. <div style="border: 1px solid red;">
  5.   <ng-content select=".red"></ng-content>
  6. </div>
  7. <div style="border: 1px solid red;">
  8.   <ng-content select=".green"></ng-content>
  9. </div>
复制代码

4.png

图 5.2、例5.2实例运行效果图

六、 最后的钩子 ngAfterContentInit 和 ngAfterContentChecked

6.1、简单的看下执行的顺序

AppComponent 控制器代码:

  1. import {AfterContentChecked, AfterContentInit, AfterViewInit, Component} from '@angular/core';
  2. @Component({
  3.   selector: 'app-root',
  4.   templateUrl: './app.component.html',
  5.   styleUrls: ['./app.component.css']
  6. })
  7. export class AppComponent implements AfterContentInit, AfterContentChecked, AfterViewInit {
  8.   ngAfterContentInit(): void {
  9.     console.log("父组件投影内容初始化完毕");
  10.   }
  11.   ngAfterContentChecked(): void {
  12.     console.log("父组件投影内容变更检测完毕");
  13.   }
  14.   ngAfterViewInit(): void {
  15.     console.log("父组件视图内容初始化完毕");
  16.   }
  17. }
复制代码

ChildComponen 控制器代码:

  1. import {AfterContentChecked, AfterContentInit, AfterViewInit, Component, OnInit} from '@angular/core';
  2. @Component({
  3.   selector: 'app-child',
  4.   templateUrl: './child.component.html',
  5.   styleUrls: ['./child.component.css']
  6. })
  7. export class ChildComponent implements OnInit, AfterContentInit, AfterContentChecked, AfterViewInit {
  8.   ngAfterContentInit(): void {
  9.     console.log("子组件投影内容初始化完毕");
  10.   }
  11.   ngAfterContentChecked(): void {
  12.     console.log("子组件投影内容变更检测完毕");
  13.   }
  14.   ngAfterViewInit(): void {
  15.     console.log("子组件视图内容初始化完毕");
  16.   }
  17.   constructor() {
  18.   }
  19.   ngOnInit() {
  20.   }
  21. }
复制代码

5.png

图6.1、运行后的效果

在 ngAfterContentInit 和 ngAfterContentChecked 中是可以修改属性的值,如在 ChildComponent 中输入以下代码会被正常的执行

  1. import {AfterContentChecked, AfterContentInit, AfterViewInit, Component, OnInit} from '@angular/core';
  2. @Component({
  3.   selector: 'app-child',
  4.   templateUrl: './child.component.html',
  5.   styleUrls: ['./child.component.css']
  6. })
  7. export class ChildComponent implements OnInit, AfterContentInit, AfterContentChecked, AfterViewInit {
  8.   message: string = "Hello";
  9.   ngAfterContentInit(): void {
  10.     console.log("子组件投影内容初始化完毕");
  11.     this.message = "Hello world";
  12.   }
  13.   ngAfterContentChecked(): void {
  14.     console.log("子组件投影内容变更检测完毕");
  15.   }
  16.   ngAfterViewInit(): void {
  17.     console.log("子组件视图内容初始化完毕");
  18.   }
  19.   constructor() {
  20.   }
  21.   ngOnInit() {
  22.   }
  23. }
复制代码

然后在模板里面加上:

  1. <div>
  2.   child works!
  3. </div>
  4. <div style="border: 1px solid red;">
  5.   <ng-content select=".red"></ng-content>
  6. </div>
  7. <div style="border: 1px solid red;">
  8.   <ng-content select=".green"></ng-content>
  9. </div>
  10. <div>{{message}}</div>
复制代码

6.png

七、最后 ngOnDestroy

继续上(六)的项目,添加了 Child2Component, 这里将使用路由,路由的配置就不多写,主要记下关键的几步,分别改写它们的模板和控制器。模板的代码也不多写了。主要是控制器的代码。

ChildComponent 和 Child2Component 的控制器相似:

  1. export class Child2Component implements OnInit, OnDestroy {
  2.   ngOnDestroy(): void {
  3.     console.log('Child2Component 被销毁');
  4.   }
  5.   constructor() { }
  6.   ngOnInit() {
  7.   }
  8. }
复制代码

GIF-4.gif

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精华推荐
  • 探究!做设计之前的“构思”

    探究!做设计之前的“构思”

  • 汉字之美!中文字体设计原则

    汉字之美!中文字体设计原则

  • 一支互联网雪糕的诞生

    一支互联网雪糕的诞生

  • 设计灵感来自何处?

    设计灵感来自何处?

  • 自行车停靠架和旧自行车变废为宝家居创意作品大全

    自行车停靠架和旧自行车变废为宝家居创意作

  • 造车生死局:要么转型,要么死

    造车生死局:要么转型,要么死

  • 从欠8千万到年赚8亿

    从欠8千万到年赚8亿

  • 一座非典型五线小城的日常

    一座非典型五线小城的日常

QQ客服热线
QQ:1090281100 周一至周日:09:00 - 21:00
WeChat:duzhe1069
Email:kaixin1069@vip.qq.com

优创意logo

勿要吝啬你无形资产,请为创新续源,知识、点子、灵感、经验、需求等均是创新源泉,你不经意的一句话将是另一个人的灵感。明天的明天,还有明天,我们应该把握今天,每一个今天,都有一个新的事物在出现,今天的漠视明天的落后,不浪费每一个学习的时刻,学习助力非凡。

技术支持 Discuz! X3.4 - 3.5 beta © 2001-2019 Comsenz Inc.

小黑屋|手机版|优创意 ( 粤ICP备16085288号-1 )|申请友链

粤公网安备 44011102001144 号 GMT+8, 2020-10-31 00:45 , Processed in 0.104392 second(s), 28 queries , Gzip On.

快速回复 返回顶部 返回列表