在实际的开发中,我们不难遇到移动端h5的开发,各种手机的兼容,安卓与ios,华为与小米,让我们头痛不已,在移动端海报截屏之中,网上有很多的案例,但是要么不稳定,要么需要的插件太大,要么就是兼容性差。
而这套代码,是经历过生产的考验的,目前没有发现不兼容的情况,很稳定,效率也比较高。

实现移动端h5截屏

  1. 引入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>
  1. 书写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>
  1. 书写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>
  1. 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