svg图片渲染到页面的几种方式
- 背景
- 🟡require.context获取目录下的所有文件
- 🟡方式1: 直接在html中渲染
- 🟡方式: 发起ajax请求,获取SVG文件
背景
需要实现从本地目录下去获取所有的svg图标进行预览,将选中的图片显示在另一个地方,再上传。
🟡require.context获取目录下的所有文件
require.context
中传入三个参数:一 个要搜索的目录,一个标记位表示是否还搜索其子目录, 以及一个匹配文件的正则表达式。
// 获取该目录下的所有svg文件
const files = require.context('static/topology/icon', false, /\.svg$/);
const imgs = files.keys().map((key) => files(key));// 返回一个数组,存储的是base64字符串
这个字符串是一段base64
编码后的SVG图片数据,可以直接在HTML/CSS中使用,进行图片的预览
🔸如果还想获取该svg图片的文件名:
const iconImgs= ref<{ url: string; name: string }[]>([]);
const files = require.context('static/topology/icon', false, /\.svg$/);
const imgs = files.keys().map((key) => {
iconImgs.value = key.split('/').pop(); // 提取文件名部分
return {
url: files(key), // base64编码的字符串
name: fileName, // 文件名 xx.svg
};
});
🔸注意:如果在ts
中使用会出现以下的警告: 类型"NodeRequire”上不存在属性"context”
🔸解决方法:
npm install --save-dev @types/webpack-env
{
"compilerOptions": {
// other options...
"types": [
// other types...
"webpack-env"
]
}
}
🟡方式1: 直接在html中渲染
将base64字符串直接绑定到img
的src
上,一般用于图片的预览。
<div v-for="(item, index) in iconImgs" :key="index" >
<div
:title="item.name.split('.')[0]">
<img :src="item.url" />
</div>
</div>
🟡方式: 发起ajax请求,获取SVG文件
一般用于图片的回显,根据名称或者i d.
async function getImage(name = 'default') {
try {
const iconName = name || 'default';
iconUrl = `${window.__ctx}/static/icon/${iconName}.svg`;
//发起ajax请求,获取SVG文件
const res = await $.ajax({
url: iconUrl,
type: 'GET',
dataType: 'xml',
});
console.log('res', res);//打印见下图1
// 解析SVG文件,获取SVG元素
var svg = $(res).find('svg');
console.log('svg:', svg);//打印见下图2
if (!svg || svg.length === 0) throw new Error(`${name}.svg 图标不存在`);
svg.css({ width: '96px', height: '96px' });//给svg图片设置样式
// 将 svg 元素的 HTML 内容赋值给 iconImage,绑定到div的v-html就可以显示了
iconImage.value = svg.prop('outerHTML');
console.log('iconImage:', iconImage.value);//打印见下图2
// 将svg图片变成文件,待上传
//注意:这里传的一定是svg字符串,而且type一定是image/svg+xml格式(这边之前踩了坑!!)
iconFile.value = new File([new Blob([iconImage.value], { type: 'image/svg+xml' })], `${name}.svg`, {
type: 'image/svg+xml',
});
} catch (err) {
console.log(`[log] - getImage - err:`, err);
// 如果获取不到图标则使用默认图标
if (name !== 'default') {
await getImage('default');
}
}
}
🔸【图1】:是一个document
文档
🔸【图2】:是一个svg
元素,可使用$(res).find('svg')
去获取.
将获取到的SVG文件内容转换成jQuery
对象,然后通过jQuery对象的find()
方法,筛选出其中的SVG
元素。
🔸不借助jQuery的实现方法:
1.使用原生的DOMParser
去解析
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(svgStr, 'image/svg+xml');
2. querySelector
或者getElementsByTagName
方法获取 SVG 元素
const svgElement = xmlDoc.querySelector('svg');
const pathElements = xmlDoc.getElementsByTagName('path');
🔸【图3】:svg元素的内容,通过svg.prop('outerHTML')
可以得到。
🔸将svg元素的内容显示在页面上:
<div
title="点击选择图标"
style="width: 112px; height: 112px; border: 1px solid #c3cdd7"
@click="showIconDialog"
v-html="iconImage"></div>
💦小插曲:
之前将svg转成文件后上传,服务器显示的文件是[object XMLDocument]
, 是由于请求的参数类型不正确导致的。
一开始的错误写法:将svg文档转成字节流了
iconFile.value = new File([new Blob([res], { type: 'image/svg+xml' })], `${name}.svg`);
🔸正常的传参显示:svg元素的内容
🔸svg内容的两种形式的区别
前面的这个包含了一些冗余数据,后面这个是经过压缩的,只有 svg 路径数据。