在一些情况下,我们想要将类似d3.js之类的框架渲染的svg保存到本地,这要怎么实现呢?其实非常简单。
首先,让我们创建一个用来下载的函数,这个函数不仅仅支持svg,甚至可以支持任意内容。
function download(href, name) { var a = document.createElement('a'); a.download = name; a.href = href; document.body.appendChild(a); a.click(); document.body.removeChild(a); }
我们创建了一个通用的下载函数,但是这个href只支持url,所以,我们要创建一个函数来获得svg的url。
function createObjectUrl(content, type) { return window.URL.createObjectURL(new Blob(content, { type: type })) }
这个函数的content是可以支持多个类型的,因为它会被传入new Blob中,但是需要注意,如果传入字符串,要传入一个数组。
download(createObjectUrl(['<div></div>'], 'text/html'), 'index.html')
现在就好办了,我们只要把svg元素的outerHTML读出来,然后传给download函数就可以了。
download(createObjectUrl([document.querySelector('svg').outerHTML, 'image/svg'), 'some.svg')
对上面操作进行简单封装
function downloadSvg(svg, name) { download(createObjectUrl([document.querySelector(svg).outerHTML, 'image/svg'), name) }
如果要下载为其他类型的图片,那在download之前,要进行一个转码,我们用canvas作为中转,把svg放到一个canvas中之后在下载。
function downloadSvgAsPng(svg, name) { const text = document.querySelector(svg).outerHTML const { width, height } = svg // 或者通过其他方式也可以获得宽高 const image = new Image() image.onload = () => { const canvas = document.createElement('canvas') canvas.width = width cnavas.height = height const context = canvas.getContext('2d') context.fillStyle = context.createPattern(image, 'repeat') context.fillRect(0, 0, width, height) download(canvas.toDataURL('image/png'), name) } image.src = 'data:image/svg+xml;base64,' + btoa(text) }
此处我们没有用到createObjectUrl,因为我们直接将svg转化为base64然后渲染到canvas里面,变成了位图。
最后,需要注意的是,使用这种方法,我们必须在svg内完全定义自身的样式,如果你是在svg之外定义了svg内部元素的样式,那么下载的svg就不包含这部分样式,那自然就会有样式问题。