Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix
  • Loading branch information
wxiaoguang committed Mar 19, 2023
commit 6d93d554bd408a66767c415320f4d1a53c74572b
42 changes: 40 additions & 2 deletions web_src/js/svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export function svg(name, size = 16, className = '') {
const svgNode = document.firstChild;
if (size !== 16) svgNode.setAttribute('width', String(size));
if (size !== 16) svgNode.setAttribute('height', String(size));
// filter array to remove empty string
if (className) svgNode.classList.add(...className.split(/\s+/).filter(Boolean));
return serializer.serializeToString(svgNode);
}
Expand All @@ -120,6 +119,45 @@ export const SvgIcon = {
className: {type: String, default: ''},
},
render() {
return h('span', {innerHTML: svg(this.name, this.size, this.className)});
const svgStr = svgs[this.name];
if (!svgStr) throw new Error(`Unknown SVG icon: ${this.name}`);

// parse the SVG string to 2 parts
// * svgInnerHtml: the inner part of the SVG, will be used as the content of the <svg> VNode
// * svgOuter: the outer part of the SVG, including attributes
// the builtin SVG contents are clean, so it's safe to use `indexOf` to split the content:
// eg: <svg outer-attributes>${svgInnerHtml}</svg>
const p1 = svgStr.indexOf('>'), p2 = svgStr.lastIndexOf('<');
if (p1 === -1 || p2 === -1) throw new Error(`Invalid SVG icon: ${this.name}`);
const svgInnerHtml = svgStr.slice(p1 + 1, p2);
const svgOuterHtml = svgStr.slice(0, p1 + 1) + svgStr.slice(p2);
const svgDoc = parser.parseFromString(svgOuterHtml, 'image/svg+xml');
const svgOuter = svgDoc.firstChild;

// https://vuejs.org/guide/extras/render-function.html#creating-vnodes
// the `^` is used for attr, set SVG attributes like 'width', `aria-hidden`, `viewBox`, etc
const attrs = {};
for (const attr of svgOuter.attributes) {
if (attr.name === 'class') continue;
attrs[`^${attr.name}`] = attr.value;
}
attrs[`^width`] = this.size;
attrs[`^height`] = this.size;

// make the <SvgIcon class="foo" class-name="bar"> classes work together
const classes = [];
for (const cls of svgOuter.classList) {
classes.push(cls);
}
if (this.className) {
classes.push(...this.className.split(/\s+/).filter(Boolean));
}

// create VNode
return h('svg', {
...attrs,
class: classes,
innerHTML: svgInnerHtml,
});
},
};