ionic3+我的ionic

【Appetite】ionic3实录(七)次页实现及分析解决问题

2017-11-07  本文已影响426人  IT晴天

上一节提到几个问题,现在我们逐一来解释一下:

问题一:initSwiper方法为什么放在获取数据之后?它放在其它地方可以吗?此外,它上面为什么会放个this.cd.detectChanges()?

initSwiper() {
    new Swiper('.wheel .swiper-container', {
      slidesPerView: 2,
      initialSlide: 1,
      watchActiveIndex: true,
      centeredSlides: true,
      resizeReInit: true,
      keyboardControl: true,
      grabCursor: true
    });
  }

一般一些js插件,是依托dom的。我们观察initSwiper方法,第一个参数'.wheel .swiper-container'其实是个选择器,所以它也是依托dom操作的,此外,由于我们使用了数据绑定,this.vm.dessertSlides的值更新会影响到dom,所以应该在数据更新从而使得dom更新完成后再调用initSwiper方法。
angular的脏检测机制是基于一定条件和时间的,在给this.vm.dessertSlides赋值,dom还没更新完成就调用initSwiper方法不一定会获得想要结果的,所以在此之前调用手动检测方法this.cd.detectChanges()强制检测并刷新dom。

问题二:为什么用[hidden],不用*ngIf或者ngSwitch?

因为前者只是隐藏,而后两者是会移除。也就是说,前者只会初始化一次,而后两者每次显示都需要重新初始化,进一步说,若使用后两者方式,对于这里用到的swiper,它不是一个angular封装起来的组件,不会自动初始化,我们每次显示它时都需要显式调用一下initSwiper方法,这就有点繁琐还耗费性能。同理,有些组件要注意类似情况。这并不是说都不要用*ngIf,因为当页面元素太多时会容易导致界面卡顿,所以没用的多余元素应该移除,此时就用它。一句话说就是根据情况合理选择显示控制方法

问题三:<div class="swiper-container">标签内容能否换成注释掉的<ion-slides>内容?

这是当然可以的,因为ion-slides组件组件最终也是生成<div class="swiper-container">标签代码。

问题三的延伸:既然ion-slides已经是封装起来的控件了,我们用它不是可以省掉不少代码?

是的,在大多场景中可以直接用ion-slides,只是会有个别坑要解决,比如我们改动下ts和html文件。

ts中把initSwiper方法相关内容移除:

import { Component, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
import { NavController, Slides, PopoverController } from 'ionic-angular';
import { AboutProvider } from '../../providers/about/about';
import { ChatPage } from '../contact/chat/chat';

declare let Swiper: any;

@Component({
  selector: 'page-about',
  templateUrl: 'about.html'
})
export class AboutPage {

  @ViewChild(Slides) slides: Slides;
  vm: {
    dessertSlides: any[] ,    //轮播数据源
    dessertList: any[],    //甜点列表数据源
    selectedSegment: string    //segment选择对象
  } = {
    dessertSlides: [],
    dessertList: [],
    selectedSegment: 'one'
  };

  constructor(public navCtrl: NavController, private aboutProvider: AboutProvider, private cd: ChangeDetectorRef, private popoverController: PopoverController) {
  }

  ionViewDidLoad() {
    this.getDessertSlides();
    this.getDessertList();
  }

  /**
   * 获取甜点轮播图片
   */
  getDessertSlides(){
    return this.aboutProvider.getDessertSlides().then((rep: any) => {
      this.vm.dessertSlides = rep.result;
      return rep;
    });
  }

  /**
   * 获取甜点列表
   */
  getDessertList(){
    return this.aboutProvider.getDessertList().then((rep: any)=>{
      this.vm.dessertList = rep.result;
      return rep;
    });
  }
  }
}

html里用ion-slides:

<ion-content>
  <div [hidden]="vm.selectedSegment != 'one'" class="wheel">
     <ion-slides centeredSlides="true" slidesPerView="2" initialSlide="1" zoom="false" >
      <ion-slide *ngFor="let item of vm.dessertSlides">
        <img [src]="item.src" />
      </ion-slide>
    </ion-slides>     
    <div text-center *ngFor="let item of vm.dessertList" padding-left padding-right>
      <h5><strong>{{item.title}}</strong></h5>
      <p>{{item.desc}}</p>
      <img [src]="item.src" style="height: 140px; width: 100%;" />
    </div>
  </div>
  <div [hidden]="vm.selectedSegment !='two'" >
    <div text-center *ngFor="let item of dessertList" >
      <h5>{{item.title}}</h5>
      <p>{{item.desc}}</p>
      <img [src]="item.src" style="height: 140px; width: 100%;" />
    </div>
  </div>
  <div [hidden]="vm.selectedSegment != 'three'">
    三
  </div>
  <div [hidden]="vm.selectedSegment != 'four'">
    四
  </div>
</ion-content>

执行看下效果:


数据未正确应用

对比上一节的实际效果图,会发现这里只显示了两个图片,什么原因呢?是因为该组件在异步获取到数据this.vm.dessertSlides前已完成了初始化了,这样新数据其实没有应用到,为了处理这种情况,我们改造一下html,为ion-slides组件加上一段*ngIf="vm.dessertSlides && vm.dessertSlides.length>0"

    <ion-slides centeredSlides="true" slidesPerView="2" initialSlide="1" zoom="false"  *ngIf="vm.dessertSlides && vm.dessertSlides.length>0">
      <ion-slide *ngFor="let item of vm.dessertSlides">
        <img [src]="item.src" />
      </ion-slide>
    </ion-slides>   

这样当新数据有值且长度大于0时,才会显示ion-slides组件,进而内部进行初始化,此时运行看效果如下,只是此时有个比较突兀的2图向3图切换效果,有兴趣的可以试试:

数据正确应用
上一篇下一篇

猜你喜欢

热点阅读