全局自定义指令 + canvas + MutationObserver实现铺满整个元素、元素长宽变化后重新加水印、不可控制台操作dom的前端水印添加

先上代码:

1、核心代码,实现自定义水印添加及监视元素阻止用户移除水印:


/**
 * @param text  水印文字
 * @param font  水印字体
 * @param color 水印颜色
 * @param deg   水印倾斜角度,负数上坡正数下坡
 * @param gap   相邻两个水印的间距
 */

const config = {
  attributes: true, // 属性的变动
  attributeOldValue: true, // 布尔值,表示观察attributes变动时,是否需要记录变动前的属性值
  attributeFilter: ['class', 'id', 'style'], // 数组,表示需要观察的特定属性(比如['class','src']
  characterData: true, // 节点内容或节点文本的变动
  childList: true, // 子节点的变动(指新增,删除或者更改)
  subtree: true, // 布尔值,表示是否将该观察器应用于该节点的所有后代节点。
  characterDataOldValue: true // 布尔值,表示观察characterData变动时,是否需要记录变动前的值。
}

function addWaterfall(el, {
  text = '我是水印',
  font = 'bold 34px STHeiti',
  color = 'rgba(180,180,180,0.8)',
  deg = -20,
  gap = 200
}) {
  // MutationObserver监听元素阻止用户操作dom
  const ob = new MutationObserver(changeOb)
  // 开始监听
  function beginWatch() {
    ob.observe(el, config)
  }

  // 停止监听,可通过observe重新监听
  function stopWatch() {
    ob.disconnect()
  }

  // 监听回调
  function changeOb(mutationList) {
    stopWatch()
    console.log('修改了dom')
    mutationList.forEach(mutation => {
      switch (mutation.type) {
        case 'attributes':
        {
          const attr = mutation.attributeName
          if (attr === 'style') {
            mutation.target.style = mutation.oldValue
          } else if (attr === 'id') {
            mutation.target.id = mutation.oldValue
          }
        }
      }
    })
    beginWatch()
  }

  function createWaterfall() {
    // 停止监听,否则会无限循环卡死
    stopWatch()
    // 创建canvas生成base64图片
    const box_w = parseFloat(document.defaultView.getComputedStyle(el).width)
    const box_h = parseFloat(document.defaultView.getComputedStyle(el).height)
    const canvas = document.createElement('canvas')
    canvas.id = 'canvas'
    canvas.width = box_w
    canvas.height = box_h
    const ctx = canvas.getContext('2d')
    ctx.rotate((deg * Math.PI) / 180)
    ctx.font = font
    ctx.fillStyle = color
    // ctx.textAlign = 'left'
    ctx.textBaseline = 'middle'
    // 暴力渲染,在最多的行数或列数的基础上前后各多渲染二分之根号二的数量
    const MAX_NUM = parseInt(Math.max(box_w, box_h) / gap) + 1
    const LEFT = Math.floor(MAX_NUM / Math.sqrt(2) * -1)
    const RIGHT = Math.ceil(MAX_NUM + MAX_NUM / Math.sqrt(2))
    console.log(LEFT, RIGHT)
    for (let i = LEFT; i <= RIGHT; i++) {
      for (let j = LEFT; j <= RIGHT; j++) {
        ctx.fillText(text, gap * i, gap * j)
      }
    }
    el.style.background = `url(${canvas.toDataURL('image/png')})`
    // 继续监听
    beginWatch()
  }

  return createWaterfall
}

export default addWaterfall

2、全局自定义指令

// 全局自定义指令  waterfall
Vue.directive('waterfall', {
  inserted(el, binding) {
    let width = ''
    let height = ''
    const createWaterfall = addWaterfall(el, binding.value)
    // 监听元素宽高发生改变,重新渲染水印
    function resize() {
      const style = document.defaultView.getComputedStyle(el)
      if (width !== style.width || height !== style.height) {
        console.log('resize')
        createWaterfall()
      }
      width = style.width
      height = style.height
    }
    resize()
    el.__VueSetInterval = setInterval(resize, 300)
  },
  unbind(el) {
    clearTimeout(el.__VueSetInterval)
  }
})

3、自定义指令的使用

<div v-waterfall="{
    text: '我是水印', // 各种水印相关的配置
}">
    <span v-for="item in 50" :key="item" class="PdR50" style="line-height: 34px;"> 文本内容文本内容文本内容文本内容文本内容文本内容    </span>
</div>

4、效果展示,元素大小变化后会重新加水印,审查元素也无法去除水印

相关技术的链接:

MutationObserver使用文档

作为前端你还不懂MutationObserver?那Out了

canvas参考手册

vue2自定义指令

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值