Files
2025-11-05 17:34:23 +08:00

324 lines
8.8 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- #ifdef APP-IOS || APP-ANDROID || APP-HARMONY-->
<!-- <web-view class="l-svg" ref="webRef" v-if="web" @error="error" @load="loaded" @message="message"
src="/uni_modules/lime-svg/hybrid/html/index.html?v=21"></web-view> -->
<!-- <l-svg-x class="l-svg" v-else :src="path" :color="color" @error="onError" @load="onLoad"
@click="$emit('click')"></l-svg-x> -->
<!-- <image class="l-svg-" v-bind="$attrs" v-if="color == '' && src.indexOf('<svg') != 0 && src.indexOf('data:image') != 0" :src="src" @error="onError" @load="onLoadImage" /> -->
<native-view class="l-svg" v-bind="$attrs" @init="onviewinit" @error="onError" @load="onLoad"></native-view>
<!-- #endif -->
<!-- #ifdef WEB -->
<view class="l-svg" v-if="src.startsWith('<svg')" v-html="src" :style="styles"></view>
<view class="l-svg" :class="{'is-inherit': isInherit}" v-else :style="styles">
<image class="l-svg-img" :src="src" @error="onError" @load="onLoad" />
</view>
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<!-- <native-view class="l-svg" v-bind="$attrs" @init="onviewinit" @error="onError" @load="onLoad"></native-view> -->
<!-- #endif -->
<!-- #ifndef APP-IOS || APP-ANDROID || APP-HARMONY || WEB -->
<view class="l-svg" :class="{'is-inherit': isInherit}" :style="styles">
<image class="l-svg-img" :src="path" @error="onError" @load="onLoad"></image>
</view>
<!-- #endif -->
</template>
<script setup lang="uts">
/**
* Svg SVG组件
* @description 用于渲染SVG路径元素支持动态颜色和继承属性
* <br>插件类型LSvpComponentPublicInstance
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-svg
*
* @property {string} src SVG路径
* @property {string} color 路径颜色(默认:"currentColor"
* @property {boolean} web 是否启用Web优化模式默认false
* @property {boolean} inherit 是否继承父级SVG属性默认true
* @event {Function} load SVG路径加载完成时触发
* @event {Function} error SVG路径加载失败时触发
*/
import { LSvpProps } from './type'
// #ifndef UNI-APP-X && APP || WEB
import { pathToDataUrl, svgToDataUrl } from './utils'
// #endif
// #ifdef APP-ANDROID || APP-IOS
import { pathToDataUrl, svgToDataUrl } from './utils'
// #endif
// #ifdef APP
import { NativeImage } from "@/uni_modules/lime-svg";
let nativeImage : NativeImage | null = null
// #endif
const props = withDefaults(defineProps<LSvpProps>(), {
src: '',
color: '',
web: false,
inherit: false
})
const emit = defineEmits(['load', 'error'])
const path = ref(props.src)
const svgRef = ref<UniElement | null>(null)
// #ifndef APP-ANDROID || APP-IOS
const isInherit = computed(() : boolean => {
return props.color != ''
})
// #endif
const imageURL = ref('')
const formatUrl = (url : string, action : string) : string => {
if (url.indexOf(`'`) > 0) return `${action}("${url}")`
return `${action}('${url}')`
}
const styles = computed(() : Map<string, string> => {
const style = new Map<string, string>()
// #ifdef WEB
if (props.src != '' && !props.src.startsWith('<svg')) {
// style.set('--svg', formatUrl(props.src, 'url'))
style.set('--svg', formatUrl(imageURL.value ?? props.src, 'url'))
}
// #endif
// #ifndef APP || WEB
if (path.value != '') {
// style.set('--svg', formatUrl(props.src, 'url'))
style.set('--svg', formatUrl(path.value, 'url'))
}
// #endif
if (props.color != '') {
style.set('color', props.color)
}
return style
})
// #ifdef APP-ANDROID
const errorDetaill = new UniImageErrorEventDetail('加载失败')
const errorEvent = new UniImageErrorEvent('error', errorDetaill)
// #endif
// #ifndef APP-ANDROID
const errorDetaill = {
errMsg: '加载失败'
}
const errorEvent = {
type: 'error',
detaill: errorDetaill
}
// #endif
const onError = () => {
emit('error', errorEvent)
}
const onLoadImage = (e: UniImageLoadEvent) => {
emit('load', e)
}
const onLoad = (e : UniNativeViewEvent) => {
// #ifdef WEB
// @ts-ignore
imageURL.value = e.target.src
// #endif
// #ifdef APP-ANDROID
const detail = new ImageLoadEventDetail(512, 512)
const loadEvent = new UniImageLoadEvent('load', detail)
// #endif
// #ifndef APP-ANDROID
const detail = {
width: 512,
height: 512
}
const loadEvent = {
type: 'load',
detail
}
// #endif
emit('load', loadEvent)
}
// app
// #ifdef APP-ANDROID || APP-IOS
// const webRef = ref<UniWebViewElement | null>(null)
// const setSvgSrc = () => {
// if (path.value != '') {
// webRef.value?.evalJS(formatUrl(path.value, 'setSrc'));
// }
// }
// const setSvgColor = () => {
// if (props.color != '' && path.value != '') {
// webRef.value?.evalJS(`setStyle({"--color": "${props.color}"})`);
// }
// }
// const error = (_ : UniWebViewErrorEvent) => {
// emit('error', errorEvent)
// }
// const loaded = (_ : UniWebViewLoadEvent) => {
// watchEffect(() => {
// if (props.src == '' || !props.web) return
// if (props.src.startsWith('<svg')) {
// path.value = svgToDataUrl(props.src)
// setSvgSrc()
// setSvgColor()
// } else if (props.src.startsWith('/static')) {
// pathToDataUrl(props.src).then(res => {
// path.value = res;
// setSvgSrc()
// setSvgColor()
// }).catch(err => {
// emit('error', errorEvent)
// console.warn("[lime-svg]" + props.src + JSON.stringify(err))
// })
// } else {
// path.value = props.src
// setSvgSrc()
// setSvgColor()
// }
// })
// }
// const message = (event : UniWebViewMessageEvent) => {
// const data = UTSJSONObject.assign({}, event.detail.data[0] as UTSJSONObject); //event.detail.data[0] as UTSJSONObject
// const type = data.getString('event')
// // #ifdef APP-ANDROID
// const detail = data.getJSON('data')?.getJSON('detail')
// // #endif
// // #ifndef APP-ANDROID
// const detail = UTSJSONObject.assign({}, data?.data?.detail ?? {})
// // #endif
// if (type == 'click') {
// emit('click')
// } else if (type == 'load') {
// const width = detail?.getNumber('width') ?? 512
// const height = detail?.getNumber('height') ?? 512
// // #ifdef APP-ANDROID
// const loadDetail = new ImageLoadEventDetail(width, height)
// const loadEvent = new UniImageLoadEvent('load', loadDetail)
// // #endif
// // #ifndef APP-ANDROID
// const loadDetail = {
// width,
// height
// }
// const loadEvent = {
// type: 'error',
// detail: loadDetail
// }
// // #endif
// emit(type, loadEvent)
// } else if (type == 'error') {
// emit(type, errorEvent)
// }
// }
// #endif
// #ifdef APP
function onviewinit(e : UniNativeViewInitEvent) {
nativeImage = new NativeImage(e.detail.element);
nativeImage?.updateSrc(path.value)
nativeImage?.updateColor(props.color)
}
const map = new Map<string, string>()
watchEffect(() => {
// #ifdef APP-ANDROID || APP-IOS
// ios uts组件使用uni.request会报错故在这里使用
if (!props.web && props.src.startsWith('http')) {
if(map.has(props.src)) {
nativeImage?.updateSrc(map.get(props.src)!)
return
}
uni.downloadFile({
url: props.src,
success(res) {
path.value = res.tempFilePath
map.set(props.src, res.tempFilePath)
nativeImage?.updateSrc(res.tempFilePath)
}
})
} else {
// const a = UTSAndroid.convert2AbsFullPath(props.src)
path.value = props.src;
nativeImage?.updateSrc(props.src)
}
// #endif
// #ifdef APP-HARMONY
path.value = props.src;
nativeImage?.updateSrc(props.src)
// #endif
})
watchEffect(() => {
if(props.color == '') return
nativeImage?.updateColor(props.color)
})
// #endif
// 小程序
// #ifndef APP || WEB
watchEffect(() => {
if (props.src == '') return
if (props.src.startsWith('<svg')) {
path.value = svgToDataUrl(props.src)
} else if (props.src.startsWith('/static')) {
pathToDataUrl(props.src).then(res => {
path.value = res;
}).catch(err => {
emit('error', errorEvent)
console.warn("[lime-svg]" + props.src + JSON.stringify(err))
})
} else {
path.value = props.src
}
})
// #endif
</script>
<style lang="scss">
.l-svg {
// align-self: flex-start;
/* #ifdef APP */
width: 24px;
height: 24px;
/* #endif */
/* #ifndef APP */
width: 1em;
height: 1em;
/* #endif */
/* #ifndef APP */
:deep(svg) {
width: 100%;
height: 100%;
}
&-img {
mix-blend-mode: lighten;
width: 100%;
height: 100%;
}
&.is-inherit {
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
background-color: currentColor;
}
&:not(.is-inherit) {
background: var(--svg) no-repeat;
background-size: 100% 100%;
background-color: transparent;
image {
mix-blend-mode: inherit;
opacity: 0;
}
}
/* #endif */
}
</style>