這段時間的主業是完成一個家政類小程序,終于是過審核發布了。不得不說微信的這個小程序生態還是頗有想法的,拋開他現有的一些問題不說,其提供的組件系統乍一看還是蠻酷的。比如其提供的一個叫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]); }); } }}
新聞熱點
疑難解答