img-cache.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <template>
  2. <image
  3. class="img-cache"
  4. :src="resource"
  5. :mode="mode"
  6. :lazy-load="lazyLoad"
  7. :fade-show="fadeShow"
  8. :webp="webp"
  9. :show-menu-by-longpress="showMenuByLongpress"
  10. :style="[style]"
  11. @tap="fnEvent('click', $event)"
  12. @error="fnEvent('error', $event)"
  13. @load="fnEvent('load', $event)"
  14. >
  15. </image>
  16. </template>
  17. <script>
  18. // #ifdef APP-PLUS
  19. import storage from './storage'
  20. import download from './download'
  21. import { resolveFile } from './index'
  22. // #endif
  23. /**
  24. * ImgCache 图片缓存
  25. * @description APP端图片缓存
  26. * @tutorial https://ext.dcloud.net.cn/plugin?id=2515
  27. * @property {string} src 图片资源地址
  28. * @property {string} mode 图片裁剪、缩放的模式
  29. * @property {boolean} lazyLoad 是否图片懒加载
  30. * @property {boolean} fade-show 图片显示动画效果
  31. * @property {boolean} webp 默认不解析 webP 格式,只支持网络资源
  32. * @property {boolean} show-menu-by-longpress 开启长按图片显示识别小程序码菜单
  33. * @property {string} dir 缓存的文件目录,文件夹开头不能有_
  34. * @property {string} width 宽度,单位任意,如果为数值,则为 rpx 单位
  35. * @property {string} height 高度,单位任意,如果为数值,则为 rpx 单位
  36. * @property {object} custom-style 自定义样式
  37. * @event {Function} click 点击图片
  38. * @event {Function} error 错误发生
  39. * @event {Function} load 图片载入完毕
  40. * @example <img-cache src="https://example.com/image.png"></img-cache>
  41. */
  42. export default {
  43. name: 'ImgCache',
  44. props: {
  45. src: {
  46. type: String
  47. },
  48. mode: {
  49. type: String,
  50. default: 'scaleToFill'
  51. },
  52. lazyLoad: {
  53. type: Boolean,
  54. default: false
  55. },
  56. fadeShow: {
  57. type: Boolean,
  58. default: true
  59. },
  60. webp: {
  61. type: Boolean,
  62. default: false
  63. },
  64. showMenuByLongpress: {
  65. type: Boolean,
  66. default: false
  67. },
  68. dir: {
  69. type: String,
  70. default: 'imgcache'
  71. },
  72. width: {
  73. type: [String, Number]
  74. },
  75. height: {
  76. type: [String, Number]
  77. },
  78. customStyle: {
  79. type: Object,
  80. default: () => ({})
  81. }
  82. },
  83. data() {
  84. return {
  85. resource: ''
  86. }
  87. },
  88. computed: {
  89. style() {
  90. let style = { willChange: 'transform' }
  91. // 判断传过来的值不为 undefined null ''
  92. if ((this.width ?? '') !== '') style.width = this.addUnit(this.width)
  93. if ((this.height ?? '') !== '') style.height = this.addUnit(this.height)
  94. return {
  95. ...style,
  96. ...this.customStyle
  97. }
  98. }
  99. },
  100. watch: {
  101. src: {
  102. handler: 'init',
  103. immediate: true
  104. }
  105. },
  106. methods: {
  107. // 初始化
  108. init() {
  109. // #ifdef APP-PLUS
  110. this.fnCache()
  111. // #endif
  112. // #ifndef APP-PLUS
  113. this.setSrc()
  114. // #endif
  115. },
  116. // 获取缓存
  117. async fnCache() {
  118. const url = this.src // 赋值到新变量,避免下载时 src 更改,从而网络地址和本地地址图片不一致
  119. if (!/^https?:\/\//.test(url)) return this.setSrc() // 判断是否网络地址
  120. const [select] = storage.select({ url }) // 查询缓存是否存在
  121. if (select) {
  122. const path = select.local
  123. if (await resolveFile(path)) return this.setSrc(path) // 判断本地文件是否存在 如果存在则显示本地文件
  124. storage.delete(select) // 如果本地文件不存在则删除缓存数据
  125. }
  126. this.setSrc()
  127. const local = await download(url, this.dir) // 下载文件
  128. if (local) storage.insert({ url, local }) // 缓存数据
  129. },
  130. // 发送事件
  131. fnEvent(emit, event) {
  132. this.$emit(emit, event)
  133. },
  134. // 设置图片资源地址
  135. setSrc(src) {
  136. this.resource = src || this.src
  137. },
  138. // 添加单位,如果为数值则为rpx单位,否则直接返回
  139. addUnit(value) {
  140. value = String(value ?? '')
  141. return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value) ? `${value}rpx` : value
  142. }
  143. }
  144. }
  145. </script>