vue + Element +avue 全局水印

1,132 阅读2分钟
  1. 在utils 创建一个watermark文件,里面包含index.js和watermark.js 两个js文件

    index.js
    
    import _waterMark from './watermark';export function dataURLtoFile (dataurl, filename) {  let arr = dataurl.split(',');  let mime = arr[0].match(/:(.*?);/)[1];  let bstr = atob(arr[1]);  let n = bstr.length;  let u8arr = new Uint8Array(n);  while (n--) {    u8arr[n] = bstr.charCodeAt(n);  }  return new File([u8arr], filename, {    type: mime  });}// 标准参数var canvas, ctx, configDefault = {  width: 200,  height: 200};let config = {  text: 'avue.top', // 文字  fontFamily: 'microsoft yahei', // 字体  color: '#999', // 颜色  fontSize: 16, // 大小  opacity: 100, // 透明度  bottom: 10, // 下边位置  right: 10, // 右边位置  ratio: 1// 压缩比};/** * 参数 {Object} opt * @param {String} text    水印文本,默认'avue商用通用无敌大水印' * @param {String} font    水印字体,默认'30px 黑体' * @param {Int} canvasWidth    单个水印容器宽度,默认500 * @param {Int} canvasHeight    单个水印容器高度,默认200 * @param {String} textAlign    水印文本对齐方式,默认'center' * @param {String} textStyle    水印文本样式,默认'rgba(100,100,100,0.15)' * @param {Int} degree    水印文本旋转角度,默认 -20 * @param return **/export const watermark = function(opt = {}) {  console.log(opt)  return new _waterMark(opt);};// 将base64转换为文件export function detailImg(file, option = {}) {  return new Promise(function(resolve, reject) {    const { text, fontFamily, color, fontSize, opacity, bottom, right, ratio } = option;    initParams();    fileToBase64(file, initImg);    // 参数初始化    function initParams() {      config.text = text || config.text;      config.fontFamily = fontFamily || config.fontFamily;      config.color = color || config.color;      config.fontSize = fontSize || config.fontSize;      config.opacity = opacity || config.opacity;      config.bottom = bottom || config.bottom;      config.right = right || config.right;      config.ratio = ratio || config.ratio;    }    // 加载图片    function initImg(data) {      var img = new Image();      img.src = data;      img.onload = function() {        var width = img.width;        var height = img.height;        cretedCanvas(width, height);        ctx.drawImage(img, 0, 0, width, height);        setText(width, height);        resolve(dataURLtoFile(document.getElementById('canvas').toDataURL(file.type, config.ratio), file.name));      };    }    // 创建画板    function cretedCanvas(width, height) {      canvas = document.getElementById('canvas');      if (canvas === null) {        canvas = document.createElement('canvas');        canvas.id = 'canvas';        canvas.className = 'avue-canvas';        document.body.appendChild(canvas);      }      ctx = canvas.getContext('2d');      canvas.width = width;      canvas.height = height;    }    // 添加水印    function setText(width, height) {      var txt = config.text;      var param = calcParam(txt, width, height);      ctx.font = param.fontSize + 'px ' + config.fontFamily;      ctx.fillStyle = config.color;      ctx.globalAlpha = config.opacity / 100;      ctx.fillText(txt, param.x, param.y);    }    // 计算比例    function calcParam(txt, width, height) {      var x, y;      // 字体的比例      var calcFontSize = config.fontSize / configDefault.width;      var fontSize = calcFontSize * width;      if (config.bottom) {        y = configDefault.height - config.bottom;      } else {        y = config.top;      }      if (config.right) {        x = configDefault.width - config.right;      } else {        x = config.left;      }      ctx.font = config.fontSize + 'px ' + config.fontFamily;      var txtWidth = Number(ctx.measureText(txt).width);      x = x - txtWidth;      var calcPosX = x / configDefault.width;      var calcPosY = y / configDefault.height;      x = calcPosX * width;      y = calcPosY * height;      return {        x: x,        y: y,        fontSize: fontSize      };    }    // file转base64    function fileToBase64(file, callback) {      var reader = new FileReader();      reader.readAsDataURL(file);      reader.onload = function(e) {        callback(e.target.result);      };    }  });}
    

    watermark.js

    export function randomId () { let chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;letmaxPos=chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; let maxPos = chars.length; let id = ''; for (let i = 0; i < 16; i++) { id += chars.charAt(Math.floor(Math.random() * maxPos)); } return id;}class waterMark { constructor(opt = {}) { this.CONTAINERID = randomId(); this.drawCanvas = this.drawCanvas.bind(this); this.parentObserver = this.parentObserver.bind(this); this.Repaint = this.Repaint.bind(this); this.isOberserve = false; this.init(opt); this.drawCanvas(); this.parentObserver(); } init(opt) { this.option = {}; this.option.text = opt.text || 'avue商用通用无敌大水印'; this.option.font = opt.font || '30px 黑体'; this.option.canvasWidth = opt.canvasWidth || 500; this.option.canvasHeight = opt.canvasHeight || 200; this.option.textAlign = opt.textAlign || 'center'; this.option.textStyle = opt.textStyle || 'rgba(100,100,100,0.15)'; this.option.degree = opt.degree || -20; } drawCanvas() { this.isOberserve = true; let divContainer = document.createElement('div'); let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); divContainer.id = this.CONTAINERID; canvas.width = this.option.canvasWidth; canvas.height = this.option.canvasHeight; context.font = this.option.font; context.textAlign = this.option.textAlign; context.fillStyle = this.option.textStyle; context.translate(canvas.width / 2, canvas.height / 2); context.rotate(this.option.degree * Math.PI / 180); context.fillText(this.option.text, 0, 0); let backgroundUrl = canvas.toDataURL('image/png'); this.styleStr = ` position:fixed; top:0; left:0; width:100%; height:100%; z-index:9999; pointer-events:none; background-repeat:repeat; background-image:url('{backgroundUrl}'); divContainer.setAttribute('style', this.styleStr); document.body.appendChild(divContainer); this.wmObserver(divContainer); this.isOberserve = false; } wmObserver(divContainer) { let wmConf = { attributes: true, childList: true, characterData: true }; let wmObserver = new MutationObserver((mo) => { if (!this.isOberserve) { let _obj = mo[0].target; _obj.setAttribute('style', this.styleStr); _obj.setAttribute('id', this.CONTAINERID); wmObserver.takeRecords(); } }); wmObserver.observe(divContainer, wmConf); } parentObserver() { let bodyObserver = new MutationObserver(() => { if (!this.isOberserve) { let __wm = document.querySelector(#{this.CONTAINERID}`); if (!__wm) { this.drawCanvas(); } else if (__wm.getAttribute('style') !== this.styleStr) { __wm.setAttribute('style', this.styleStr); } } }); bodyObserver.observe(document.querySelector(`#{this.CONTAINERID}).parentNode, { childList: true }); } Repaint(opt = {}) { this.remove(); this.init(opt); this.drawCanvas(); } remove() { this.isOberserve = true; let _wm = document.querySelector(#${this.CONTAINERID}`); _wm.parentNode.removeChild(_wm); }}export default waterMark;

2 .home.vue里使用组件

<template>  <div>    <div style="width: 400px; position: absolute; top: 200px">      <el-button @click.stop="submit" type="primary">全局水印</el-button>      <el-button @click.stop="del" type="danger">删除水印</el-button>    </div>  </div></template><script>import { watermark } from "../utils/canvas/index.js"; // 引入index.js 水印的配置文件export default {  name: "home",  data() {    return {      obj: "",      create: false,    };  },  methods: {    submit() {      if(this.create){        this.$message.success('已经创建水印了')        return      }      this.create=true;      this.$message.success('添加水印成功')
      // 可自定义 宽、高、文本、 字体、颜色、对齐方式、旋转角度等 具体可查index.js配置文件
      this.obj=watermark({text:'全局水印演示',})     },    del(){      this.obj.remove();      this.create=false;    },  },};</script><style scoped></style>

3 .演示效果