优雅解决方案在最下面,小伙伴们儿可以直接前往

背景

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

the End……

vue3+vite2动态绑定图片优雅解决方案的更多相关文章

  1. Java 图片处理解决方案:ImageMagick 快速入门

    一.ImageMagick介绍 ImageMagick是一个免费的创建.编辑.合成图片的软件,可以实现图片切割.颜色替换.图片缩略图.图片水印等各种效果.ImageMagick是免费开源软件,支持大多 ...

  2. Atitit 手机图片备份解决方案attilax总结

    Atitit 手机图片备份解决方案attilax总结 1.1. 图片分类 相机图片与app图片1 1.2. 增量备份,只能使用按照时间法备份..1 1.3. 备份工具选型1 1.4. App图片,只好 ...

  3. Silverlight或WPF动态绑定图片路径问题,不用Converter完美解决

    关于Silverlight或WPF动态绑定图片路径问题,不用Converter完美解决, 可想,一个固定的字符串MS都能找到,按常理动态绑定也应该没问题的,只需在前面标记它是一个Path类型的值它就能 ...

  4. Java 图片处理解决方案:ImageMagick 快速入门教程

    文章首发于[博客园-陈树义],点击跳转到原文Java 图片处理解决方案:ImageMagick 快速入门教程. ImageMagick介绍 ImageMagick是一个免费的创建.编辑.合成图片的软件 ...

  5. vue动态绑定图片和背景图

    1.动态绑定图片 <img class="binding-img" :src="require('../assets/images/test.png')" ...

  6. vue3 vite2 封装 SVG 图标组件 - 基于 vite 创建 vue3 全家桶项目续篇

    在<基于 vite 创建 vue3 全家桶>一文整合了 Element Plus,并将 Element Plus 中提供的图标进行全局注册,这样可以很方便的延续 Element UI 的风 ...

  7. nginx 一二事(1) - 简单图片服务器解决方案

    最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的 今天再这里简单讲一下上传图片以及图片服务器的大致理念 如果是个人项目或者企业小项目,仅仅只有十来号人使 ...

  8. vue-cli 动态绑定图片失败

    1.template 中引用图片,第一个为固定路径,第二个为动态绑定路径 eg: <img src="XXXXXX.png" alt=""> < ...

  9. Servlet拦截静态图片的解决方案

    一.现象 建立一个使用Freemarker的Web Project程序. Product.ftl中的代码为: <!DOCTYPE html PUBLIC "-//W3C//DTDHTM ...

  10. Android分享图片失败解决方案

    前言:在做图片分享到微博或是用彩信分享的时候,会遇到“无法将图片添加到信息中”,其实这个问题的原因是创建的那个图片默认是,只能被当前应用调用,无法被其他应用调用,即分享的时候,无法读取到图片,并提示I ...

随机推荐

  1. 2021-10-24:快乐数。编写一个算法来判断一个数 n 是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是

    2021-10-24:快乐数.编写一个算法来判断一个数 n 是不是快乐数.「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和.然后重复这个过程直到这个数变为 1,也可能是 ...

  2. LLM探索:环境搭建与模型本地部署

    前言 最近一直在炼丹(搞AIGC这块),突然发现业务代码都索然无味了- 上次发了篇AI画图的文章,ChatGPT虽然没法自己部署,但现在开源的LLM还是不少的,只要有一块差不多的显卡,要搞个LLM本地 ...

  3. macOS下由yarn与npm差异引发的Electron镜像地址读取问题

    记录macOS下由yarn与npm差异引发的Electron镜像地址读取问题 写在前面:该问题仅仅出现在Linux和macOS上,Windows上不存在该问题! 初始背景 最近笔者重新拾起了Elect ...

  4. [vuex] unknown action type:***

    vuex 分模块后使用mapActions调用action老是提示 [vuex] unknown action type:*** 异常 目录 index.js是这样的 import Vue from ...

  5. .net开发者应掌握的利器CommunityToolkit.HighPerformance——MemoryOwner与SpanOwner

    MemoryOwner和SpanOwner都可以理解为是对ArrayPool<>的一个包装,无非一个是在堆栈上,一个是在托管堆上.既然做了包装,那肯定随之而来就是改进和优化. 目录 Mem ...

  6. 手把手实践丨基于STM32+华为云设计的智慧烟感系统

    摘要:当前基于STM32和华为云,设计了一种智慧烟感系统,该系统可以检测烟雾,同时将检测到的数据上传到云端进行处理和分析. 本文分享自华为云社区<基于STM32+华为云设计的智慧烟感系统> ...

  7. Mdnice 简洁主题

    Md2All 是个人非常喜欢的一个 Markdown 排版工具,也是一直以来本公众号推文排版编辑的主要阵地.但发现 Md2All 有时候会非常卡(不太清楚是不是 Md2All 用了国外的服务器),而且 ...

  8. Vue3 之 响应式 API reactive、 effect源码,详细注释

    Vue3之响应式 API reactive. effect源码,详细注释 目录 一.实现响应式 API:reactive.shallowReactive.readonly.shallowReadonl ...

  9. 前端Vue自定义简单实用中国省市区三级联动选择器

    前端Vue自定义简单实用中国省市区三级联动选择器, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=13118 效果图如下: 使用方法 < ...

  10. 了解前端中的BFC(块级格式化上下文)

    BFC(块级格式化上下文) 什么是BFC 指的是一个块级渲染作用域,该区域内拥有一套完整的规则来约束块级盒子的布局,且与区域外部无关. 为什么要使用BFC 当一个盒子不设置高度,当其中的子元素都浮动时 ...