I'm trying to create a functional component that renders the Feather Icons package but I'm not able to figure out the last step. Here's what I got:
This is my FeatherIcon.vue component.
<script>
const feather = require("feather-icons");
export default {
components: {},
props: {
type: {
required: true,
type: String
}
},
mounted() {},
render(createElement) {
return createElement(
"svg",
{attrs: feather.icons[this.type].attrs },
feather.icons[this.type].contents
);
}
};
</script>
The 3rd argument according to Vue docs says that it should be either:
// {String | Array}
// Children VNodes, built using `createElement()`,
// or using strings to get 'text VNodes'. Optional.
However, the result of my 3rd argument feather.icon[this.type].contents is a string containing the "innerHTML" inside the svg tag:
"<line x1="6" y1="3" x2="6" y2="15"></line><circle cx="18" cy="6" r="3"></circle><circle cx="6" cy="18" r="3"></circle><path d="M18 9a9 9 0 0 1-9 9"></path>"
So my question is, how to convert feather.icon[this.type].contents into a set of VNodes?
I've tried with DOMParser and using parseFromString but no luck. Any idea?
You can use the domProps
property of the data object.
This object also allows you to bind normal HTML attributes as well as DOM properties such as innerHTML (this would replace the v-html directive)
Here is an example.
console.clear()
const content = `
<line x1="6" y1="3" x2="6" y2="15"></line>
<circle cx="18" cy="6" r="3"></circle>
<circle cx="6" cy="18" r="3"></circle>
<path d="M18 9a9 9 0 0 1-9 9"></path>
`
new Vue({
el: "#app",
render(h){
return h("svg", {domProps:{innerHTML: content}})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app"></div>
In your case, you would just set innerHTML to the content from feathers.
Also, as a side note, if you don't have a template, generally you just use a straight javascript file. You don't need a single file component. So your component would be
FeatherIcon.js
const feather = require("feather-icons");
export default {
props: {
type: {
required: true,
type: String
}
},
render(createElement) {
return createElement(
"svg",
{
attrs: feather.icons[this.type].attrs,
domProps: {
innerHTML: feather.icons[this.type].content
}
});
}
};
Finally, you mentioned wanted to make this a functional component, in which case, you could just do something like this:
const FeatherIcon = {
functional: true,
props: {
type: {
required: true,
type: String
}
},
render(h, context){
const {contents, attrs} = feather.icons[context.props.type]
return h("svg", {attrs, domProps: {innerHTML: contents}})
}
};
Here is an example of that working.
console.clear()
const FeatherIcon = {
functional: true,
props: {
type: {
required: true,
type: String
}
},
render(h, context){
const {contents, attrs} = feather.icons[context.props.type]
return h("svg", {attrs, domProps: {innerHTML: contents}})
}
};
new Vue({
el: "#app",
components: {
FeatherIcon
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<div id="app">
<feather-icon type="eye"></feather-icon>
<feather-icon type="activity"></feather-icon>
<feather-icon type="award"></feather-icon>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With