index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import baseComponent from '../helpers/baseComponent'
  2. import classNames from '../helpers/classNames'
  3. const EMPTY = 'empty'
  4. const LOADING = 'loading'
  5. const LOADED = 'loaded'
  6. const ERROR = 'error'
  7. const UNMOUNTED = 'unmounted'
  8. const calcStyle = (value) => typeof value === 'number' ? `${value}px` : value
  9. baseComponent({
  10. properties: {
  11. prefixCls: {
  12. type: String,
  13. value: 'wux-image',
  14. },
  15. src: {
  16. type: String,
  17. value: '',
  18. observer: 'updated',
  19. },
  20. mode: {
  21. type: String,
  22. value: 'scaleToFill',
  23. },
  24. lazyLoad: {
  25. type: Boolean,
  26. value: false,
  27. },
  28. shape: {
  29. type: String,
  30. value: 'normal',
  31. },
  32. width: {
  33. type: null,
  34. value: 300,
  35. observer: 'updateStyle',
  36. },
  37. height: {
  38. type: null,
  39. value: 225,
  40. observer: 'updateStyle',
  41. },
  42. unmountOnEmpty: {
  43. type: Boolean,
  44. value: false,
  45. },
  46. unmountOnError: {
  47. type: Boolean,
  48. value: false,
  49. },
  50. empty: {
  51. type: String,
  52. value: '',
  53. },
  54. loading: {
  55. type: String,
  56. value: '',
  57. },
  58. error: {
  59. type: String,
  60. value: '',
  61. },
  62. },
  63. data: {
  64. status: '',
  65. },
  66. computed: {
  67. classes() {
  68. const { prefixCls, shape, mode, status, empty, loading, error } = this.data
  69. const wrap = classNames(prefixCls, {
  70. [`${prefixCls}--${shape}`]: shape,
  71. [`${prefixCls}--${mode}`]: mode,
  72. [`${prefixCls}--${status}`]: status,
  73. })
  74. const inner = `${prefixCls}__inner`
  75. const thumb = `${prefixCls}__thumb`
  76. const mask = classNames(`${prefixCls}__mask`, {
  77. [`${prefixCls}__mask--text`]: empty || loading || error,
  78. })
  79. const text = `${prefixCls}__text`
  80. return {
  81. wrap,
  82. inner,
  83. thumb,
  84. mask,
  85. text,
  86. }
  87. },
  88. },
  89. methods: {
  90. /**
  91. * 更新资源地址
  92. */
  93. updated(src = this.data.src) {
  94. this.updateStatus(!!src ? LOADING : this.data.unmountOnEmpty ? UNMOUNTED : EMPTY)
  95. },
  96. /**
  97. * 更新组件样式
  98. */
  99. updateStyle(opts = {}) {
  100. const { width, height } = Object.assign({}, this.data, opts)
  101. const style = `width: ${calcStyle(width)}; height: ${calcStyle(height)}`
  102. this.setData({
  103. style,
  104. })
  105. },
  106. /**
  107. * 更新组件状态
  108. */
  109. updateStatus(status) {
  110. if (this.data.status !== status) {
  111. this.setData({
  112. status,
  113. })
  114. }
  115. this.triggerEvent('change', { status })
  116. },
  117. /**
  118. * 资源加载完成时的回调函数
  119. */
  120. onLoad(e) {
  121. this.updateStatus(LOADED)
  122. this.triggerEvent('load', { ...e.detail, status: LOADED })
  123. },
  124. /**
  125. * 资源加载失败时的回调函数
  126. */
  127. onError(e) {
  128. const status = this.data.unmountOnError ? UNMOUNTED : ERROR
  129. this.updateStatus(status)
  130. this.triggerEvent('error', { ...e.detail, status })
  131. },
  132. /**
  133. * 点击事件
  134. */
  135. onTap(e) {
  136. this.triggerEvent('click', { ...e.detail, status: this.data.status })
  137. },
  138. },
  139. attached() {
  140. this.updateStyle()
  141. this.updated()
  142. },
  143. })