<template> | |
<div class="inline-block" v-html="require('icon-' + this.icon + '.svg')"></div> | |
</template> | |
<style module> | |
.svg { | |
fill: currentColor; | |
height: 1em; | |
margin-top: -4px; | |
vertical-align: middle; | |
width: 1em; | |
} | |
</style> | |
<script> | |
export default { | |
props: ['icon'], | |
mounted() { | |
this.$el.firstChild.classList.add(this.$style.svg) | |
this.$el.firstChild.removeAttribute('height') | |
this.$el.firstChild.removeAttribute('width') | |
} | |
} | |
</script> | |
// Here is the custom code for my webpack.mix.js file: | |
// Exclude svg icons | |
Mix.listen('configReady', function (config) { | |
const rules = config.module.rules; | |
const targetRegex = /(\.(png|jpe?g|gif)$|^((?!font).)*\.svg$)/; | |
for (let rule of rules) { | |
if (rule.test.toString() == targetRegex.toString()) { | |
rule.exclude = /\.svg$/; | |
break; | |
} | |
} | |
}); | |
// Use a custom loader for inline icons | |
mix.webpackConfig({ | |
module: { | |
rules: [{ | |
test: /\.svg$/, | |
use: [{ | |
loader: 'html-loader', | |
options: { | |
minimize: true | |
} | |
}] | |
}] | |
}, | |
resolve: { | |
modules: [ path.resolve(__dirname, 'resources/assets/svg') ] | |
} | |
}); | |
This comment has been minimized.
This comment has been minimized.
Awesome! A tip though, if you change your require to |
This comment has been minimized.
This comment has been minimized.
I ended up shrinking it a bit thanks to @beijer.
and to implement inside your vue component
Should output
This is so useful because you can now see what the svg instead of having preview it in the browser |
This comment has been minimized.
This comment has been minimized.
Thank you guys for these useful examples. @blueoctopuswebdesigns you can simplify your usage a tad more. ...
mounted() {
this.$el.removeAttribute('class');
this.$el.firstChild.classList.add(...this.$vnode.data.staticClass.split(' '));
}
...
Hope this helps! |
This comment has been minimized.
This comment has been minimized.
Thanks for this gist and great comments guys. I also wanted to remove the container div and just render a I also added a <template>
<div v-html="require('!!html-loader!./../../../svg/zondicons/' + this.icon + '.svg')" v-once></div>
</template>
<script>
export default {
props: ['icon'],
mounted() {
this.$el.firstChild.classList.add(...this.$el.className.split(' '));
this.$el.firstChild.classList.add('fill-current');
this.$el.outerHTML = this.$el.innerHTML;
},
};
</script> Quick note: I'm using Zondicons that don't have the height and width attributes, that's why I don't have the lines that remove those attributes. |
This comment has been minimized.
This comment has been minimized.
@calebporzio great article and nice solution! A few things I've changed:
Hope this helps someone. Btw, in case anyone wants to modify
|
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
This is a pretty amazing idea, the main draw back is that it now adds the entire icon set that I'm using to app.js, instead of extracting the data from the specific file. So remember to either make a stripped down version of only the icons that you need. |
This comment has been minimized.
This comment has been minimized.
npm i -D html-loader
mix.webpackConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/'),
},
},
});
<template>
<div v-html="require(`!!html-loader!@/svg/${icon}.svg`)" v-once></div>
</template>
<script>
export default {
props: {
name: {
default: '',
type: String,
},
},
mounted() {
this.$el.firstChild.classList.add(...this.$el.className.split(' '));
this.$el.outerHTML = this.$el.innerHTML;
},
}
</script> |
This comment has been minimized.
This comment has been minimized.
Thanks for all the examples! Based on these, I came up with a mix of some proposals:
Also ensure you have the path set up correctly in <template>
<div
v-html="require(`!!html-loader!@Icons/${name}.svg`)" class="svg-icon"
v-once
role="img"
></div>
</template>
<script>
export default {
props: {
name: {
default: '',
type: String,
required: true,
},
},
mounted() {
this.$el.firstChild.removeAttribute('width')
this.$el.firstChild.removeAttribute('height')
// Reassign class list and remove the div wrapper
this.$el.firstChild.classList.add(...this.$el.className.split(' '))
this.$el.outerHTML = this.$el.innerHTML
},
}
</script>
<style module>
.svg-icon {
height: 1em;
margin-top: -4px;
vertical-align: middle;
width: 1em;
}
</style> |
This comment has been minimized.
Awesome, thanks!
The link to the post in case someone finds this first: http://calebporzio.com/using-inline-svgs-in-vue-compoments/