合同小程序前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
5.2 KiB

1 week ago
  1. <template>
  2. <text class="l-icon" :class="[classes, lClass]" :style="[styles, lStyle]" v-if="!isImage && !isIconify && !isSVG" @click="$emit('click')">{{iconCode}}</text>
  3. <image class="l-icon" :class="[classes, lClass]" :style="[styles, lStyle]" v-else-if="(!isSVG && !isIconify) && isImage" :src="iconUrl" @click="$emit('click')"></image>
  4. <l-svg class="l-icon" :class="[classes, lClass]" :style="[styles, lStyle]" :color="color" :src="iconUrl" v-else :web="web" @error="imageError" @load="imageload" @click="$emit('click')"></l-svg>
  5. </template>
  6. <script lang="uts" setup>
  7. import { addUnit } from '@/uni_modules/lime-shared/addUnit';
  8. import { IconCollection } from './types';
  9. import { icons } from './icons'
  10. defineOptions({
  11. name: 'l-icon'
  12. })
  13. const name = 'l-icon'
  14. const IconifyURL : string = 'https://api.iconify.design/';
  15. const $iconsHost : string | null = uni.getStorageSync('$limeIconsHost') as string | null
  16. /**
  17. * LimeIcon 图标
  18. * @description ICON集
  19. * @tutorial https://ext.dcloud.net.cn/plugin?id=14057
  20. * @property {String} name 图标名称
  21. * @property {String} color 颜色
  22. * @property {String} size 尺寸
  23. * @property {String} prefix 字体图标前缀
  24. * @property {Boolean} inherit 是否继承颜色
  25. * @property {Boolean} web 原生 app(nvue,uvue) 是否使用web渲染
  26. * @event {Function} click 点击事件
  27. */
  28. const props = defineProps({
  29. name: {
  30. type: String,
  31. default: ''
  32. },
  33. color: {
  34. type: String,
  35. default: ''
  36. },
  37. // #ifdef APP-ANDROID
  38. size: {
  39. type: Object,
  40. // default: 32
  41. },
  42. // #endif
  43. // #ifndef APP-ANDROID
  44. size: {
  45. type: [String, Number],
  46. // #ifdef APP-IOS
  47. // default: 32,
  48. // #endif
  49. },
  50. // #endif
  51. prefix: {
  52. type: String,
  53. default: ''
  54. },
  55. lClass: {
  56. type: String,
  57. default: ''
  58. },
  59. // 对安卓IOS无效
  60. inherit: {
  61. type: Boolean,
  62. default: true
  63. },
  64. web: {
  65. type: Boolean,
  66. default: false
  67. },
  68. lStyle: {
  69. type: [String, Object, Array],
  70. default: ''
  71. },
  72. })
  73. const emits = defineEmits(['click'])
  74. const $iconCollection = inject<IconCollection>('$iconCollection', {has: false, icons: new Map<string, any|null>()} as IconCollection)
  75. const collectionIcon = computed(():string|null => {
  76. return $iconCollection.icons.get(props.name) as string | null
  77. })
  78. const webviewRef = ref<UniWebViewElement | null>(null)
  79. const hasHost = computed<boolean>(() : boolean => props.name.indexOf('/') != -1)
  80. const isIconify = computed<boolean>(() : boolean => {
  81. return !hasHost.value && props.name.includes(':')
  82. })
  83. const isImage = computed<boolean>(() : boolean => {
  84. return /\.(jpe?g|png|gif|bmp|webp|tiff?)$/i.test(props.name) || /^data:image\/(jpeg|png|gif|bmp|webp|tiff);base64,/.test(props.name)
  85. })
  86. const isSVG = computed<boolean>(():boolean => {
  87. return /\.svg$/i.test(props.name) || props.name.startsWith('data:image/svg+xml') || props.name.startsWith('<svg')
  88. })
  89. const classes = computed<Map<string, any>>(() : Map<string, any> => {
  90. const cls = new Map<string, any>()
  91. cls.set(`${name}--font`, !isImage.value && !isIconify.value && !isSVG.value)
  92. cls.set(`${name}--image`, isImage.value || isIconify.value || isSVG.value)
  93. cls.set(props.prefix, props.prefix.length > 0)
  94. cls.set(props.lClass, props.lClass.length > 0)
  95. // #ifndef APP-ANDROID || APP-IOS
  96. cls.set(`is-inherit`, (isIconify.value) && (props.color.length > 0 || props.inherit))
  97. // #endif
  98. return cls
  99. })
  100. const styles = computed<Map<string, any>>(() : Map<string, any> => {
  101. const style = new Map<string, any>();
  102. // #ifdef APP
  103. if (props.color != '' && !isImage.value && !isIconify.value) {
  104. style.set('color', props.color)
  105. }
  106. const size = addUnit(props.size) ?? ((isImage.value || isIconify.value) ? '32px' : null)
  107. // #endif
  108. // #ifndef APP
  109. style.set('color', props.color)
  110. const size = addUnit(props.size)
  111. // #endif
  112. if (size != null) {
  113. style.set('width', size)
  114. if (isImage.value || isIconify.value || isSVG.value) {
  115. style.set('height', size)
  116. } else {
  117. style.set('fontSize', size)
  118. }
  119. }
  120. return style
  121. })
  122. const iconCode = computed<string>(() : string => {
  123. return icons.value.get(props.name) as string | null ?? ''
  124. })
  125. const isError = ref(false)
  126. const cacheMap = new Map<string, string>()
  127. const iconUrl = computed(():string => {
  128. const hasIconsHost = $iconsHost != null && $iconsHost != ''
  129. // const hasIconCollection = $iconCollection.has
  130. if(isImage.value) {
  131. return hasHost.value ? props.name : ($iconsHost ?? '') + props.name
  132. } else if(isIconify.value) {
  133. // 防止重绘
  134. if(cacheMap.has(props.name) && !isError.value) {
  135. return cacheMap.get(props.name)!
  136. }
  137. // 如果存在collectionIcon则使用
  138. // 如果设置的路径加载失败 就使用网络地址 就使用iconify api
  139. const _host = `${hasIconsHost ? $iconsHost : IconifyURL}`
  140. const _icon =collectionIcon.value ?? _host + `${props.name}.svg`.replace(/:/g, '/')
  141. cacheMap.set(props.name, _icon)
  142. return _icon
  143. } else if(isSVG.value) {
  144. return (/\.svg$/i.test(props.name) && $iconsHost != null && !hasHost.value ? $iconsHost : '') + props.name.replace(/'/g, '"')
  145. } else {
  146. return ''
  147. }
  148. })
  149. const imageError = () => {
  150. isError.value = true
  151. }
  152. const imageload = () => {
  153. isError.value = false
  154. }
  155. </script>
  156. <style lang="scss">
  157. @import './index.scss';
  158. </style>