Merge pull request #47 from KevinMidboe/feature/lazy-loading-images
Lazy loading for list items.
This commit is contained in:
		| @@ -1,11 +1,12 @@ | |||||||
| <template> | <template> | ||||||
|   <li class="movies-item" :class="{'shortList': shortList}"> |   <li class="movies-item" :class="{'shortList': shortList}"> | ||||||
|     <a class="movies-item__link" :class="{'no-image': noImage}" @click.prevent="openMoviePopup(movie.id, movie.type)"> |     <a class="movies-item__link" :class="{'no-image': !movie}" @click.prevent="openMoviePopup(movie.id, movie.type)"> | ||||||
|  |  | ||||||
|       <!-- TODO change to picture element --> |       <!-- TODO change to picture element --> | ||||||
|       <figure class="movies-item__poster"> |       <figure class="movies-item__poster"> | ||||||
|         <img v-if="!noImage" class="movies-item__img" src="~assets/placeholder.png" v-img="poster()" alt=""> |         <img v-if="movie.poster" class="movies-item__img is-loaded" ref="image" src="~assets/placeholder.png"> | ||||||
|         <img v-if="noImage" class="movies-item__img is-loaded" src="~assets/no-image.png" alt=""> |         <!--        <img class="movies-item__img is-loaded" ref="image" :data-src="posterUrl" src="~assets/placeholder.png"> --> | ||||||
|  |         <!--        <img v-if="poster === null" class="movies-item__img is-loaded" src="~assets/no-image.png" alt=""> --> | ||||||
|  |  | ||||||
|         <div v-if="movie.download" class="progress"> |         <div v-if="movie.download" class="progress"> | ||||||
|           <progress :value="movie.download.progress" max="100"></progress> |           <progress :value="movie.download.progress" max="100"></progress> | ||||||
| @@ -24,24 +25,70 @@ | |||||||
| import img from '../directives/v-image' | import img from '../directives/v-image' | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   props: ['movie', 'shortList'], |   props: { | ||||||
|  |     movie: { | ||||||
|  |       type: Object, | ||||||
|  |       required: true | ||||||
|  |     }, | ||||||
|  |     shortList: { | ||||||
|  |       type: Boolean, | ||||||
|  |       required: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   directives: { |   directives: { | ||||||
|     img: img |     img: img | ||||||
|   }, |   }, | ||||||
|   data(){ |   data(){ | ||||||
|     return { |     return { | ||||||
|       noImage: false |       posterSizes: [{ | ||||||
|  |         id: 'w500', | ||||||
|  |         minWidth: 500 | ||||||
|  |       }, { | ||||||
|  |         id: 'w342', | ||||||
|  |         minWidth: 342 | ||||||
|  |       }, { | ||||||
|  |         id: 'w185', | ||||||
|  |         minWidth: 185 | ||||||
|  |       }, { | ||||||
|  |         id: 'w154', | ||||||
|  |         minWidth: 0 | ||||||
|  |       }] | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   computed: { | ||||||
|     // TODO handle missing images better and load diff sizes based on screen size |     posterUrl: function() { | ||||||
|     poster() { |       if (this.movie.poster == null) | ||||||
|       if (this.movie.poster) { |         return "~assets/no-image.png" | ||||||
|         return 'https://image.tmdb.org/t/p/w500' + this.movie.poster |  | ||||||
|       } else { |       const correctWidth = this.posterQualityIdentifierFromPosterWidth | ||||||
|         this.noImage = true |  | ||||||
|       } |       return `https://image.tmdb.org/t/p/${correctWidth}${this.movie.poster}` | ||||||
|     }, |     }, | ||||||
|  |     posterQualityIdentifierFromPosterWidth: function() { | ||||||
|  |       const posterWidth = this.$refs.image.clientHeight | ||||||
|  |       if (posterWidth > this.posterSizes[0].minWidth) | ||||||
|  |         return this.posterSizes[0].id | ||||||
|  |  | ||||||
|  |       const widthCandidates = this.posterSizes.filter(size => posterWidth < size.minWidth ? size.id : null) | ||||||
|  |       return widthCandidates[widthCandidates.length - 1].id | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     if (this.$refs.image == undefined) | ||||||
|  |       return | ||||||
|  |     const imageObserver = new IntersectionObserver((entries, imgObserver) => { | ||||||
|  |       entries.forEach((entry) => { | ||||||
|  |         if (entry.isIntersecting) { | ||||||
|  |           const lazyImage = entry.target | ||||||
|  |           lazyImage.src = this.posterUrl | ||||||
|  |           lazyImage.class | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     imageObserver.observe(this.$refs.image); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|     openMoviePopup(id, type) { |     openMoviePopup(id, type) { | ||||||
|       this.$popup.open(id, type) |       this.$popup.open(id, type) | ||||||
|     } |     } | ||||||
| @@ -162,4 +209,4 @@ export default { | |||||||
|     background-color: green; |     background-color: green; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user