Vuejs组件中的内联SVG

9
我使用@vue/cli 3.0.0-beta.16创建了一个Vuejs项目,在Home.vue单文件组件中,我想在模板中导入并添加内联SVG,但我遇到了麻烦。
问题是vue cli已经将 .svg 文件扩展名用于文件加载器,例如:
webpackConfig.module
  .rule('svg')
    .test(/\.(svg)(\?.*)?$/)
    .use('file-loader')
      .loader('file-loader')
      .options({
        name: getAssetPath(options, `img/[name].[hash:8].[ext]`)
      })

我已经尝试使用html-loader插件来将svg包含在模板中,如果我清除vue.config.js中默认的svg use并添加自己的加载器,它就可以正常工作:

// vue.config.js

chainWebpack: config => {
    const svgRule = config.module.rule('svg')

    // clear all existing loaders.
    // if you don't do this, the loader below will be appended to
    // existing loaders of the rule.
    svgRule.uses.clear()

    // add replacement loader(s)
    svgRule
    .test(/\.(svg)$/)
    .use('html-loader')
    .loader('html-loader')
    .options({
    })
}

并且在我的模板中:
// Home.vue

<div v-html="require('./../assets/inline.svg')"></div>

但问题是,它也会用内联svg代码替换<img />标签中的svg src。我想要的是对于<img src="something.svg" />使用file-loader,并对于require('./inline.svg')使用html-loader。我该如何在webpack中为同一规则使用多个加载器?或者这是否是正确的方法?任何帮助将不胜感激。
编辑 我认为问题在于我错误地添加了两个加载器。这是我在文件中添加它们的方式:
// vue.config.js

svgRule
.test(/\.(svg)$/)
.use('file-loader')
.loader('file-loader')
.options({
  name: getAssetPath(options, `img/[name].[ext]`)
})

svgRule
.test(/\.(svg)$/)
.use('html-loader')
.loader('html-loader')
.options({
  attrs: ['div:v-html']
})

希望这可以帮到你:https://stackoverflow.com/questions/49383528/vue-loader-different-loaders-for-one-extension - Irony
4个回答

6

您可以在 require 表达式中添加前导的 ! 来“覆盖”由 webpack 配置设置的现有加载程序。

<div v-html="require('!html-loader!./../assets/inline.svg')"></div>

这将不需要更改 vue.config.js,只要安装了 html-loader 即可。
另外,可以尝试使用 svg-inline-loader,它可以为类和 id 添加哈希值,这样如果页面上有多个内联 svg,则不需要担心名称冲突问题。

这个方法很好,但是当尝试从变量中加载 .svg 文件时会出现问题,例如 <div v-html="require(\!html-loader!${mySvg}`)"></div>`。有没有办法让它正常工作? - tettoffensive
@tettoffensive 我认为这与加载器覆盖无关,除非它以某种方式防止webpack识别表达式。请阅读以下文档页面,看看是否有帮助 https://webpack.js.org/guides/dependency-management/ 您应该将路径与 . 作为字符串的一部分 ./${mySvg} 而不仅仅是 ${mySvg},即使尽可能将变量保持在路径的最小部分或最好避免在导入中使用变量。 - Igonato
就我所知,这在Vue 3中似乎无法工作。 - Connor Shea

5

如果您尚未安装html-loader,请执行以下命令:

yarn add -D html-loader

然后在你的webpack配置文件中的rules数组中添加以下对象:
{
  test: /\.svg$/,
  use: [{ loader: 'html-loader' }]
}

最后,您将能够使用内联加载器将svg文件导入到您的脚本中。

require('!html-loader!./../assets/inline.svg')

// or directly in your v-html directive
<div v-html="require('!html-loader!./../assets/inline.svg')"></div>

1

你已经快完成了,只需告诉Webpack使用哪个加载器:

<div v-html="require('html-loader!./../assets/inline.svg')"/>

1
谢谢回复。我尝试了那个方法,但是如果我不在vue.config文件中添加html-loader,它似乎不起作用,而如果我添加了它,file-loader就停止工作了。我无法弄清楚如何正确添加这两个加载器。 - Atta ur Rehman

0

你可能想要同时使用webpack加载器,但也要告诉你的html加载器仅限于使用以下语法中带有v-htmldiv元素:

{
  attrs: ['div:v-html']
}

HTML 加载器的文档可以在 这里 找到。


1
我尝试过了,但只有在删除文件加载器时才能正常工作,而在这种情况下 <img src="something.svg" /> 就无法工作。我似乎无法弄清如何同时使用两个加载器。 PS:这是我添加两个加载器的方式: svgRule // .test(/.(svg)(?.*)?$/) .test(/.(svg)$/) .use('file-loader') .loader('file-loader') .options({ name: getAssetPath(options, img/[name].[ext]) })svgRule .test(/.(svg)$/) .use('html-loader') .loader('html-loader') .options({ }) - Atta ur Rehman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接