一. 需求
公司项目需要在界面上做多种不规则纹理的镂空效果,css的mask可以实现正向遮罩,直接使用的话只会显示不规则纹理区域内的内容。目前我想要的的效果与之相反——不规则图形区域内不显示,其他区域显示。
二. 思路
于是我就想到了利用canvas,先利用canvas获取不规则纹理的像素数据,再把需要遮罩的dom元素和不规则纹理绘制到同一个canvas,根据事先获取的像数数据对不规则纹理内的不透明像素的变成透明,最后把canvas转换成base64的url,设置mask属性,大功告成。
三.准备
由于要把dom转换为canvas,使用了html2canvas,
网址:html2canvas官网
四.实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
div {
text-align: center;
background: black;
border: 2px solid #143182;
border-radius: 10px;
width: 250px;
height: 150px;
margin: 2px;
}
</style>
</head>
<body>
有遮罩的
<div></div>
没遮罩的
<div></div>
遮罩纹理<br />
<img src="sheep.png" alt="" />
<script src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
const img = document.querySelector("img");
img.onload = function(e) {
const div = document.querySelector("div");
addMask(div, img, 20, 0);
};
// 添加mask
function addMask(dom, mask, x = 0, y = 0) {
html2canvas(dom).then(canvas => {
const ctx = canvas.getContext("2d");
// 先用一个新的canvas获取图片的像素数据
const maskcvs = document.createElement("canvas"),
maskctx = maskcvs.getContext("2d");
maskcvs.width = mask.width;
maskcvs.height = mask.height;
maskctx.drawImage(mask, 0, 0);
const maskdata = maskctx.getImageData(0, 0, mask.width, mask.height);
// 再从画布上获取对应像素区域
const maskdataOnCVS = ctx.getImageData(x, y, mask.width, mask.height);
// 根据图片的像素数据把图片的不透明像素转换成透明像素
for (let i = 0, len = maskdataOnCVS.data.length; i < len; i += 4) {
if (maskdata.data[i + 3] > 0) {
maskdataOnCVS.data[i + 3] = 0;
}
}
// 把图片放回画布上
ctx.putImageData(maskdataOnCVS, x, y);
dom.style["mask"] = dom.style[
"-webkit-mask"
] = `url(${canvas.toDataURL("image/png")})`;
});
}
</script>
</body>
</html>