|
|
- <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>
|