核心逻辑
在 H5 实现一个长按 dom 节点,将当前节点保存为图片的功能,核心步骤如下
- 实现长按功能
- dom 转 canvas
长按功能
- 封装为一个
class
类,以保证能在页面中调用多个实例进行多个dom盒子的转换canvas; - 定义为从开始触摸屏幕
touchstart
到 结束触摸屏幕touchend
连续700ms
视为长按;
dom 转 canvas
我们选择 html2canvas
来实现这个功能,它是非常强大的!感谢开源社区,感谢大佬!
当然并不是所有的页面元素都可以进行转换的,下面是不支持的情况:
- 不支持 iframe
- 不支持跨域图片(可以先将线上图片转换成 base64,然后用 base64 作为图片路径)
- 不支持 flash
- 不支持 transform、transition 过渡、animation 动画(备注:transform 初始布局是可以的,但是不能参与动画类的操作)
因此在测试代码中也加入了一些场景的测试,比如 transform
、transition
、canvas
、animation
代码
核心代码
longPressSave2Img.js
import html2canvas from 'html2canvas'
// 长按 dom 保存 dom 为图片
class LongPress {
constructor(el, cb) {
this.element = el
this.timer = null
this.init(cb)
}
init (cb) {
this.touchStart(cb)
this.touchEnd()
}
// 开始触摸
touchStart(cb) {
this.element.addEventListener('touchstart', function (e) {
e.preventDefault()
this.timer = setTimeout(() => {
cb?.()
}, 700)
}, { passive: false })
}
// 结束触摸
touchEnd () {
this.element.addEventListener('touchend', function (e) {
e.preventDefault()
clearTimeout(this.timer)
this.timer = null
}, { passive: false })
}
// htmlToCanvas
htmlToCanvas({ mime, encoderOptions, ...html2canvasOpts }, cb) {
html2canvas(this.element, html2canvasOpts).then(canvas => {
try {
const imgUrl = canvas.toDataURL(mime, encoderOptions); // 此方法可以设置截图质量(0-1)
cb?.({
flag: 1,
data: imgUrl
})
} catch (err) {
cb?.({
flag: 0,
message: err.message
})
}
});
}
}
export default LongPress
测试代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>绘制图片</title>
<style>
canvas {
border: 1px solid red;
}
#box1 {
width: 300px;
}
.base {
transform: translate(100px);
width: 100px;
height: 100px;
display: inline-block;
background-color: #0EA9FF;
border-width: 5px;
border-style: solid;
border-color: #5daf34;
transition-property: width,height,background-color,border-width;
transition-duration: 2s;
transition-timing-function: ease-in;
transition-delay: 500ms;
}
@-ms-keyframes boke /* -ms-为了兼容IE 浏览器*/
{
0% {background: green;}
25% {background: yellow;}
50% {background: blue;}
100% {background: red;}
}
@-moz-keyframes boke /* -moz-为了兼容Firefox 浏览器*/
{
0% {background: green;}
25% {background: yellow;}
50% {background: blue;}
100% {background: red;}
}
@-webkit-keyframes boke /* -webkit-为了兼容Safari 和 Chrome 浏览器*/
{
0% {background: red;}
25% {background: yellow;}
50% {background: blue;}
100% {background: green;}
}
@-o-keyframes boke /*-o-为了兼容 Opera浏览器 */
{
0% {background: red;}
25% {background: yellow;}
50% {background: blue;}
100% {background: green;}
}
div {
animation-name: boke;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
}
html, body{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="box1">
<div class="base"></div>
<h5>transition配合transform一起使用</h5>
<canvas id="box-canvas"></canvas>
</div>
<div id="box2">
<div>box 2</div>
<div>box 2</div>
<div>box 2</div>
<div>box 2</div>
</div>
<script>
</script>
</body>
</html>
js
import LongPressSave2Img from './longPressSave2ImgCallback'
import photo from "./static/吕布.jpeg";
// 创建高清 Canvas
function createHDCanvas (w=300,h=150) {
var ratio = window.devicePixelRatio || 1;
var canvas = document.getElementById('box-canvas');
canvas.width = w * ratio; // 实际渲染像素
canvas.height = h * ratio; // 实际渲染像素
canvas.style.width = `${w}px`; // 控制显示大小
canvas.style.height = `${h}px`; // 控制显示大小
// setTransform() 允许您缩放、旋转、移动并倾斜当前的环境
canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
return canvas;
}
// 画一个canvas
const drawCanvas = () => {
var canvas = createHDCanvas(300,190)
var context = canvas.getContext("2d");
var img = new Image();
img.src = photo;
img.onload = function () {
context.drawImage(img,0,0,300,190)
}
}
drawCanvas()
// ===================
const el = document.querySelector('#box1')
const long1 = new LongPressSave2Img(el, () => {
console.log('longPress then');
const r = window.confirm("要保存为图片吗?");
if(r === true){
long1.htmlToCanvas({ mime: 'image/jpeg' }, ({ flag, data }) => {
if (flag) {
console.log("base64编码数据:", data);
const a = document.createElement('a')
a.href = data
a.download = 'base64编码数据'
a.click()
}
})
}
})
const el2 = document.querySelector('#box2')
const long2 = new LongPressSave2Img(el2, () => {
console.log('longPress then');
const r = window.confirm("要保存为图片吗?");
if(r === true){
long2.htmlToCanvas({}, ({ flag, data }) => {
if (flag) {
console.log("base64编码数据:", data);
const a = document.createElement('a')
a.href = data
a.download = 'base64编码数据'
a.click()
}
})
}
})