合同小程序前端代码仓库
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.

235 lines
5.5 KiB

3 months ago
  1. <template>
  2. <!-- #ifdef APP-NVUE -->
  3. <web-view class="l-svg" ref="webRef" @error="error" @pagefinish="loaded" @onPostMessage="message"
  4. src="/uni_modules/lime-svg/hybrid/html/index.html"></web-view>
  5. <!-- <l-svg-x v-else :src="src" :color="color" @load="onLoad" @error="onError"></l-svg-x> -->
  6. <!-- #endif -->
  7. <!-- #ifndef APP-NVUE -->
  8. <view class="l-svg" :class="{'is-inherit': isInherit}" :style="[styles]" @click="$emit('click')">
  9. <image class="l-svg-img" :src="path" @load="onLoad" @error="onError"></image>
  10. </view>
  11. <!-- #endif -->
  12. </template>
  13. <script lang="ts">
  14. import SvpProps from './props'
  15. import { defineComponent, ref, computed, watchEffect, getCurrentInstance } from './vue'
  16. import { pathToDataUrl, svgToDataUrl } from './utils'
  17. export default defineComponent({
  18. name: 'l-svg',
  19. props: SvpProps,
  20. emits: ['load', 'error', 'click'],
  21. setup(props, { emit }) {
  22. const path = ref('')
  23. // #ifndef APP-NVUE
  24. const isInherit = computed(() : boolean => {
  25. return props.color != ''
  26. })
  27. // #endif
  28. const formatUrl = (url: string, action:string):string => {
  29. if(url.indexOf(`'`) > 0) return `${action}("${url}")`
  30. return `${action}('${url}')`
  31. }
  32. const instance = getCurrentInstance()!.proxy!
  33. const imageURL = ref(null)
  34. const styles = computed(() => {
  35. const style: Record<string, any> = {}
  36. // #ifndef APP-NVUE
  37. if (path.value != '') {
  38. const image = formatUrl(imageURL.value ?? path.value, 'url')// + ';'
  39. if (isInherit.value) {
  40. style['-webkit-mask-image'] = image
  41. style['mask-image'] = image
  42. } else {
  43. style['background-image'] = image
  44. }
  45. }
  46. // #endif
  47. if (props.color != '') {
  48. style['color'] = props.color
  49. }
  50. //#ifdef VUE2
  51. // VUE2小程序最后一个值莫名的出现undefined
  52. style['undefined'] = ''
  53. // #endif
  54. return style
  55. })
  56. const onLoad = (e) => {
  57. // #ifdef WEB
  58. imageURL.value = instance.$el.querySelector('img').src
  59. // #endif
  60. emit('load')
  61. }
  62. const onError = () => {
  63. emit('error')
  64. }
  65. // APP
  66. // #ifdef APP-NVUE
  67. const webRef = ref(null)
  68. const setSvgSrc = () => {
  69. if (path.value != '') {
  70. webRef.value?.evalJS(formatUrl(path.value, 'setSrc'));
  71. }
  72. }
  73. const setSvgColor = () => {
  74. if (props.color != '' && path.value != '') {
  75. webRef.value?.evalJS(`setStyle({"--color": "${props.color}"})`);
  76. }
  77. }
  78. const error = () => {
  79. emit('error')
  80. }
  81. const loaded = () => {
  82. watchEffect(() => {
  83. if (props.src == '') return
  84. if (props.src.startsWith('<')) {
  85. path.value = props.src
  86. } else if (props.src.startsWith('/static')) {
  87. pathToDataUrl(props.src).then(res => {
  88. path.value = res;
  89. setSvgSrc()
  90. setSvgColor()
  91. }).catch(err => {
  92. emit('error')
  93. console.warn("[lime-svg]" + props.src + JSON.stringify(err))
  94. })
  95. } else {
  96. path.value = props.src
  97. }
  98. setSvgSrc()
  99. setSvgColor()
  100. })
  101. }
  102. const message = (e) => {
  103. const data = e.detail.data[0]
  104. const event = data?.event
  105. const eventDetaill = data?.data
  106. if (event == 'click') {
  107. emit('click', eventDetaill)
  108. } else if (event == 'load') {
  109. emit('load', eventDetaill)
  110. } else if (event == 'error') {
  111. emit('error', eventDetaill)
  112. }
  113. }
  114. // #endif
  115. // 小程序 WEB
  116. // #ifndef APP-NVUE
  117. watchEffect(() => {
  118. if (props.src == '') return
  119. if (props.src.startsWith('<svg')) {
  120. path.value = svgToDataUrl(props.src)
  121. } else if (props.src.startsWith('/static')) {
  122. // #ifdef WEB
  123. path.value = props.src
  124. // #endif
  125. // #ifdef APP-VUE
  126. path.value = props.src.slice(1)
  127. // #endif
  128. // #ifndef WEB || APP-VUE
  129. pathToDataUrl(props.src).then(res => {
  130. path.value = res;
  131. }).catch(err => {
  132. emit('error')
  133. console.warn("[lime-svg]" + props.src + JSON.stringify(err))
  134. })
  135. // #endif
  136. } else {
  137. path.value = props.src
  138. }
  139. })
  140. // #endif
  141. return {
  142. path,
  143. onLoad,
  144. onError,
  145. // #ifdef APP-NVUE
  146. webRef,
  147. error,
  148. loaded,
  149. message,
  150. // #endif
  151. // #ifndef APP-NVUE
  152. isInherit,
  153. styles
  154. // #endif
  155. }
  156. }
  157. })
  158. </script>
  159. <style lang="scss">
  160. /* #ifndef APP-NVUE */
  161. :host {
  162. display: inline-flex;
  163. }
  164. /* #endif */
  165. .l-svg {
  166. // display: flex;
  167. // align-self: flex-start;
  168. /* #ifdef APP-NVUE */
  169. flex: 1;
  170. /* #endif */
  171. /* #ifndef APP-NVUE */
  172. display: inline-flex;
  173. width: 100%;
  174. height: 100%;
  175. flex: 1;
  176. /* #endif */
  177. /* #ifndef APP-NVUE */
  178. :deep(svg) {
  179. width: 100%;
  180. height: 100%;
  181. }
  182. &-img {
  183. // opacity: 0;
  184. mix-blend-mode: lighten;
  185. width: 100%;
  186. height: 100%;
  187. }
  188. &.is-inherit {
  189. // background-image: var(--svg);//linear-gradient(#f09, #09f, #f0f);
  190. // background-blend-mode: lighten;
  191. // background-size: cover;
  192. // background-size: 100% 100%;
  193. // background-repeat: no-repeat;
  194. // -webkit-mask-image: var(--svg);
  195. // mask-image: var(--svg);
  196. -webkit-mask-repeat: no-repeat;
  197. mask-repeat: no-repeat;
  198. -webkit-mask-size: 100% 100%;
  199. mask-size: 100% 100%;
  200. // -webkit-mask-mode: alpha;
  201. // mask-mode: alpha;
  202. background-color: currentColor; //var(currentColor, transparent);
  203. // background-blend-mode: multiply;
  204. }
  205. &:not(.is-inherit) {
  206. // background: var(--svg) no-repeat;
  207. background-repeat: no-repeat;
  208. background-size: 100% 100%;
  209. background-color: transparent;
  210. image {
  211. mix-blend-mode: inherit;
  212. opacity: 0;
  213. }
  214. }
  215. /* #endif */
  216. /* #ifdef APP-PLUS */
  217. /* #endif */
  218. }
  219. </style>