JavaScript實現(xiàn)水印效果的示例代碼
更新時間:2023年05月18日 10:33:40 作者:一個爬坑的Coder
這篇文章主要為大家詳細介紹了JavaScript如何利用canvas實現(xiàn)添加水印的效果,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學習一下
效果
實現(xiàn)思路
- 利用canvas繪制出文字
- 將canvas作為遮罩層背景圖, 將背景x軸和y軸重復
實現(xiàn)步驟
動態(tài)生成canvas并畫出文字
const canvas = document.createElement("canvas"); canvas.width = len * fontSize; // canvas寬度, 目前是根據(jù)文字長度和大小來調(diào)整的, 自己可依照具體需求變動 canvas.height = height + fontSize * 2.8; // canvas高度, 依據(jù)需求調(diào)整 const context = canvas.getContext("2d"); context.translate(0, canvas.height / 2); // 改變旋轉基點 context.rotate((-rotate * Math.PI) / 180); // 進行旋轉, 傳過來的旋轉角度 context.font = `${fontSize}px Vedana`; // 設置字體 context.fillStyle = color; // 設置文字顏色 // 將需要的文本, 繪制到canvas上面 context.fillText(text, 10, canvas.height / 2 - 100);
將canvas做為遮罩層背景圖
// 生成水印遮罩層 const div = document.createElement("div"); div.id = DOM_ID; div.style.pointerEvents = "none"; div.style.position = "fixed"; div.style.zIndex = zIndex; div.style.left = "-32%"; div.style.top = "-32%"; div.style.opacity = opacity; div.style.width = "150%"; div.style.height = "150%"; div.style.background = `url('${canvas.toDataURL("images/png")}')repeat left top`; document.body.appendChild(div);
防止篡改水印
利用MutationObserver
API來對遮罩層做監(jiān)聽, 防止屬性修改或者dom節(jié)點被人為的刪除
MDN: MutationObserver
/** * 監(jiān)聽dom變化, 防止水印被篡改 */ static observeDomChange = (waterMarkDom, options) => { const callback = (mutationsList, observer) => { for (const mutation of mutationsList) { /** * 水印節(jié)點的屬性發(fā)生了變動 */ if (mutation.target === waterMarkDom) { this.setWaterMark(); // 重新生成水印 observer.disconnect(); // 停止觀察 } /** * 強行手動刪除了水印節(jié)點 */ if (mutation.removedNodes.length && mutation.removedNodes[0] === waterMarkDom) { this.setWaterMark(this.options); // 重新生成水印 observer.disconnect(); // 停止觀察 } } }; this.observer = new MutationObserver(callback); /** 監(jiān)聽body */ this.observer.observe(document.querySelector("body"), { attributes: true, // 觀察屬性變動 childList: true, // 觀察目標子節(jié)點的變化,是否有添加或者刪除 subtree: true, // 觀察后代節(jié)點,默認為 false }); };
所有代碼
const DOM_ID = "yss-cj-create"; /** * 水印的默認屬性 */ const DEFAULT_OPTIONS = { text: "cxk 管理員 20230424", width: 520, // 水印塊的寬度 height: 280, // 水印塊的高度 rotate: 20, // 水印塊的旋轉角度 fontSize: 28, // 文字大小 color: "#666", // 文字顏色 opacity: "0.3", // 遮罩層的透明度 zIndex: "9999999999", // 遮罩層的層級 }; class Watermark { options = {}; observer = null; /** * 生成水印 */ static setWaterMark = (options = {}) => { const waterDom = document.getElementById(DOM_ID); if (waterDom !== null) { // 每次重新繪制之前, 需要判斷是否已經(jīng)存在, 如果存在了就先刪除, 再來重新繪制 document.body.removeChild(waterDom); } const latestOptions = { ...DEFAULT_OPTIONS, ...options }; this.options = latestOptions; const { text, width, // 寬度是根據(jù)提供的文字大小和文字長度計算出來的, 這里就用不上了 height, // 水印塊的高度 rotate, // 水印塊的旋轉角度 fontSize, // 文字大小 color, // 文字顏色 opacity, // 遮罩層的透明度 zIndex, // 遮罩層的層級 } = latestOptions; const len = text.length; const canvas = document.createElement("canvas"); canvas.width = len * fontSize; canvas.height = height + fontSize * 2.8; const context = canvas.getContext("2d"); context.translate(0, canvas.height / 2); context.rotate((-rotate * Math.PI) / 180); context.font = `${fontSize}px Vedana`; // 設置字體 context.fillStyle = color; // 設置文字顏色 // 將需要的文本, 繪制到canvas上面 context.fillText(text, 10, canvas.height / 2 - 100); // 生成水印遮罩層 const div = document.createElement("div"); div.id = DOM_ID; div.style.pointerEvents = "none"; div.style.position = "fixed"; div.style.zIndex = zIndex; div.style.left = "-32%"; div.style.top = "-32%"; div.style.opacity = opacity; div.style.width = "150%"; div.style.height = "150%"; div.style.background = `url('${canvas.toDataURL("images/png")}')repeat left top`; document.body.appendChild(div); /** * 監(jiān)聽水印的dom變化 */ this.observeDomChange(div); }; /** * 去除水印 */ static removeWatermark = () => { const dom = document.getElementById(DOM_ID); if (dom !== null) { document.body.removeChild(dom); } }; /** * 監(jiān)聽dom變化, 防止水印被篡改 */ static observeDomChange = (waterMarkDom, options) => { const callback = (mutationsList, observer) => { for (const mutation of mutationsList) { /** * 水印節(jié)點的屬性發(fā)生了變動 */ if (mutation.target === waterMarkDom) { this.setWaterMark(); // 重新生成水印 observer.disconnect(); // 停止觀察 } /** * 強行手動刪除了水印節(jié)點 */ if (mutation.removedNodes.length && mutation.removedNodes[0] === waterMarkDom) { this.setWaterMark(this.options); // 重新生成水印 observer.disconnect(); } } }; this.observer = new MutationObserver(callback); /** 監(jiān)聽body */ this.observer.observe(document.querySelector("body"), { attributes: true, // 觀察屬性變動 childList: true, // 觀察目標子節(jié)點的變化,是否有添加或者刪除 subtree: true, // 觀察后代節(jié)點,默認為 false }); }; } Watermark.setWaterMark();
到此這篇關于JavaScript實現(xiàn)水印效果的示例代碼的文章就介紹到這了,更多相關JavaScript水印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
初學js插入節(jié)點appendChild insertBefore使用方法
由于可見insertBefore()方法的特性是在已有的子節(jié)點前面插入新的節(jié)點但是兩種情況結合起來發(fā)現(xiàn)insertBefore()方法插入節(jié)點,是可以在子節(jié)點列表的任意位置。2011-07-07