先上代码
<template>
<div></div>
</template>
<script setup>
import { timeChange, dateChange } from './time';
import { onMounted, getCurrentInstance } from 'vue';
defineOptions({
name: 'Watermark',
inheritAttrs: false
});
const props = defineProps({
text: { type: String, default: '水印' },
time: { type: Boolean, default: true },
date: { type: Boolean, default: false }
});
let watermark_time = timeChange(new Date());
let watermark_date = dateChange(new Date());
// let watermark_date = moment(new Date()).format('YYYY-MM-DD');
// let watermark_time = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
const cb = function (mutationList, observer) {
for (const mutation of mutationList) {
if (mutation.type === 'childList') {
const { removedNodes = [] } = mutation;
// 如果监听到水印容器变化,那么就重载页面
const node = Array.prototype.find.apply(removedNodes, [
(node) => node.className === 'watermark'
]);
//如果水印被删除,重新加载页面
if (node) {
window.location.reload();
}
}
}
};
function createWaterMark() {
const angle = -20; //旋转角度
const txt = props.text; //水印文字
const canvas = document.createElement('canvas'); //创建画布
canvas.width = 280; //画布宽
canvas.height = 200; //画布高
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 280, 200); //清除画布内容
ctx.fillStyle = 'rgba(0,0,0,.5)'; //填充颜色
ctx.globalAlpha = 0.2; //透明度
ctx.font = `12px YaHei`; //字体属性
ctx.rotate((Math.PI / 180) * angle); //旋转
ctx.textAlign = 'center'; //字体居中
ctx.fillText(txt, 20, 100); //填充字体
if (props.time) {
//填充时间
ctx.fillText(watermark_time, 20, 120);
}
if (props.date && !props.time) {
//填充日期
ctx.fillText(watermark_date, 20, 120);
}
return canvas.toDataURL();
}
const watermarkDiv = document.createElement('div');
watermarkDiv.className = 'watermark';
watermarkDiv.style.backgroundImage = `url(${createWaterMark()})`;
onMounted(() => {
const app = document.querySelector('#app');
//监听Dom改变
const observer = new MutationObserver(cb);
observer.observe(app, {
attributes: true,
childList: true
});
app.appendChild(watermarkDiv);
});
</script>
<style scoped lang="less">
.watermark {
position: fixed;
width: 100%;
height: 100%;
padding: 40px 0 0 0;
top: 0;
left: 0;
bottom: 0;
right: 0;
pointer-events: none;
z-index: 9999999;
display: flex;
flex-wrap: wrap;
overflow: hidden;
}
</style>
定义了组件的基本结构,但没有实际的 DOM 元素,因为水印是通过 JavaScript 动态生成的。
在组件挂载后onMounted,首先选择页面的根元素(假设 ID 为 app),然后创建一个 MutationObserver 来监听 DOM 变化。最后,将水印元素添加到页面中。
可以说这段代码间接地利用了虚拟 DOM 的优势,尽管它主要是通过 JavaScript 动态操作 DOM 来实现水印功能。虚拟 DOM 的使用使得 Vue 能够高效地管理组件的渲染和更新,从而提升性能。
下面说下虚拟dom
简而言之就是,用JS去按照DOM结构来实现的树形结构对象,你也可以叫做DOM对象
在 DOM 中,整个文档被视为一个树,根节点是 document,每个 HTML 元素都是树中的一个节点。开发者可以使用 JavaScript 通过 DOM API 操作文档,例如添加、删除或修改节点。常用的 DOM 操作包括:
document.getElementById()
element.appendChild()
element.removeChild()
element.setAttribute()
直接操作 DOM 可能会导致性能问题,尤其是在频繁更新时,因为每次操作都可能导致浏览器重新渲染和重排。
虚拟dom的工作原理为当组件的状态或属性发生变化时,框架会生成一个新的虚拟 DOM 树。然后,它会将新的虚拟 DOM 树与旧的虚拟 DOM 树进行比较(称为“diffing”),找出需要更新的部分。最后,框架只会更新那些发生变化的真实 DOM 节点,而不是重新渲染整个树。
优点有:提高性能:通过减少对真实 DOM 的直接操作,降低了重排和重绘的次数。
简化开发:开发者可以专注于组件的状态和逻辑,框架会自动处理 DOM 更新。
718

被折叠的 条评论
为什么被折叠?



