<template>
|
|
<!-- #ifdef APP -->
|
|
<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>
|
|
<!-- #endif -->
|
|
<!-- #ifdef WEB -->
|
|
<view class="l-svg" v-if="src.startsWith('<svg')" v-html="src" :style="styles" @click="$emit('click')"></view>
|
|
<view class="l-svg" :class="{'is-inherit': isInherit}" v-else :style="styles" @click="$emit('click')">
|
|
<image class="l-svg-img" :src="src" @error="onError" @load="onLoad"/>
|
|
</view>
|
|
<!-- #endif -->
|
|
<!-- #ifndef APP || WEB -->
|
|
<view class="l-svg" :class="{'is-inherit': isInherit}" :style="styles" @click="$emit('click')">
|
|
<image class="l-svg-img" :src="path" @error="onError" @load="onLoad"></image>
|
|
</view>
|
|
<!-- #endif -->
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { LSvpProps } from './type'
|
|
// #ifndef APP || WEB
|
|
import { pathToDataUrl, svgToDataUrl } from './utils'
|
|
// #endif
|
|
// #ifdef APP
|
|
import { pathToDataUrl, svgToDataUrl } from './utils'
|
|
// #endif
|
|
|
|
|
|
const props = withDefaults(defineProps<LSvpProps>(), {
|
|
src: '',
|
|
color: '',
|
|
web: false,
|
|
inherit: false
|
|
})
|
|
const emits = defineEmits(['load', 'error', 'click'])
|
|
const path = ref(props.src)
|
|
// #ifndef APP
|
|
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 = () => {
|
|
emits('error', errorEvent)
|
|
}
|
|
const onLoad = (e: UniImageLoadEvent) => {
|
|
// #ifdef WEB
|
|
// @ts-ignore
|
|
imageURL.value = e.target.src
|
|
// #endif
|
|
// #ifdef APP-ANDROID
|
|
// const detail = new ImageLoadEventDetail(512, 512)
|
|
const loadEvent = e;//new UniImageLoadEvent('load', detail)
|
|
// #endif
|
|
// #ifndef APP-ANDROID
|
|
const detail = {
|
|
width: 512,
|
|
height:512
|
|
}
|
|
const loadEvent = {
|
|
type: 'error',
|
|
detail
|
|
}
|
|
// #endif
|
|
|
|
emits('load', loadEvent)
|
|
}
|
|
// app
|
|
// #ifdef APP
|
|
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) => {
|
|
emits('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 => {
|
|
emits('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') {
|
|
emits('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
|
|
emits(type, loadEvent)
|
|
} else if(type == 'error') {
|
|
emits(type, errorEvent)
|
|
}
|
|
}
|
|
// #endif
|
|
|
|
|
|
// #ifdef APP
|
|
// ios uts组件使用uni.request会报错,故在这里使用
|
|
watchEffect(()=>{
|
|
if(!props.web && props.src.startsWith('http')) {
|
|
uni.downloadFile({
|
|
url: props.src,
|
|
success(res) {
|
|
path.value = res.tempFilePath
|
|
}
|
|
})
|
|
// uni.request({
|
|
// url: props.src,
|
|
// dataType: 'text',
|
|
// success(res) {
|
|
// path.value = res.data as string as string | null ?? ''
|
|
// }
|
|
// })
|
|
} else {
|
|
path.value = props.src;
|
|
}
|
|
})
|
|
// #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 => {
|
|
emits('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>
|