页面添加水印

vue2项目使用自定义指令给页面添加水印
在这里插入图片描述

1、在util文件夹下创建waterMarker文件夹,在waterMarker文件夹下创建index.js,js文件内容如下

const globalCanvas = document.createElement('canvas')
const globalWaterMark = document.createElement('div')
let waterMarkObserver = null
let waterMarkStyle = ''

// 定义指令配置项
export default {
  // 初始化设置
  bind (el, binding, vnode) {
    binding.def?.init(el, binding)
  },
  // 元素插入父元素时调用
  inserted (el, binding, vnode) {
  },
  // 组件更新时调用
  update (el, binding, vnode) {
  },
  // 组件及子组件更新后调用
  componentUpdated (el, binding, vnode) {
  },
  // 解绑时调用
  unbind (el, binding, vnode) {
    // 停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器
    waterMarkObserver && waterMarkObserver.disconnect()
  },
  /**
   * 初始化水印
   * @param el
   * @param binding
   */
  init (el, binding) {
    // 设置水印
    binding.def?.setWaterMark(el, binding) || binding.dir?.setWaterMark(el, binding)
    // 启动监控
    binding.def?.createObserver(el, binding) || binding.dir?.createObserver(el, binding)
  },
  /**
   * 默认配置
   * @returns {{fontFamily: string, color: string, size: number, text: string}}
   */
  defaultOptions () {
    return {
      // 水印文字
      text: '默认水印',
      // 水印文字颜色
      color: 'rgba(150, 150, 150, 0.3)',
      // 水印字体大小
      size: 14,
      // 水印字体类型
      // fontFamily: 'Arial'
      height: '8000px'
    }
  },
  /**
   * 水印容器class名
   * @returns {string}
   */
  waterMarkName () {
    return 'kms-water-mark'
  },
  /**
   * 水印容器样式
   * @returns {string}
   */
  waterMarkStyle (height) {
    const style = {
      'display': 'block',
      'overflow': 'hidden',
      'position': 'absolute',
      'left': '0px',
      'top': '0px',
      'z-index': 100000,
      'font-size': '12px',
      'background-repeat': 'repeat',
      'background-position': 'center',
      'pointer-events': 'none',
      'width': '100%',
      'height': height || '8000px'
    }
    const styleArr = Object.keys(style).map((key) => {
      return `${key}:${style[key]}`
    })
    return styleArr.join(';') + ';'
  },
  /**
   * 设置水印
   * @param el
   * @param binding
   */
  setWaterMark (el, binding) {
    const parentEl = el
    // const { width, height } = parentEl?.getBoundingClientRect()
    // 拼接配置
    let defaultOptions = binding.def?.defaultOptions() || binding.dir?.defaultOptions()
    if (Object.prototype.toString.call(binding.value) === '[object Object]') {
      defaultOptions = Object.assign(defaultOptions, {
        text: binding.value.text || defaultOptions.text,
        color: binding.value.color || defaultOptions.color,
        size: binding.value?.size?.toString().replace('px', '') || defaultOptions.size,
        fontFamily: binding.value.fontFamily || defaultOptions.fontFamily
      })
    }
    // 获取对应的 canvas 画布相关的 base64 url
    const url = binding.def?.getDataUrl(defaultOptions) || binding.dir?.getDataUrl(defaultOptions)
    // 创建 waterMark 父元素
    const waterMark = globalWaterMark || document.createElement('div')
    waterMark.className = binding.def?.waterMarkName() || binding.dir?.waterMarkName() // 方便自定义展示结果
    waterMarkStyle = `${binding.def?.waterMarkStyle(binding.value.height) || binding.dir?.waterMarkStyle(binding.value.height)};background-image: url(${url})`
    waterMark.setAttribute('style', waterMarkStyle)
    // 如果父元素有自己的stayle 则获取后和自定义的拼接,并避免重复添加
    let currStyle = parentEl?.getAttribute('style') ? parentEl?.getAttribute('style') : ''
    currStyle = currStyle?.includes('position: relative') ? currStyle : currStyle + 'position: relative;'
    // 将对应图片的父容器作为定位元素
    parentEl?.setAttribute('style', currStyle)
    // 将图片元素移动到 waterMark 中
    parentEl?.appendChild(waterMark)
  },
  /**
   * 生成水印图片,返回一个包含图片展示的数据 URL
   * @param options
   * @returns {string} 水印图片:base64-url
   */
  getDataUrl (options) {
    const { text, size, fontFamily, color } = options
    const rotate = -20
    const canvas = globalCanvas || document.createElement('canvas')
    const ctx = canvas.getContext('2d') // 获取canvas画布的绘图环境
    canvas.width = 250 // 单个水印大小,宽度
    canvas.height = 150 // 高度

    ctx.fillStyle = 'rgba(0, 0, 0, 0)' // 背景填充色
    ctx.fillRect(0, 0, 300, 150) // 填充区域大小

    ctx.save()
    ctx.font = `${size}px ${fontFamily}` // 文字字体大小
    ctx.fillStyle = color // 文字颜色
    ctx.translate((300) / 2, (150) / 2) // 平移,旋转的中心点
    ctx?.rotate((rotate * Math.PI) / 360) // 水印旋转角度
    ctx.textBaseline = 'middle' // 垂直居中
    ctx.textAlign = 'center' // 水平居中
    ctx?.fillText(text, 0, 0)
    ctx.restore()
    ctx.clip()
    return canvas.toDataURL('image/png')
  },
  /**
   * 添加观察者,监听DOM变化,用 MutationObserver 对水印元素进行监听,删除、属性变化时,再立即生成一个水印元素
   * @param el
   * @param binding
   */
  createObserver (el, binding) {
    const className = binding.def?.waterMarkName() || binding.dir?.waterMarkName()
    const waterMarkEl = el.querySelector(`.${className}`)
    waterMarkObserver = new MutationObserver((mutationsList) => {
      if (mutationsList.length) {
        const { removedNodes, type, target } = mutationsList[0]
        const currStyle = waterMarkEl?.getAttribute('style')
        // 证明被删除了
        if (removedNodes[0] === waterMarkEl) {
          // 停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器
          waterMarkObserver.disconnect()
          // 重新初始化(设置水印,启动监控)
          binding.def?.init(el, binding) || binding.dir?.init(el, binding)
        } else if (type === 'attributes' && target === waterMarkEl && currStyle !== waterMarkStyle) {
          waterMarkEl.setAttribute('style', waterMarkStyle)
        }
      }
    })
    waterMarkObserver.observe(el, { attributes: true, childList: true, subtree: true, attributeOldValue: true })
  }
}

2、在main.js中引入
import watermarkDirective from ‘./util/waterMarker/index’

Vue.use(watermarkDirective)

3、在页面中使用自定义指令
在这里插入图片描述
目前还存在的问题:在waterMarkStyle方法里面,高没有设置100% 。而是设置了一个8000px或者是在使用的时候传入高,因为页面是可以滚动的,设置100%页面滚动的时候不会给页面自动添加上水印,这里还没搞明白。。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值