内容简介:最近在刷到一篇关于水印的文章,作者分享的几种实现方式,结合到自己的项目也有用到,所以将主要的前端生成策略进行了封装,以便以后项目使用。canvas 有着不错的兼容性,是一种比较可靠、成熟的可视化技术。但是它比较依赖分辨率,对文本的处理上也有着先天的不足。但是它可以很方便的将结果保存为图片,对于完成水印的需求也是非常合适的。
最近在刷到一篇关于水印的文章,作者分享的几种实现方式,结合到自己的项目也有用到,所以将主要的前端生成策略进行了封装,以便以后项目使用。
Github | NPM | DEMO
canvas 生成方式
canvas 有着不错的兼容性,是一种比较可靠、成熟的可视化技术。但是它比较依赖分辨率,对文本的处理上也有着先天的不足。但是它可以很方便的将结果保存为图片,对于完成水印的需求也是非常合适的。
为了方便使用者上手,我将所有的实现坐标都设置为top/left,以方便对x、y的设置。
export default class CanvasWay { constructor(watermark) { this.watermark = watermark const {width, height} = watermark this.canvas = document.createElement('canvas'); this.canvas.setAttribute('width', width); this.canvas.setAttribute('height', height); } render() { const {txt, x, y, width, height, font, color, fontSize, alpha, angle} = this.watermark const ctx = this.canvas.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.textBaseline = 'top'; ctx.textAlign = 'left' ctx.fillStyle = color; ctx.globalAlpha = alpha; ctx.font = `${fontSize}px ${font}` ctx.translate(x, y) ctx.rotate(Math.PI / 180 * angle); ctx.translate(-x, -y - fontSize) ctx.fillText(txt, x, y + fontSize); return this.canvas.toDataURL(); } } 复制代码
svg 生成方式
svg 与 canvas 相比浏览器兼容性几乎一致,除了几个早起的 Android 版本,这样的设备以及很难找到了,完全可以忽略。svg 使用的是 XML 的方式,不依赖分辨率,在做水印这件事上 svg 有着更好的优势。
svg 的 text 属性 x、y,是将文本左下位置定位到其坐标系的(x,y)位置,这可能和日常写 css 的定位不同,所有需要有一个 dy 值,设置其偏移量。
export default class SvgWay { constructor(watermark) { this.watermark = watermark } render() { const {txt, x, y, width, height, color, font, fontSize, alpha, angle} = this.watermark const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}px" height="${height}px"> <text x="${x}px" y="${y}px" dy="${fontSize}px" text-anchor="start" stroke="${color}" stroke-opacity="${alpha}" fill="none" transform="rotate(${angle},${x} ${y})" font-weight="100" font-size="${fontSize}" font-family="${font}" > ${txt} </text> </svg>`; return `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`; } } 复制代码
element 生成方式
使用元素生成是一种很传统的方式,在本次实践中,我并没有考虑兼容性,因为使用了 CSS3 的属性 transform 所以在ie9 以下也是不能胜任的,但是因为有这种方式的实现,我们可以根据需求在后续补充不同的浏览器 Hack,如: filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
使用这些代码,就可以完整覆盖到更多的浏览器。
import bindCSS from '../helpers/bindCSS' export default class ElementWay { constructor(watermark) { this.watermark = watermark } _createItem() { let {txt, x, y, font, color, fontSize, alpha, angle, width, height} = this.watermark const item = document.createElement('div'); bindCSS(item, { position: 'relative', width, height, flex: `0 0 ${width}px`, overflow: 'hidden', pointerEvents: 'none' }) let span = document.createElement('span'); span.innerHTML = txt bindCSS(span, { position: 'absolute', top: `${y}px`, left: `${x}px`, fontFamily: font, fontSize: `${fontSize}px`, color: color, lineHeight: 1.5, opacity: alpha, fontWeight: 400, transform: `rotate(${angle}deg)`, transformOrigin: '0 0', userSelect: 'none', whiteSpace: 'nowrap', overflow: 'hidden' }) item.appendChild(span) return item; } render() { const {width, height} = this.watermark const {clientWidth, clientHeight} = document.documentElement || document.body const column = Math.ceil(clientWidth / width) const rows = Math.ceil(clientHeight / height) const wrap = document.createElement('div'); bindCSS(wrap, { display: 'flex', flexWrap: 'wrap', width: `${width * column}px`, height: `${height * rows}px` }) for (let i = 0; i < column * rows; i++) { wrap.appendChild(this._createItem()); } return wrap; } } 复制代码
MutationObserver 元素异动监控
MutationObserver 对现代浏览的兼容性还是不错的,MutationObserver是变动观察器,字面上就可以理解这是用来观察Node(节点)变化的。MutationObserver是在DOM4规范中定义的,它的前身是MutationEvent事件,最低支持版本为 ie9 ,目前已经被弃用。
在这里我们主要观察的有三点
- 水印元素本身是否被移除
- 水印元素属性是否被篡改(display:none ...)
- 水印元素的子元素是否被移除和篡改 (主要考虑 element的实现方式 )
为了更少的触发观察者,我写了两个配置,第一个针对水印元素本身 {characterData: true, attributes: true, childList: true, subtree: true}
对所有的异动处理,第二个观察者主要对 body 下的 {childList: true}
敏感,也就是子元素的改变,在 body 观察者的回调只对有 removedNodes 这件事做出反应。
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; export const observer = (callback) => { if (!MutationObserver) return false let bodyObserver = new MutationObserver( mutationsList => mutationsList.forEach(mutation => mutation.removedNodes.forEach( _target => _target.id === _id && callback() ) ) ) bodyObserver.observe(document.body, {childList: true}); const target = document.getElementById(_id); let observer = new MutationObserver(callback); observer.observe(target, {characterData: true, attributes: true, childList: true, subtree: true}); return {bodyObserver, observer}; } 复制代码
最终 工具 调用方式
gwm.creation({ mode: 'svg', watch: false, fontSize: 13, color: '#000', font: 'sans-serif', alpha: 0.2, angle: -15 }) 复制代码
Github | NPM | DEMO
以上所述就是小编给大家介绍的《前端页面水印生成实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 浅谈前端水印
- 前端水印初探
- Python+OpenCV为图片添加中文水印与图片水印
- 工具系列--简单水印(watermark-dom)和算法水印(频域方式图片合并)实现
- 插件系列--简单水印(watermark-dom)和算法水印(频域方式图片合并)实现
- 网页水印SDK的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Algorithms Sequential & Parallel
Russ Miller、Laurence Boxer / Charles River Media / 2005-08-03 / USD 59.95
With multi-core processors replacing traditional processors and the movement to multiprocessor workstations and servers, parallel computing has moved from a specialty area to the core of computer scie......一起来看看 《Algorithms Sequential & Parallel》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
在线进制转换器
各进制数互转换器