用虚拟dom写一个水印组件

先上代码

<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 更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值