【问题标题】:Vue 3 Vite - dynamic img srcVue 3 Vite - 动态 img src
【发布时间】:2021-05-30 19:41:50
【问题描述】:

我正在使用 Vue 3 和 Vite。在 Vite 构建生产后,我遇到了动态 img src 的问题。静态img src没有问题。

<img src="/src/assets/images/my-image.png" alt="Image" class="logo"/>

它在两种情况下都运行良好:在开发模式下运行时以及在 vite 构建之后。但是我有一些图像名称存储在动态加载的数据库中(菜单图标)。在这种情况下,我必须像这样编写路径:

<img :src="'/src/assets/images/' + menuItem.iconSource" />

(menuItem.iconSource 包含图像的名称,例如“my-image.png”)。 在这种情况下,它在以开发模式运行应用程序时有效,但在生产构建后无效。当 Vite 为生产构建应用程序时,路径会发生变化(所有资产都放入 _assets 文件夹中)。静态图像源由 Vite 构建处理并相应更改路径,但组合图像源并非如此。它只是将/src/assets/images/ 作为一个常量并且不会更改它(当应用程序抛出 404 not found for image /src/assets/images/my-image.png 时,我可以在网络监视器中看到它)。 我试图找到解决方案,有人建议使用require(),但我不确定vite是否可以使用它。

【问题讨论】:

    标签: vuejs3 vite


    【解决方案1】:

    按照 Vite 文档,您可以使用此处提到和解释的解决方案:

    vite documentation

    const imgUrl = new URL('./img.png', import.meta.url)
    
    document.getElementById('hero-img').src = imgUrl
    

    我在计算属性中使用它来动态设置路径,例如:

        var imagePath = computed(() => {
          switch (condition.value) {
            case 1:
              const imgUrl = new URL('../assets/1.jpg',
                import.meta.url)
              return imgUrl
              break;
            case 2:
              const imgUrl2 = new URL('../assets/2.jpg',
                import.meta.url)
              return imgUrl2
              break;
            case 3:
              const imgUrl3 = new URL('../assets/3.jpg',
                import.meta.url)
              return imgUrl3
              break;
          }
        });
    

    非常适合我。

    【讨论】:

      【解决方案2】:

      请尝试以下方法

      const getSrc = (name) => {
          const path = `/static/icon/${name}.svg`;
          const modules = import.meta.globEager("/static/icon/*.svg");
          return modules[path].default;
        };
      

      【讨论】:

      • 纯代码答案并不是特别有用。请添加一些关于此代码如何解决问题的说明。
      • 嗨。嗯,这行得通。但它是如何工作的?你可以解释吗?每次请求图标时,加载所有图标的代码都会运行,或者不运行?这会非常低效,不是吗?
      • 这不是一个很好的方法,确实存在引入太多无用内容的问题,但是我尝试用一​​个变量来定义图片路径到import.meta.globEager,这个方法会报错一个错误,它只能接收一个字符串类型。如果有更好的解决方案可以提供给我,非常感谢!
      【解决方案3】:

      require()import() 用于在基于 Webpack 的 Vue 应用程序中解决这种情况确实是仅 Webpack 构造

      在幕后,Webpack 通过将路径固定部分 (/src/assets/images/) 中的每个文件作为应用程序包的一部分并可供导入来处理此类动态导入。对于图像,这通常意味着创建某种内部地图,如下所示:

      {
       'src/assets/images/image1.png' : 'assets/img/image1.hash.png',
        ...
      }
      

      关键是图像在源树中的路径。该值是由负责在构建期间处理图像的加载程序创建的路径(捆绑应用程序中的图像路径)。 Webpack 在运行时使用此映射将动态生成的路径“解析”为图像的真实路径

      在 Vite 中没有require(),但您可以通过使用Glob Import 来创建与上述类似的“地图”并使用此地图您自己

      或者您可以使用this plugin 以不太透明的方式做类似的事情...

      更多详情this GitHub issue

      更新

      由于 Vite 在后台使用 Rollup,使用 plugin-dynamic-import-vars 可能是另一种解决方案,用法与 Webpack 非常相似...

      但是这目前有一个 limitation 只允许相对路径,这使得 Glob Imports 可能是更好的选择

      【讨论】:

        【解决方案4】:

        使用 Vite 的 API import.meta.glob 效果很好,我参考了 webpack-to-vite 文档中的步骤。它列出了一些转换项和错误修复方法。它甚至可以一键将旧项目转换为 vite 项目。不错,推荐!

        1. 创建一个模型来保存导入的模块,使用异步方法动态导入模块并将它们更新到模型中
        // src/store/index.js
        import Vue from 'vue'
        import Vuex from 'vuex'
        const assets = import.meta.glob('../assets/**')
        Vue.use(Vuex)
        export default new Vuex.Store({
          state: {
            assets: {}
          },
          mutations: {
            setAssets(state, data) {
              state.assets = Object.assign({}, state.assets, data)
            }
          },
          actions: {
            async getAssets({ commit }, url) {
              const getAsset = assets[url]
              if (!getAsset) {
                commit('setAssets', { [url]: ''})
              } else {
                const asset = await getAsset()
                commit('setAssets', { [url]: asset.default })
              }
            }
          }
        })
        
        1. .vue SFC 中使用
        // img1.vue
        <template>
          <img :src="$store.state.assets['../assets/images/' + options.src]" />
        </template>
        <script>
        export default {
          name: "img1",
          props: {
            options: Object
          },
          watch: {
            'options.src': {
              handler (val) {
                this.$store.dispatch('getAssets', `../assets/images/${val}`)
              },
              immediate: true,
              deep: true
            }
          }
        }
        </script>
        

        【讨论】:

          猜你喜欢
          • 2020-11-05
          • 1970-01-01
          • 2021-11-02
          • 2022-10-04
          • 2018-09-15
          • 1970-01-01
          • 2021-10-14
          • 2021-02-12
          • 1970-01-01
          相关资源
          最近更新 更多