lazyImg.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <div ref="LazyImage"
  3. :class="customClass"
  4. class="lazy-img">
  5. <q-resize-observer @resize="onresize" />
  6. <q-img v-if="qImage && width && height"
  7. :alt="alt"
  8. :src="lazyImageSrc"
  9. :width="computedWidth+'px'"
  10. :height="computedHeight+'px'"
  11. :ratio="ratio"
  12. fit="contain"
  13. class="full-width img"
  14. position="0 0">
  15. <slot />
  16. </q-img>
  17. <img v-else-if="!qImage && width && height"
  18. :alt="alt"
  19. :src="lazyImageSrc"
  20. class="full-width img"
  21. :style="{height: computedHeight+'px', width: computedWidth+'px'}">
  22. <q-img v-else-if="qImage && (!width || !height)"
  23. :src="computedSrc"
  24. :alt="alt">
  25. <slot />
  26. </q-img>
  27. <img v-else-if="!qImage && (!width || !height)"
  28. :src="computedSrc"
  29. :alt="alt"
  30. class="full-width">
  31. </div>
  32. </template>
  33. <script>
  34. import process from 'process'
  35. export default {
  36. name: 'lazyImg',
  37. props: {
  38. src: {
  39. type: String,
  40. default: null
  41. },
  42. alt: {
  43. type: String,
  44. default: null
  45. },
  46. qImage: {
  47. type: Boolean,
  48. default: false
  49. },
  50. class: {
  51. type: String,
  52. default: null
  53. },
  54. width: {
  55. type: String,
  56. default: null
  57. },
  58. height: {
  59. type: String,
  60. default: null
  61. }
  62. },
  63. data () {
  64. return {
  65. lazyImageSrc: '',
  66. computedWidth: 0,
  67. computedHeight: 0
  68. }
  69. },
  70. computed: {
  71. computedSrc () {
  72. if (!process.env.APP_ENV !== 'production' && this.src) {
  73. return this.src.replace('https://stage-minio.alaatv.com', 'https://nodes.alaatv.com')
  74. }
  75. return this.src
  76. },
  77. customClass () {
  78. return this.class
  79. },
  80. normalizedSizeWithPx () {
  81. return {
  82. w: this.normalizedSizeInNumber.w + 'px',
  83. h: this.normalizedSizeInNumber.h + 'px'
  84. }
  85. },
  86. normalizedSizeInNumber () {
  87. if (!this.width || !this.height) {
  88. return {
  89. w: 0,
  90. h: 0
  91. }
  92. }
  93. const wContain = this.width.search('px') !== -1 ? 'px' : this.width.search('%') ? '%' : ''
  94. const HContain = this.height.search('px') !== -1 ? 'px' : this.height.search('%') ? '%' : ''
  95. return {
  96. w: this.width.replace(wContain, ''),
  97. h: this.height.replace(HContain, '')
  98. }
  99. },
  100. ratio () {
  101. return this.normalizedSizeInNumber.w + '/' + this.normalizedSizeInNumber.h
  102. }
  103. },
  104. watch: {
  105. src () {
  106. this.updateLazyImageSrc()
  107. }
  108. },
  109. mounted() {
  110. this.updateLazyImageSrc()
  111. },
  112. methods: {
  113. onresize () {
  114. this.updateLazyImageSrc()
  115. },
  116. updateLazyImageSrc () {
  117. this.computedWidth = Math.floor(this.getOffsetWidth())
  118. this.computedHeight = Math.floor(this.getOffsetHeight())
  119. if (this.normalizedSizeInNumber.w !== null && this.normalizedSizeInNumber.h !== null && !isNaN(parseInt(this.normalizedSizeInNumber.w)) && !isNaN(parseInt(this.normalizedSizeInNumber.h))) {
  120. this.computedHeight = Math.floor((parseInt(this.normalizedSizeInNumber.h) * this.computedWidth) / parseInt(this.normalizedSizeInNumber.w))
  121. }
  122. this.lazyImageSrc = this.computedSrc
  123. if (this.lazyImageSrc && !isNaN(this.computedWidth) && this.computedWidth > 0 && !isNaN(this.computedHeight) && this.computedHeight > 0) {
  124. this.lazyImageSrc += '?w=' + this.computedWidth + '&h=' + this.computedHeight
  125. }
  126. if (!this.lazyImageSrc) {
  127. this.lazyImageSrc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TpSKVDhYRcchQnSyIijpqFYpQIdQKrTqYXPohNGlIUlwcBdeCgx+LVQcXZ10dXAVB8APE1cVJ0UVK/F9SaBHjwXE/3t173L0DhHqZaVbHKKDptplOJsRsbkUMvUJABCH0YUpmljErSSn4jq97BPh6F+dZ/uf+HD1q3mJAQCSeYYZpE68TT27aBud94igrySrxOfGISRckfuS64vEb56LLAs+Mmpn0HHGUWCy2sdLGrGRqxBPEMVXTKV/Ieqxy3uKslauseU/+wnBeX17iOs1BJLGARUgQoaCKDZRhI06rToqFNO0nfPwDrl8il0KuDTByzKMCDbLrB/+D391ahfExLymcADpfHOdjCAjtAo2a43wfO07jBAg+A1d6y1+pA9OfpNdaWuwIiGwDF9ctTdkDLneA/idDNmVXCtIUCgXg/Yy+KQf03gLdq15vzX2cPgAZ6ip1AxwcAsNFyl7zeXdXe2//nmn29wNtt3Klb/Gn/QAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+cCDwcZJTB9qXYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4P4EBAAQhAZCbA9mPAAAAAElFTkSuQmCC'
  128. }
  129. },
  130. getImageElement () {
  131. if (!this.$refs.LazyImage) {
  132. return {
  133. offsetWidth: null,
  134. offsetHeight: null
  135. }
  136. }
  137. if (this.$refs.LazyImage.$el) {
  138. return this.$refs.LazyImage.$el
  139. }
  140. if (this.$refs.LazyImage) {
  141. return this.$refs.LazyImage
  142. }
  143. },
  144. getOffsetWidth () {
  145. const imageElement = this.getImageElement()
  146. if (!imageElement) {
  147. return 0
  148. }
  149. return imageElement.offsetWidth
  150. },
  151. getOffsetHeight () {
  152. const imageElement = this.getImageElement()
  153. if (!imageElement) {
  154. return 0
  155. }
  156. return imageElement.offsetHeight
  157. }
  158. }
  159. }
  160. </script>
  161. <style lang="scss" scoped>
  162. .lazy-img {
  163. font-size: 0;
  164. border-radius: inherit;
  165. overflow: hidden;
  166. .img{
  167. border-radius: inherit;
  168. }
  169. }
  170. </style>