###### tags: `Web` `FrontEnd` `Vue` `Nuxt` # Photoswipe使用Vue封裝(TypeScript)並建立畫廊(Gallery)顯示與撥放功能 **## 注意:本文使用Material UI套件為 [Vuetify](https://vuetifyjs.com/en/)** ## 一、安裝 ### a.使用npm安裝 PhotoSwipe `npm install photoswipe` 使用ts的,需再安裝 `npm install --save @types/photoswipe` ### b.安裝後新增VPhotoSwipe.vue檔案 ## 二、新增VPhotoSwipe並封裝PhotoSwipe ### a. 新增HTML Template Code [根據官網使用說明直接複製Html Code](https://reurl.cc/NZ1xl5) ```=Html <!-- Root element of PhotoSwipe. Must have class pswp. --> <div ref="pswp" class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> <!-- Background of PhotoSwipe. It's a separate element, as animating opacity is faster than rgba(). --> <div class="pswp__bg"></div> <!-- Slides wrapper with overflow:hidden. --> <div class="pswp__scroll-wrap"> <!-- Container that holds slides. PhotoSwipe keeps only 3 slides in DOM to save memory. --> <div class="pswp__container"> <!-- don't modify these 3 pswp__item elements, data is added later on --> <div class="pswp__item"></div> <div class="pswp__item"></div> <div class="pswp__item"></div> </div> <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. --> <div class="pswp__ui pswp__ui--hidden"> <div class="pswp__top-bar"> <!-- Controls are self-explanatory. Order can be changed. --> <div class="pswp__counter"></div> <button class="pswp__button pswp__button--close" title="Close (Esc)"></button> <button class="pswp__button pswp__button--share" title="Share"></button> <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button> <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button> <!-- element will get class pswp__preloader--active when preloader is running --> <div class="pswp__preloader"> <div class="pswp__preloader__icn"> <div class="pswp__preloader__cut"> <div class="pswp__preloader__donut"></div> </div> </div> </div> </div> <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> <div class="pswp__share-tooltip"></div> </div> <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"> </button> <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"> </button> <div class="pswp__caption"> <div class="pswp__caption__center"></div> </div> </div> </div> </div> ``` ### b.新增Sytle部分,Import PhotoSwipe Package CSS file ```=CSS @import 'photoswipe/dist/photoswipe.css'; @import 'photoswipe/dist/default-skin/default-skin.css'; ``` ### c.新增TypeScipt部分 #### Import Import PhotoSwipe 與 PhotoSwipeUIDefault ```=TypeScript import PhotoSwipe from 'PhotoSwipe'; import PhotoSwipeUIDefault from 'PhotoSwipe/dist/photoswipe-ui-default'; ``` #### 使用Ref讀取Dom Content Html部分將ref pswp置入 ```=Html <div ref="pswp" class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> ``` 宣告Dom Element ```=TypeScript @Ref('pswp') private readonly pswpElement!: any; ``` #### 宣告Image Items,給外部使用做傳遞 ```=TypeScript @Prop() private items!: PhotoSwipe.Item[]; ``` #### [設定options](https://photoswipe.com/documentation/options.html) ```=TypeScript private options = { history: false, focus: false, showAnimationDuration: 0, hideAnimationDuration: 0 }; ``` #### 新增OpenPhotoSwipe Function ```=TypeScript public OpenPhotoSwipe(index: number): void { const phtoswipe = new PhotoSwipe( this.pswpElement, PhotoSwipeUIDefault, this.items, this.options ); phtoswipe.init(); phtoswipe.goTo(index); } ``` ## 三、新增Gallery.vue Component,並使用封裝的VPhotoSwipe ### a. 撰寫TypeScript #### 新增 PhotoImage Model ```=TypeScript export interface PhotoImage{ id:number; src:string; w:number; h:number; } ``` 宣告imgae,給外部使用做傳遞 ```=TypeScript @Prop() private images!: PhotoImage[]; ``` Import 撰寫的 VPhotoSwipe ```=TypeScript import VPhotoSwipe from '~/yourpath/VPhotoSwipe.vue'; ``` 宣告使用VPhotoSwipe OpenPhotoSwipe方法 ```=TypeScript @Ref('photo-swipe') private readonly photoSwipe!: InstanceType<typeof VPhotoSwipe>; OnOpenPhotoSwipe(index: number): void { this.photoSwipe.OpenPhotoSwipe(index); } ``` #### Html Code ```=Html <div> <v-photo-swipe ref="photo-swipe" :items="images"></v-photo-swipe> <v-row no-gutters> <v-col v-for="item in images" :key="item.id" class="d-flex child-flex" cols="6" sm="4" > <v-card flat tile class="d-flex" @click="OnOpenPhotoSwipe(item.id)"> <v-img :src="item.src" aspect-ratio="1.5" class="grey lighten-2"> <template #placeholder> <v-row class="fill-height ma-0" align="center" justify="center"> <v-progress-circular indeterminate color="grey lighten-5" ></v-progress-circular> </v-row> </template> </v-img> </v-card> </v-col> </v-row> </div> ``` ## 四、使用Gallery Component ### Import Gallery Component 與 Gallery 的 PhotoImage Model ```=TypeScript import { PhotoImage } from '~/yourpath/Gallery.vue'; import Gallery from '@/yourpath/Gallery.vue'; @Component({ layout: 'home-stay', components: { Gallery, }, }) ``` ### 宣告Images資料 ```=TypeScript private images : PhotoImage[] = [{ id:0, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-01-free-img.jpg', w: 1024, h: 964, }, { id:1, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-02-free-img.jpg', w: 1024, h: 964, }, { id:2, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-03-free-img.jpg', w: 1024, h: 500, }, { id:3, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-04-free-img.jpg', w: 1024, h: 964, }, { id:4, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-05-free-img.jpg', w: 1024, h: 964, }, { id:5, src: 'https://websitedemos.net/home-stay-04/wp-content/uploads/sites/811/2021/04/gallery-06-free-img.jpg', w: 1024, h: 500, }, ``` ### Html使用 ```=Html <v-col cols="12"> <gallery :images="images"></gallery> </v-col> ``` ## 五、效果 ![](https://i.imgur.com/T2WDVVj.jpg) ![](https://i.imgur.com/85tTdaK.jpg)