在实际的开发中,我们不难遇到移动端h5的开发,各种手机的兼容,安卓与ios,华为与小米,让我们头痛不已,在移动端海报截屏之中,网上有很多的案例,但是要么不稳定,要么需要的插件太大,要么就是兼容性差。
而这套代码,是经历过生产的考验的,目前没有发现不兼容的情况,很稳定,效率也比较高。
实现移动端h5截屏
- 引入js
<script src="./js/flexible.js" defer="defer"></script>
<script src="./js/html2canvas.js" defer="defer"></script>
<script src="./js/vue-2.4.2.min.js"></script>
- 书写html代码
<div id="app">
<div id="img" style="width: 100%;">
<p class="top">这是头部,可以放logo或者文字图片</p>
<div class="div_qrcode">
<img src="img/18539204593.jpg" class="qrCode"/>
</div>
<p class="bottom">这是底部,可以放一些修饰的文字或者图片</p>
</div>
<center>
<p class="setcharity" id="setcharity"></p>
</center>
<!--生成图片按钮-->
<div class="generatePicture" data-html2canvas-ignore @click="generateImage" v-show="afterCanvasImageHide">
<p class="optText" id="optText">生成海报</p>
</div>
<!--生成的图片的存放容器-->
<div class="shareImg" id="shareImg">
</div>
</div>
<div class="zz" id="zz"></div>
- 书写css
<style>
html,
body {
height: 100%;
width: 100%;
margin: 0rem;
padding: 0rem;
font-size: 16px;
}
#app {
overflow: hidden;
position: relative;
width: 100%;
}
#img{
background:#B22222;
width: 100%;
margin: 0rem;
padding: 0rem;
}
.div_qrcode{
width: 100%;
text-align: center;
}
.qrCode{
width: 36%;
margin-top: 10%;
}
.generatePicture {
z-index: 999;
width: 40%;
height: 2rem;
position: fixed;
bottom: 0.5rem;
right: 30%;
overflow: hidden;
}
.generatePicture .optText {
text-align: center;
font-size: 0.4rem;
height: 1rem;
line-height: 1rem;
width: 100%;
border-radius: 0.1rem;
color: #FFFDEF;
background-color: #B22222;
}
.paragraph_tab {
width: 100%;
margin-top: 1.8rem;
}
.paragraph_tab td {
width: 50%;
}
.setcharity {
font-size: 0.4rem;
color: #FFFDEF;
z-index: 10;
position: fixed;
top: 1rem;
bottom: 0.5rem;
display: none;
margin-left: 25%;
width: 50%;
text-align: center;
}
.shareImg {
z-index: 10;
opacity: 1;
position: absolute;
top: 2rem;
width: 85%;
height: 100%;
left: 7.5%;
}
.shareImg img {
width: 100%;
/* filter:progid:DXImageTransform.Microsoft.Shadow(color=#D0D0D0,direction=120,strength=3);
-moz-box-shadow: 0rem 0rem 1rem #999999;
-webkit-box-shadow: 0rem 0rem 1rem #999999;
box-shadow:0rem 0rem 1rem #999999; */
/*pointer-events: none;*/
}
.zz {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.7;
display: none;
z-index: 5;
display: none;
}
</style>
- js文件
<script>
var vm = new Vue({
el: '#app',
data: function() {
return {
afterCanvasImageHide: true,
showToast: false,
avatar: ''
};
},
mounted: function() {
this.$nextTick(function() {
var _this = this;
// 用base64展示html中要显示的图片(如果这个图片地址是服务端链接,图片链接需要服务端允许跨域,本地图片可以不用转base64)
// 因为直接使用服务端地址链接,canvas.toDataUrl API抛出异常:
// Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. ==> 受污染的画布不能导出
var imgUrl1 =
'http://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKVkoe7Viae4lreoZBybEywysxHlnlqplGTbaJLQI7pV8W5KMFK1DqBrNntO5O9wT0YYP9cgP6m4dA/132';
_this.img2base64(imgUrl1, 'Anonymous').then(function(res) {
_this.avatar = res;
});
});
},
methods: {
/**
* 根据 window.devicePixelRatio 获取像素比
* @returns {number}
* @constructor
*/
getDpr: function() {
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
return 1;
},
/**
* 将传入值转为整数
* @param value
* @returns {number}
*/
parseValue: function(value) {
return parseInt(value, 10);
},
// 将图片转为base64格式
img2base64: function(url, crossOrigin) {
return new Promise(resolve => {
const img = new Image();
img.onload = () => {
const c = document.createElement('canvas');
c.width = img.naturalWidth;
c.height = img.naturalHeight;
const cxt = c.getContext('2d');
cxt.drawImage(img, 0, 0);
// 得到图片的base64编码数据
resolve(c.toDataURL('image/png'));
};
// 结合合适的CORS响应头,实现在画布中使用跨域<img>元素的图像
crossOrigin && img.setAttribute('crossOrigin', crossOrigin);
img.src = url;
});
},
/**
* 生成图片
*/
generateImage: function() {
var _this = this;
document.getElementById('setcharity').style.display = "block";
document.getElementById('optText').innerText = "生成中...";
document.getElementById('optText').style.backgroundColor = "#D0D0D0";
document.getElementById('optText').style.disabled = true;
// 获取想要转换的dom节点
// var dom = document.querySelector('body');
var dom = document.getElementById('img');
var box = window.getComputedStyle(dom);
// dom节点计算后宽高
var width = _this.parseValue(box.width);
var height = _this.parseValue(box.height);
// 获取像素比
var scaleBy = _this.getDpr();
// 创建自定义的canvas元素
var canvas = document.createElement('canvas');
// 设置canvas元素属性宽高为 DOM 节点宽高 * 像素比
canvas.width = width * scaleBy;
canvas.height = height * scaleBy;
// 设置canvas css 宽高为DOM节点宽高
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
// 获取画笔
var context = canvas.getContext('2d');
// 将所有绘制内容放大像素比倍
context.scale(scaleBy, scaleBy);
// 设置需要生成的图片的大小,不限于可视区域(即可保存长图)
var w = document.getElementById('img').style.width;
var h = document.getElementById('img').style.height;
html2canvas(dom, {
allowTaint: true,
width: w,
height: h,
useCORS: true
}).then(function(canvas) {
// 将canvas转换成图片渲染到页面上
var url = canvas.toDataURL('image/png'); // base64数据
var image = new Image();
image.src = url;
document.getElementById('shareImg').appendChild(image);
document.getElementById('setcharity').innerText = "长按保存海报至相册";
document.getElementById('zz').style.display = "block";
_this.afterCanvasImageHide = false;
_this.showToast = true;
setTimeout(function() {
_this.showToast = false;
}, 1000);
});
}
}
});
</script>
疑问解答:
1. 这三个js文件好大啊,并且我还要引入其他的js,怎么能提升速度?
答:合理运用懒加载机制,用户不会一进入页面就截屏的,肯定会有一个过程,利用这个时间合理安排代码js的引入。
2. 如果遇到跨域问题怎么办?
答:这个不用担心,js中已经解决了跨域的问题,无需担心。
3. 我想一进入页面就自动截屏怎么实现?
答:如果你使用过vue的话就应该能懂,在onload事件中,将methods里面的代码转移到onlocd即可,但是需要把img2base64保留;
4. 截屏后的遮罩层不能铺满整个手机屏幕,导致底部有一些不能遮到;
答:第一个办法,引入jq是由$(function(){})事件机制,获取页面的高度,然后赋给遮罩层。第二个办法,在onload方法中获取页面高度,然后利用响应式的机制,替换遮罩层的高度;
5. 截取屏幕的图片底部会有一条细细的白线,什么问题?
答:在不同机型上截取的高度是不一样的,高度有可能不是整数,有可能是630.54,如果这样,计算机会四舍五入的取整,那个白色的细线就是四舍五入后多出来的高度。
在获取图片区域高度的时候,减一就好了。
最后附上源码地址:https://github.com/NoFindBug/poster-dome