Jcrop+html2canvas实现意见反馈中的截图功能
1,页面大体的样式:
(这个样式是抄的百度的意见反馈,但是没有实现大佬们写的截图方式,在源码中读到了html2canvas的关键字,然后实现了一个略简陋略low的截图方式;)
2,实现的大体思路:
(1) 使用html2canvas将DOM节点转为图片(略过截图模糊、图片跨域、外联样式渲染错误、错位、iframe等...自己百度解决吧,其实不难,把你要转的节点clone一份,append body后面,改变它的层级,z-index:-1,具体百度一下,很多方案)
(2)调用jcrop的API,实现如图效果
(3)将右边的dom再次转为img base64流,传给后台;
完。。。
代码:
$(function () {
//缓存jcrop对象
var jcropApi;
var jcropFlag = false;
var _feedbackDTO = {};
//弹出反馈弹窗
$("#tool-feedback").click(function () {
$('.fb-baidu-wizard').show();
$('.fb-feedback-right-dialog').css({ height: '365px' });
})
$('#fb_jietu').click(function () {
jcropFlag = true;
//需要截图的dom节点
var $str = $('.container');
//获取节点高度,后面为克隆节点设置高度。
var height = $str.height()
//克隆节点,默认为false,不复制方法属性,为true是全部复制。
var cloneDom = $str.clone(false);
//设置克隆节点的css属性,因为之前的层级为0,我们只需要比被克隆的节点层级低即可
cloneDom.css({
"background-color": "white",
"position": "absolute",
"top": "0px",
"z-index": "-1",
"height": height,
"data-show": 1,
});
//消除重复点击;
var cloneDome_length = $('.container').length;
if (cloneDome_length >= 2) {
return false;
}
//将克隆节点动态追加到body后面。
$("body").append(cloneDom);
layer.load(1, {
shade: [0.1, '#000'] //0.1透明度的灰色背景
});
//调用html2canvasAPI
html2canvas(cloneDom, {
onrendered: function (canvas) {
window._image = canvas.toDataURL("image/png");
var img = new Image();
img.id = "drawImg";
img.style.position = "absolute";
img.style.top = 0;
img.style.left = 0;
//截图必须要在dom转为图片之后调用,否则报错!
img.onload = function () {
$('.fb-baidu-wizard').hide();
layer.closeAll('loading');
//为了缓存
$('#crop_preview').attr('src', window._image);
$str.append(img);
$('#drawImg').Jcrop({
allowSelect: true,
onChange: showPreview,
onSelect: showPreview,
aspectRatio: 1,
setSelect: [0, 0, 0, 0] //初始化选中区域,为了操作性
}, function () {
jcropApi = this;//缓存jcrop对象以便销毁;
});
//缓存截图的dom
$('#preview_box').show().css('z-index', -99)
}
img.setAttribute('src', window._image)
}
});
})
$('#fb_close_x').click(function () {
if (jcropApi != null) {
//销毁截屏
jcropApi.destroy();
}
$('#fb_des_content').val('')
$('#feedback_email').val('')
$('#preview_box').hide()
$('.fb-baidu-wizard').hide();
$('#drawImg').remove()
$('.fb-feedback-right-dialog').css({ height: '0' });
if ($(".container")[1]) {
$(".container")[1].remove()
}
})
function showPreview(coords) {
//简单的事件处理程序,响应自onChange,onSelect事件,按照上面的Jcrop调用
if (parseInt(coords.w) > 0) {
//计算预览区域图片缩放的比例,通过计算显示区域的宽度(与高度)与剪裁的宽度(与高度)之比得到
var rx = $("#preview_box").width() / coords.w;
var ry = $("#preview_box").height() / coords.h;
//通过比例值控制图片的样式与显示
$("#crop_preview").css({
width: Math.round(rx * $("#drawImg").width()) + "px", //预览图片宽度为计算比例值与原图片宽度的乘积
height: Math.round(rx * $("#drawImg").height()) + "px", //预览图片高度为计算比例值与原图片高度的乘积
marginLeft: "-" + Math.round(rx * coords.x) + "px",
marginTop: "-" + Math.round(ry * coords.y) + "px"
});
}
};
$('#fb_right_canvas_save').click(function () {
var fb_content = $('#fb_des_content').val();
if (fb_content.length > 400) {
layer.msg("反馈内容不能超过400字");
return false;
}
if (fb_content.length == 0) {
layer.msg("反馈内容不能为空");
return false;
}
var fb_type = $(".form-control").val();
var policeTel = $('#feedback_email').val();
_feedbackDTO = {
returnType: fb_type,
content: fb_content,
policeTel: policeTel,
url: ''
}
if (jcropFlag) {
var $upload_img = $('#preview_box');
html2canvas($upload_img, {
onrendered: function (canvas) {
window._myimage = canvas.toDataURL("image/png");
var img = new Image();
img.id = "upload_img";
img.style.position = "absolute";
img.style.top = 0;
img.style.left = 0;
img.onload = function () {
uploadImg64(window._myimage);
$('#save_img').empty().append(img);
}
img.setAttribute('src', window._myimage)
// var pHtml = "<img style='position: absolute;top: 0;left: 0' id='upload_img' data-flag='1' src="+window._myimage+" />";
$upload_img.hide();
}
});
} else {
savafb()
}
if (jcropApi != null) {
//销毁截屏
jcropApi.destroy();
}
$('.fb-baidu-wizard').hide();
$('#drawImg').remove()
$('.fb-feedback-right-dialog').css({ height: '0' });
if ($(".container")[1]) {
$(".container")[1].remove()
}
})
// $('#tool-feedback').click(function(){
$('#open-my-fb-list').click(function () {
if (jcropApi != null) {
//销毁截屏
jcropApi.destroy();
}
$('.fb-baidu-wizard').hide();
$('#drawImg').remove()
$('.fb-feedback-right-dialog').css({ height: '0' });
if ($(".container")[1]) {
$(".container")[1].remove()
}
layui.use('layer', function () {
var layer = layui.layer;
layer.open({
type: 1,
title: false,
area: ['1220px', '660px'],
skin: 'layui-layer-lan',
content: $('.my-fb-list'),
// skin:'yinying-none',
shade: 0.4,
end: function () {
}
});
});
})
getData("#fb_type select", '');
/*数据初始化*/
function getData(obj, val) {
var appendHtml = '';
$.ajax({
url: bpath + '/return/getSymCode',
type: 'post',
dataType: 'json',
data: {parentId:'1'},
success: function (data) {
var datavalue = data.zddata;
$.each(datavalue, function (item, data) {
appendHtml += "<option value='" + data.zdz + "'>" + data.name + "</option>";
});
$(obj).append(appendHtml);
}
});
}
function uploadImg64(base64) {
var feedbackDTO = {
img1: base64
}
$.ajax({
url: bpath + '/return/uploadBase',
type: 'post',
dataType: 'json',
data: feedbackDTO,
success: function (data) {
// alert(data)
if (data.operate == 'success') {
var imgurl = data.result[0].url;
if (imgurl) {
savafb(imgurl)
}
}
//调用提交反馈方法
}
});
};
function savafb(imgurl) {
var feedbackDTO = {}
if (imgurl) {
feedbackDTO.url = imgurl;
} else {
feedbackDTO.url = ''
}
feedbackDTO.returnType = _feedbackDTO.returnType;
feedbackDTO.content = _feedbackDTO.content;
feedbackDTO.policeTel = _feedbackDTO.policeTel;
$.ajax({
url: bpath + '/return/addReturn',
type: 'post',
dataType: 'json',
data: feedbackDTO,
success: function (data) {
if (data.code == 1) {
$('#save_img').empty()
$('#fb_des_content').val('')
layer.alert('您的意见已经收到,谢谢!', { icon: 6 });
}
}
});
}
getMyReturnList();
function getMyReturnList(){
$.ajax({
url: bpath + '/return/myReturn',
type: 'post',
dataType: 'json',
data: '',
success: function (data) {
console.log(data);
var html= '';
$.each(data.list, function (index, item) {
$('.my-fb-list').append(
'<div class="fb-describe">'+
'<span class="fb-tip">问题:</span>'+
'<span class="my-fb-content" title="">'+ item.content +'</span>'+
'<span class="fb-uptime">'+ item.submitDate +'</span>'+
'<span class="fb-return-tip" style="color:#58b05d">回复:</span>'+
'<span class="my-fb-return-content">'+(item.returnContent?item.returnContent:'')+'</span>'+
'</div>'
)
});
},
error: function (data) {
console.log(data);
}
});
};
})
DOM:
<span style="display: none" id="preview_box" class="crop_preview">
<img id="crop_preview" src="images/mid-content.png"/>
</span>
<div class="fb-baidu-wizard" style="display: none;"></div>
<div id="fb_baidu_right_dialog" class="fb-feedback-right-dialog" style="">
<div class="fb-modal " data-html2canvas-ignore="true">
<div class="fb-header" id="fb_dialog_header" unselectable="on" onselectstart="return false;">
<a class="fb-close" id="fb_close_x">×</a>
<h3 class="fb-header-tips">意见反馈
<font style="font-size:13px;color:#2d9ef8;line-height:13px;">|
<a id="open-my-fb-list" style="font-size:13px;color:#2d9ef8;line-height:13px;" href="#">
我的反馈
</a>
</font>
</h3>
</div>
<div class="fb-body" id="fb_qa_feedback_body">
<div class="form-group" id="fb_type">
<label>反馈类型</label>
<select class="form-control">
</select>
</div>
<!-- <div style="width: 35%;float: right;top: 0" class="fb-block fb-cut-block">
<div>
<input type="button" class="fb-btn fb-cut-btn"
style="background: url(https://sp2.baidu.com/-uV1bjeh1BF3odCf/feedback/images/jietu.png) no-repeat center"
id="fb_jietu" value="">
<span id="fb_tips_span">
</span>
</div>
</div> -->
<div class="fb-action" style="clear: both">
<div class="fb-tips-block">
<span class="fb-danger-tips">*</span>
<span class="fb-content-tips">反馈内容</span>
</div>
<div class="fb-textarea fb-content-block">
<textarea maxlength="400" class="fb-des-content" name="issuedesc" id="fb_des_content"
data-exclude="true" placeholder="欢迎提出您在使用过程中遇到的问题或宝贵建议(400字以内),感谢您对图像应用平台的支持。"></textarea>
</div>
<div class="fb-block fb-email-block">
<div class="fb-phone-txt">联系方式</div>
<div>
<input type="text" class="fb-email" maxlength="100" value="" placeholder="请留下您的联系方式,以便我们及时回复您。" id="feedback_email">
</div>
</div>
</div>
<div class="fb-footer">
<div class="fb-btn fb-btn-primary" id="fb_right_canvas_save">提交反馈</div>
</div>
</div>
</div>
</div>
<div style="display: none" id="save_img"></div>
这个中间还有很多遮罩和显隐,挺多细节需要注意,前端小白,代码写的很烂,希望能帮到碰到类似需求的人