vue3+vite2实现动态绑定图片的优雅解决方案

 更新时间:2023年08月24日 08:43:55   作者:前端cry  
这篇文章主要为大家详细介绍了vue3+vite2实现动态绑定图片的优雅解决方案,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下

背景

在vue3+vite2项目中,我们有时候想要动态绑定资源,比如像下面的代码这样:

<template>
    <div>
	    <!-- 动态绑定图片资源 -->
        <img :src="img_src">
    </div>
</template>
<script setup>
import { ref } from 'vue';
// 静态图片资源
const img_src = ref('./1.jpg');
</script>

实际效果是这样:

原因分析

我们注意到,控制台的报错信息GET http://127.0.0.1:5173/1.jpg 404 (Not Found)

  • GET:表示向服务器请求资源的方式。
  • http://127.0.0.1:5173:表示主机为项目开启的服务器地址以及端口号
  • http://127.0.0.1:5173/1.jpg:表示存放在服务器中的图片资源地址。
  • 404 (Not Found):状态码,404表示找不到资源。

问题就出在http://127.0.0.1:5173/1.jpg 这里,项目文件的路径是src/App.vue ,图片的路径是src/1.jpg ,因此,图片在服务器上的存放路径实际应该是http://127.0.0.1:5173/src/1.jpg ,我们直接在浏览器中访问这个地址。

可以看到,成功获取了图片资源。

由于vite打包的机制,造成了路径错误的问题(类似于vue2 + vue-cli项目的动态绑定图片问题)。

解决

目前网上的解决方案有很多,这里列出其中一种受众的,以及笔者在此基础上进一步加强的解决方案。

普遍的解决方案

话不多说,直接列出代码:

<template>
    <div>
	    <!-- 动态绑定图片资源 -->
        <img :src="img_src">
    </div>
</template>
<script setup>
import { ref } from 'vue';
// 静态图片资源
const img_src = ref('./1.jpg');
// 主要代码,利用 new URL().href 进行相对路径的拼接
function getAssetImage(imgSrc) {
  return new URL(imgSrc, import.meta.url).href;
}
// 当然你也可以这样简写,这里用到es6箭头函数
// const getAssetImage = imgSrc => new URL(imgSrc, import.meta.url).href;
</script>

这段代码的重点是new URL().href 和 es6的 import.meta.url 。

  • new URL(url, baseUrl).href:路径拼接。比如url是./1.jpg,baseUrl是http://127.0.0.1:5173/src/App.vue ,那么拼接出来就是http://127.0.0.1:5173/src/1.jpg
  • import.meta.url:获取当前模块的路径,比如在src/App.vue中,就是http://127.0.0.1:5173/src/App.vue

所以最后的new URL().href 就是真正的图片资源地址,自己打印一下new URL(url, baseUrl) 和import.meta.url 就容易明白了。

这里给大伙儿画张图,便于理解。

优雅的解决方案

上面的方案可行,但不够优雅。试想,如果有很多文件都需要动态绑定静态图片资源,那岂不是每个.vue文件都要封装一次getAssetImage() 函数?所以下面介绍一种优雅的封装方案。

封装的主要问题是如何自动获取.vue文件的import.meta.url ,就可以不必每次调用都携带import.meta.url

核心思路是通过抛出错误获取函数调用栈,从而获得函数调用者文件(或者说模块)的路径,再通过正则表达式提取出路径信息,把import.meta.url替换掉,就能实现,只传图片相对路径这一个参数,得到图片的完整路径的效果

直接上代码:

JavaScript版本

// src/utils/common.js
export default {
    getAssetImage(imgSrc, baseUrl) {
        // console.log('baseUrl', baseUrl);
        // console.log('new URL(imgSrc, baseUrl).href', new URL(imgSrc, baseUrl).href);
        // console.log('import.meta.url', import.meta.url);
        // console.log('new URL(imgSrc, import.meta.url).href', new URL(imgSrc, import.meta.url).href);
        // 正则匹配函数调用者文件的路径
        const regExp1 = /at Proxy.getAssetImage \((.+)\)/g;
        // 正则命中目标
        let target;
        try {
            // 抛出错误,获取函数调用栈信息
            throw new Error();
        } catch (err) {
            // 匹配函数调用者文件的路径
            target = regExp1.exec(err?.stack);
            // console.log('err.stack', err?.stack);
            // console.log(target?.[1]);
        }
        if (target?.[1]) {
            // 用户没有传入第二个参数,就使用自动获取的路径
            baseUrl = baseUrl || target?.[1];
        }
        if (!baseUrl) {
            // 用户没有传入第二个参数,且获取函数调用者文件的路径失败
            throw new Error('请传入第二个参数 import.meta.url');
        }
        // 返回处理后的资源路径
        return new URL(imgSrc, baseUrl).href;
    }
}

TypeScript版本

// src/utils/common.ts
export default {
    getAssetImage(imgSrc: string, baseUrl: string) {
        // console.log('baseUrl', baseUrl);
        // console.log('new URL(imgSrc, baseUrl).href', new URL(imgSrc, baseUrl).href);
        // console.log('import.meta.url', import.meta.url);
        // console.log('new URL(imgSrc, import.meta.url).href', new URL(imgSrc, import.meta.url).href);
        // 正则匹配函数调用者文件的路径
        const regExp1 = /at Proxy.getAssetImage \((.+)\)/g;
        // 正则命中目标
        let target: RegExpExecArray | null;
        try {
            // 抛出错误,获取函数调用栈信息
            throw new Error();
        } catch (err) {
            // 匹配函数调用者文件的路径
            target = regExp1.exec(err?.stack);
            // console.log('err.stack', err?.stack);
            // console.log(target?.[1]);
        }
        if (target?.[1]) {
            // 用户没有传入第二个参数,就使用自动获取的路径
            baseUrl = baseUrl || target?.[1];
        }
        if (!baseUrl) {
            // 用户没有传入第二个参数,且获取函数调用者文件的路径失败
            throw new Error('请传入第二个参数 import.meta.url');
        }
        // 返回处理后的资源路径
        return new URL(imgSrc, baseUrl).href;
    }
}

在.vue文件中使用

// src/App.vue
<template>
    <div>
        <!-- 测试 -->
        <img :src="getAssetImage(img_src)">
        <!-- 可以试试在嵌套组件中使用^_^ -->
    </div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import common from '@/utils/common.ts';
const img_src = ref('./1.jpg');
// const getAssetImage = img_src => common.getAssetImage(img_src, import.meta.url);
// 可以省略第二个参数import.meta.url,函数内部会自动获取函数的调用路径。
const getAssetImage = img_src => common.getAssetImage(img_src);
// 常规写法
// function getAssetImage(img_src) {
//   return common.getAssetImage(img_src);
// }
</script>

到此这篇关于vue3+vite2实现动态绑定图片的优雅解决方案的文章就介绍到这了,更多相关vue3 vite2动态绑定图片内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue实现Header渐隐渐现效果的实例代码

    Vue实现Header渐隐渐现效果的实例代码

    这篇文章主要介绍了Vue实现Header渐隐渐现效果,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • vue3的api解读之ref和reactive示例详解

    vue3的api解读之ref和reactive示例详解

    这篇文章主要介绍了vue3的api解读之ref和reactive详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • vue3在单个组件中实现类似mixin的事件调用

    vue3在单个组件中实现类似mixin的事件调用

    这篇文章主要为大家详细介绍了vue3如何在单个组件中实现类似mixin的事件调用,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • Vue3中使用监听器的具体实践

    Vue3中使用监听器的具体实践

    监听器是Vue3中非常好用的一个特性,用于监听某个响应式变量的变化,本文就来介绍一下Vue3中使用监听器的具体实践,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • vue-cli 组件的导入与使用教程详解

    vue-cli 组件的导入与使用教程详解

    这篇文章主要介绍了vue-cli--组件的导入与使用详解,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-04-04
  • Vue.js第二天学习笔记(vue-router)

    Vue.js第二天学习笔记(vue-router)

    这篇文章主要为大家详细介绍了Vue.js第二天的学习笔记,关于vue-router的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • Vue router 路由守卫详解

    Vue router 路由守卫详解

    这篇文章主要为大家介绍了Vue router 路由守卫,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • vuex mutation action同级调用方式

    vuex mutation action同级调用方式

    这篇文章主要介绍了vuex mutation action同级调用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据

    vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据

    这篇文章主要为大家详细介绍了vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • Vertx基于EventBus发送接受自定义对象

    Vertx基于EventBus发送接受自定义对象

    这篇文章主要介绍了Vertx基于EventBus发送接受自定义对象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11

最新评论