亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

基于angular實現模擬微信小程序swiper組件

2019-11-19 16:22:12
字體:
來源:轉載
供稿:網友

這段時間的主業是完成一個家政類小程序,終于是過審核發布了。不得不說微信的這個小程序生態還是頗有想法的,拋開他現有的一些問題不說,其提供的組件系統乍一看還是蠻酷的。比如其提供的一個叫swiper的視圖組件,就可以在寫界面的時候省不少時間和代碼,輪播圖片跟可滑動列表都可以用。導致現在回來寫angular項目時也想整一個這樣的組件出來,本文就將使用angular的組件能力和服務能力完成這么一個比較通用,耦合度較低的swiper出來。

首先要選擇使用的技術,要實現的是與界面打交道的東西,自然是實現成一個組件,最終要實現的效果是寫下這樣的代碼就可以完成一個可以滑動的視圖來:

<swipers><swiper>視圖1</swiper><swiper>視圖2</swiper></swipers>

然后要把最基本的組件定義寫出來,顯然這里要定義兩個組件。第一個是父級組件,選擇器名字就叫ytm-swipers,目前做的事情僅僅是做一個外殼定義基本樣式,使用時的子標簽都會插入在ng-content標簽中。

@Component({  selector: 'ytm-swipers',  template: `    <div class="view-body">      <ng-content></ng-content>    </div>    `,  styles: [`    .view-body{height: 100%;width: 100%;overflow: hidden;position: relative;}  `]})

第二個就是子視圖了,在父級組件下,每個子組件都會沾滿父級組件,只有當前的子組件會顯示,當切換視圖時實際做的就是更改這些子組件的顯示方式,說的最簡單的話,這個子組件還是僅僅用來加一個子外殼,給外殼添加基本樣式,實際的頁面內容原封不動放在ng-content標簽中。

@Component({  selector: 'swiper',  template: `    <div class="view-child" *ngIf="swiper.displayList.indexOf(childId) >= 0"    [ngClass]="{'active': swiper.displayList[0] === childId,    'prev': swiper.displayList[2] === childId, 'next': swiper.displayList[1] === childId}">      <ng-content></ng-content>    </div>  `,  styles: [`    .view-child{      height: 100%;width: 100%;position: absolute;top: 0;      transition: 0.5s linear;background: #fff;      overflow-x: hidden;    }    .view-child.active{left: 0;z-index: 9;}    .view-child.next{left: 100%;z-index: 7;}    .view-child.prev{left: -100%;z-index: 8;}  `]})

下一步是要讓這兩個父子組件完成心靈的溝通,講道理其實可以直接使用ElementRef強行取到DOM來操作,不過這里使用的是組件內服務。和普通的服務使用上沒差別,不過其provider是聲明在某個組件里的,所以此服務只有在此組件以及子組件中可以注入使用。

@Injectable()class SwiperService {  public swiperList: number[];  public displayList: number[]; // 0為當前 1為下一個 2為上一個  public current: number;  private changing: boolean;  constructor() {    this.changing = false;    this.swiperList = [];    this.displayList = [];    this.current = 0;  }  public Add(id: number) {    this.swiperList.push(id);    switch (this.swiperList.length) {      case 1:        this.displayList[0] = id;        return;      case 2:        this.displayList[1] = id;        return;      default:        this.displayList[2] = id;        return;    }  }  public Next(): Promise<any> {    if (this.changing) {      return new Promise<any>((resolve, reject) => {        return reject('on changing');      });    }    this.changing = true;    let c = this.swiperList.indexOf(this.displayList[0]);    let n = this.swiperList.indexOf(this.displayList[1]);    let p = this.swiperList.indexOf(this.displayList[2]);    p = c;    c = n;    n = (c + 1) % this.swiperList.length;    this.displayList[0] = this.swiperList[c];    this.displayList[2] = this.swiperList[p];    this.displayList[1] = -1;    setTimeout(() => {      this.displayList[1] = this.swiperList[n];      this.changing = false;    }, 500);    return new Promise<any>((resolve, reject) => {      return resolve(this.displayList[0]);    });  }  public Prev(): Promise<any> {    if (this.changing) {      return new Promise<any>((resolve, reject) => {        return reject('on changing');      });    }    this.changing = true;    let c = this.swiperList.indexOf(this.displayList[0]);    let n = this.swiperList.indexOf(this.displayList[1]);    let p = this.swiperList.indexOf(this.displayList[2]);    n = c;    c = p;    p = p - 1 < 0 ? this.swiperList.length - 1 : p - 1;    this.displayList[0] = this.swiperList[c];    this.displayList[1] = this.swiperList[n];    this.displayList[2] = -1;    setTimeout(() => {      this.displayList[2] = this.swiperList[p];      this.changing = false;    }, 500);    return new Promise<any>((resolve, reject) => {      return resolve(this.displayList[0]);    });  }  public Skip(index: number): Promise<any> {    let c = this.swiperList.indexOf(this.displayList[0]);    if (this.changing || c === index) {      return new Promise<any>((resolve, reject) => {        reject('on changing or no change');      });    }    this.changing = true;    let n = (index + 1) % this.swiperList.length;    let p = index - 1 < 0 ? this.swiperList.length - 1 : index - 1;    this.displayList[0] = this.swiperList[index];    if (index > c) {      this.displayList[2] = this.swiperList[p];      this.displayList[1] = -1;      setTimeout(() => {        this.displayList[1] = this.swiperList[n];        this.changing = false;      }, 500);      return new Promise<any>((resolve, reject) => {        return resolve(this.displayList[0]);      });    } else {      this.displayList[1] = this.swiperList[n];      this.displayList[2] = -1;      setTimeout(() => {        this.displayList[2] = this.swiperList[p];        this.changing = false;      }, 500);      return new Promise<any>((resolve, reject) => {        return resolve(this.displayList[0]);      });    }  }}

用到的變量包括: changing變量保證同時只能進行一個切換,保證切換完成才能進行下一個切換;swiperList裝填所有的視圖的id,這個id在視圖初始化的時候生成;displayList數組只會有三個成員,裝填的依次是當前視圖在swiperList中的索引,下一個視圖的索引,上一個視圖的索引;current變量用戶指示當前顯示的視圖的id。實際視圖中的顯示的控制就是使用ngClass指令來根據displayList和視圖id附加相應的類,當前視圖會正好顯示,前一視圖會在左邊剛好遮擋,后一視圖會在右邊剛好遮擋。

同時服務還要提供幾個方法:Add用于添加制定id的視圖,Next用于切換到下一個視圖(左滑時調用),Prev用于切換到前一個視圖(右滑時調用),再來一個Skip用于直接切換到指定id的視圖。

在子視圖中注入此服務,需要在子視圖初始化時生成一個id并Add到視圖列表中:

export class YTMSwiperViewComponent {
    public childId: number;
    constructor(@Optional() @Host() public swiper: SwiperService) {
        this.childId = this.swip

@Injectable()class SwiperService {  public swiperList: number[];  public displayList: number[]; // 0為當前 1為下一個 2為上一個  public current: number;  private changing: boolean;  constructor() {    this.changing = false;    this.swiperList = [];    this.displayList = [];    this.current = 0;  }  public Add(id: number) {    this.swiperList.push(id);    switch (this.swiperList.length) {      case 1:        this.displayList[0] = id;        return;      case 2:        this.displayList[1] = id;        return;      default:        this.displayList[2] = id;        return;    }  }  public Next(): Promise<any> {    if (this.changing) {      return new Promise<any>((resolve, reject) => {        return reject('on changing');      });    }    this.changing = true;    let c = this.swiperList.indexOf(this.displayList[0]);    let n = this.swiperList.indexOf(this.displayList[1]);    let p = this.swiperList.indexOf(this.displayList[2]);    p = c;    c = n;    n = (c + 1) % this.swiperList.length;    this.displayList[0] = this.swiperList[c];    this.displayList[2] = this.swiperList[p];    this.displayList[1] = -1;    setTimeout(() => {      this.displayList[1] = this.swiperList[n];      this.changing = false;    }, 500);    return new Promise<any>((resolve, reject) => {      return resolve(this.displayList[0]);    });  }  public Prev(): Promise<any> {    if (this.changing) {      return new Promise<any>((resolve, reject) => {        return reject('on changing');      });    }    this.changing = true;    let c = this.swiperList.indexOf(this.displayList[0]);    let n = this.swiperList.indexOf(this.displayList[1]);    let p = this.swiperList.indexOf(this.displayList[2]);    n = c;    c = p;    p = p - 1 < 0 ? this.swiperList.length - 1 : p - 1;    this.displayList[0] = this.swiperList[c];    this.displayList[1] = this.swiperList[n];    this.displayList[2] = -1;    setTimeout(() => {      this.displayList[2] = this.swiperList[p];      this.changing = false;    }, 500);    return new Promise<any>((resolve, reject) => {      return resolve(this.displayList[0]);    });  }  public Skip(index: number): Promise<any> {    let c = this.swiperList.indexOf(this.displayList[0]);    if (this.changing || c === index) {      return new Promise<any>((resolve, reject) => {        reject('on changing or no change');      });    }    this.changing = true;    let n = (index + 1) % this.swiperList.length;    let p = index - 1 < 0 ? this.swiperList.length - 1 : index - 1;    this.displayList[0] = this.swiperList[index];    if (index > c) {      this.displayList[2] = this.swiperList[p];      this.displayList[1] = -1;      setTimeout(() => {        this.displayList[1] = this.swiperList[n];        this.changing = false;      }, 500);      return new Promise<any>((resolve, reject) => {        return resolve(this.displayList[0]);      });    } else {      this.displayList[1] = this.swiperList[n];      this.displayList[2] = -1;      setTimeout(() => {        this.displayList[2] = this.swiperList[p];        this.changing = false;      }, 500);      return new Promise<any>((resolve, reject) => {        return resolve(this.displayList[0]);      });    }  }}er.swiperList.length;
        this.swiper.Add(this.swiper.swiperList.length);
    }
}

這個id其實就是已有列表的索引累加,且一旦有新視圖被初始化,都會添加到列表中(支持動態加入很酷,雖然不知道會有什么隱藏問題發生)。

父組件中首先必須要配置一個provider聲明服務:

@Component({  selector: 'ytm-swipers',  template: `    <div class="view-body">      <ng-content></ng-content>    </div>    `,  styles: [`    .view-body{height: 100%;width: 100%;overflow: hidden;position: relative;}  `],  providers: [SwiperService]})

然后就是要監聽手勢滑動事件,做出相應的切換。以及傳入一個current變量,每當此變量更新時都要切換到對應id的視圖去,實際使用效果就是:

<ytm-swipers [current]="1">...</ytm-swipers>可以將視圖切換到id喂1的視圖也就是第二個視圖。

 export class YTMSwiperComponent implements OnChanges {  @Input() public current: number;  @Output() public onSwiped = new EventEmitter<Object>();  private touchStartX;  private touchStartY;  constructor(private swiper: SwiperService) {    this.current = 0;  }  public ngOnChanges(sc: SimpleChanges) {    if (sc.current && sc.current.previousValue !== undefined &&    sc.current.previousValue !== sc.current.currentValue) {      this.swiper.Skip(sc.current.currentValue).then((id) => {        console.log(id);        this.onSwiped.emit({current: id, bySwipe: false});      }).catch((err) => {        console.log(err);      });    }  }  @HostListener('touchstart', ['$event']) public onTouchStart(e) {    this.touchStartX = e.changedTouches[0].clientX;    this.touchStartY = e.changedTouches[0].clientY;  }  @HostListener('touchend', ['$event']) public onTouchEnd(e) {    let moveX = e.changedTouches[0].clientX - this.touchStartX;    let moveY = e.changedTouches[0].clientY - this.touchStartY;    if (Math.abs(moveY) < Math.abs(moveX)) {      /**       * Y軸移動小于X軸 判定為橫向滑動       */      if (moveX > 50) {        this.swiper.Prev().then((id) => {          // this.current = id;          this.onSwiped.emit({current: id, bySwipe: true});        }).catch((err) => {          console.log(err);        });      } else if (moveX < -50) {        this.swiper.Next().then((id) => {          // this.current = id;          this.onSwiped.emit({current: id, bySwipe: true});        }).catch((err) => {          console.log(err);        });      }    }    this.touchStartX = this.touchStartY = -1;  }}

此外代碼中還添加了一個回調函數,可以再視圖完成切換時執行傳入的回調,這個使用的是angular的EventEmitter能力。

以上就是全部實現了,實際的使用示例像這樣:

<ytm-swipers [current]="0" (onSwiped)="切換回調($event)">   <swiper>     視圖1   </swiper>   <swiper>     視圖2   </swiper>   <swiper>     視圖3   </swiper> </ytm-swipers>

視圖的切換有了兩種方式,一是手勢滑動,不過沒有寫實時拖動,僅僅是判斷左右滑做出反應罷了,二是更新[current]節點的值。

整個組件的實現沒有使用到angular一些比較底層的能力,僅僅是玩弄css樣式以及組件嵌套并通過服務交互,以及Input、Output與外界交互。相比之下ionic的那些組件就厲害深奧多了,筆者還有很長的路要走。

以上所述是小編給大家介紹的基于angular實現模擬微信小程序swiper組件,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言小編會及時回復大家的!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人欧美一区二区三区在线湿哒哒| 国产精品午夜一区二区欲梦| 国产精品视频在线播放| 欧美一级视频在线观看| 日韩美女视频免费在线观看| 5278欧美一区二区三区| 国产成人综合精品在线| 国产视频精品在线| 国产精品7m视频| 91国内精品久久| 欧美精品一区二区免费| 国产精品亚洲美女av网站| 69**夜色精品国产69乱| 日韩禁在线播放| 亚洲乱码国产乱码精品精| 操人视频在线观看欧美| 亚洲理论片在线观看| 最近2019中文免费高清视频观看www99| 国产亚洲精品综合一区91| 国产精品一区二区性色av| 亚洲激情小视频| 亚洲毛茸茸少妇高潮呻吟| 色琪琪综合男人的天堂aⅴ视频| 久久久久久久爱| 2019中文字幕在线观看| 国自在线精品视频| 中文字幕精品在线| 亚洲国产欧美精品| 爱福利视频一区| 日韩av在线直播| 国产丝袜一区二区三区| 欧美性色视频在线| 久久久亚洲精品视频| 国产日韩在线播放| 91麻豆桃色免费看| 国产福利精品视频| 色哟哟入口国产精品| 国产日韩欧美在线视频观看| 日韩av中文字幕在线| 中文字幕在线看视频国产欧美在线看完整| 亚洲香蕉伊综合在人在线视看| 欧美老女人在线视频| 亚洲欧美成人精品| 欧美多人爱爱视频网站| 久久成人亚洲精品| 在线精品视频视频中文字幕| 一区二区欧美日韩视频| 色综合天天综合网国产成人网| 91精品在线播放| 久久久综合av| 日本中文字幕成人| 色狠狠av一区二区三区香蕉蜜桃| 国产精品视频yy9099| 法国裸体一区二区| 亚洲视频自拍偷拍| 久久精品国产久精国产一老狼| 九九热精品视频国产| 大胆人体色综合| 亚洲精品国精品久久99热一| 欧美激情一区二区三区在线视频观看| 欧美整片在线观看| 亚洲在线一区二区| 国产精品久久久久9999| 国产精品久久久久国产a级| 亚洲91精品在线| 成人综合国产精品| 91精品免费看| 欧美一区二区三区艳史| 亚洲午夜久久久久久久| 91久久精品久久国产性色也91| 日韩av在线电影网| 久久成人免费视频| 中文字幕精品www乱入免费视频| 精品动漫一区二区| 亚洲精品按摩视频| 亚洲成人久久久久| 欧美在线视频在线播放完整版免费观看| 91夜夜未满十八勿入爽爽影院| 国产一区二区三区久久精品| 亚洲精品福利免费在线观看| 亚洲欧美精品中文字幕在线| 国产在线精品播放| 91精品视频免费看| 日韩大陆欧美高清视频区| 国产精品久久久久久久久免费| 97人洗澡人人免费公开视频碰碰碰| 7777免费精品视频| 久久人91精品久久久久久不卡| 亚洲人av在线影院| 国产mv免费观看入口亚洲| 久久久伊人日本| 亚洲欧美制服丝袜| 欧美一级电影免费在线观看| 91精品国产777在线观看| 久久精品福利视频| 91精品免费视频| 日韩成人中文字幕| 国产精品老牛影院在线观看| 国产精品久久久久国产a级| 欧美另类在线播放| 亚洲精品成人网| 黑人巨大精品欧美一区二区免费| 久久久久北条麻妃免费看| 欧美大片在线看| 国产精品入口福利| 国产精品第七影院| 欧美肥老太性生活视频| 国产成人精品日本亚洲| y97精品国产97久久久久久| 欧美黑人视频一区| 久久99久久99精品免观看粉嫩| 91精品综合久久久久久五月天| 国产精品第三页| 日本91av在线播放| 中文字幕欧美视频在线| 亚洲黄色片网站| 亚洲免费影视第一页| 亚洲欧美中文日韩v在线观看| 51色欧美片视频在线观看| 日韩成人在线播放| 精品视频一区在线视频| 疯狂做受xxxx欧美肥白少妇| 亚洲欧美第一页| 尤物yw午夜国产精品视频| 精品国产一区二区三区久久久狼| 在线免费观看羞羞视频一区二区| 久久99亚洲热视| 国产亚洲在线播放| 欧美成人精品激情在线观看| 欧美午夜激情在线| 亚洲最大在线视频| 亚洲桃花岛网站| 成人免费视频网址| 久久免费视频观看| 久久精品青青大伊人av| 欧美二区在线播放| 国内久久久精品| 欧美一区二区色| www.国产一区| 国产精品自产拍在线观看中文| www.欧美精品一二三区| 欧美巨大黑人极品精男| 久久激情五月丁香伊人| 国产精品男人爽免费视频1| 久久久久久久电影一区| 国产日韩欧美影视| 日韩有码在线视频| 国产精品日韩专区| 欧美中文字幕视频在线观看| 国产精品视频中文字幕91| 26uuu另类亚洲欧美日本一| 中文.日本.精品| 欧美国产日韩精品| 欧美日韩一区二区免费视频| 91九色视频在线| 亚洲免费福利视频| 国产小视频91| 国产成人av在线播放| 欧美成人午夜免费视在线看片| 日韩免费看的电影电视剧大全| 国产日韩精品电影| 欧美日韩aaaa| 日韩电影第一页| 欧美激情在线观看视频|