代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.bg {
position: relative;
width: 400px;
height: 400px;
background: url(./img/1.jpg); /* 自己选一个图片 */
box-sizing: border-box;
}
.mask {
position: absolute;
width: 100px;
height: 100px;
border: solid rgba(255, 255, 255, 0.3);
}
.inner {
position: relative;
width: 100%;
height: 100%;
border: 1px dashed #8c8371;
cursor: pointer;
box-sizing: border-box;
}
#preview-img {
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div class="bg">
<!-- 通过设置border颜色及宽度实现中间镂空效果 -->
<!-- 默认设置内部中心为镂空区域,长宽为100px,故默认border-width为150px -->
<!-- 必须通过style设置,方便后续js覆盖 -->
<div class="mask" style="border-width: 150px;">
<!-- 设置内部容器,宽高自动,需要根据此容器大小位置获取区域截图 -->
<div class="inner"></div>
</div>
</div>
<img id="preview-img" src="" alt="" />
<script>
const dom = document.querySelector('.mask')
const innerDom = document.querySelector('.inner')
// 通过canvas根据inner的大小位置制作截图
function takeScreenshot(element) {
// 通过promise方便返回最终结果
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// 读取图片文件并绘制进canvas
const image = new Image()
// 设置图片路径,需与待截取图片为同一个
image.src = './img/1.jpg'
// 设置canvas大小与div相同
canvas.width = element.offsetWidth
canvas.height = element.offsetHeight
// 将div区域的屏幕内容绘制到canvas上
var rect = element.getBoundingClientRect()
image.onload = () => { // 使用promise返回的原因
ctx.drawImage(
image,
rect.left,
rect.top,
canvas.width,
canvas.height,
0,
0,
canvas.width,
canvas.height
)
// 将canvas转换为Base64图片
var imgData = canvas.toDataURL('image/png')
resolve(imgData)
}
})
}
function mousedownFunc(e) {
// mask的宽高
const ow = 400
const oh = 400
// inner的宽高
const iw = 100
const ih = 100
// 判断鼠标按住时是否在inner内
if (e.target.className === 'inner') {
// 获取此时鼠标位置
let oX = e.screenX
let oY = e.screenY
// 根据鼠标移动路径及距离处理inner的移动效果
const mousemoveFunc = (ce) => {
let mX = ce.screenX
let mY = ce.screenY
const dX = oX - mX
const dY = oY - mY
// 每次移动同步上次鼠标位置,方便差值计算
oX = mX
oY = mY
const {
// 获取mask的border左上宽度,右下宽度根据左上宽度进行动态计算
// 计算方式为mask宽度减去移动距离再减去inner本身的宽度
borderTopWidth: t, borderLeftWidth: l
} = dom.style
// 因为取到的值是带px的,强制转化number类型
const [nT, nL] = [Number(parseInt(t)), Number(parseInt(l))]
let bl, bt
bl = nL - dX
bt = nT - dY
// 边缘判断,防止超出底部范围
bl = bl < 0 ? 0 : bl > ow - iw ? ow - iw : bl
bt = bt < 0 ? 0 : bt > oh - ih ? oh - ih : bt
// 计算右下border宽度
br = ow - iw - bl
bb = oh - ih - bt
// 赋值
dom.setAttribute('style', `
border-top-width: ${bt}px;
border-left-width: ${bl}px;
border-right-width: ${br}px;
border-bottom-width: ${bb}px;
`)
}
// 鼠标抬起后触发截图事件,同时回收内存
const clearListener = async () => {
let src = await takeScreenshot(innerDom)
document.getElementById('preview-img').setAttribute('src', src)
document.removeEventListener('mousemove', mousemoveFunc)
document.removeEventListener('mouseup', clearListener)
}
document.addEventListener('mousemove', mousemoveFunc)
document.addEventListener('mouseup', clearListener)
}
}
document.addEventListener('mousedown', mousedownFunc)
</script>
</body>
</html>
演示
懒得搞img标签的默认图片了,不是出错,就是src为空
同步显示为透明框选区域