参考 src/views/other/waterMarker/index.vue · yuanzbz/vue-admin-perfect - Gitee.com
记录使用canvas生成水印的过程以及水印样式的配置。
- 效果图
局部水印效果图
全局水印效果图
- 实现原理
生成一个canvas画布,指定水印的内容,倾斜度,颜色等样式,转成图片格式作为背景图布满容器。
- 创建waterMarker.js文件
/*
* 生成一个canvas画布,转化成图片格式,重复排列布满容器
*/
function watermark (options) {
const {
container = document.body, // 容器
width = '240', // canvas元素宽,调整水印的水平间距
height = '200', // canvas元素高, 调整水印的垂直间距
textAlign = 'left', // 文字对齐
textBaseline = 'bottom', // 基准线
font = '16px Microsoft Yahei', // 字体大小及样式
fillStyle = '#000', // 自定义水印的颜色
content = '小香菜今天吃什么', // 水印内容
globalAlpha = 0.3, // 设置图形和图像透明度的值
rotate = 16, // 文字旋转角度
zIndex = 1000, // 元素堆叠顺序
isCancel =true
} = options
const canvas = document.createElement('canvas')
canvas.setAttribute('width', width)
canvas.setAttribute('height', height)
const ctx = canvas.getContext('2d') // 获取 canvas2d 上下文
ctx.globalAlpha = globalAlpha
ctx.textAlign = textAlign
ctx.textBaseline = textBaseline
ctx.font = font
ctx.fillStyle = fillStyle
ctx.rotate((Math.PI * rotate) / 180)
ctx.fillText(content, -10, 150) // 调整水印倾斜角度时,需调整该项
const base64Url = canvas.toDataURL() // 返回一个包含图片展示的 data URI
const __wm = document.querySelector('.__yoyo__wm')// 选择器
const watermarkDiv = __wm || document.createElement('div')
const styleStr = `
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
z-index:${zIndex};
pointer-events:none;
background-repeat:repeat;
background-image:url('${base64Url}')`
watermarkDiv.setAttribute('style', styleStr)
watermarkDiv.classList.add('__yoyo__wm') // 为元素添加“__yoyo__wm”类名
container.style.position = 'relative'
container.appendChild(watermarkDiv) // 添加元素
}
export default watermark
- 使用watermark方法生成水印
<template>
<div class="waterMarker-container common-container yoyo-water-marker">
<div class="waterMarker-content-container">
<div class="waterMarker-button-container">
<div class="waterMarker-button partWaterMark" @click="setWaterMarker(1)">生成局部水印</div>
<div class="waterMarker-button globalWaterMark" @click="setWaterMarker(2)">生成全局水印</div>
<div class="waterMarker-button defaultColorWaterMark" @click="setWaterMarker(3)">生成默认颜色水印</div>
<div class="waterMarker-button targetWaterMark">
<el-input class="opacity-input" v-model="targetColor" placeholder="#e5f3fd"></el-input>
<div class="targetColor-button" @click="setWaterMarker(4)">生成指定颜色水印</div>
</div>
<div class="waterMarker-button randColorWaterMark" @click="setWaterMarker(5)">生成随机颜色水印</div>
<div class="waterMarker-button opacityWaterMark">
<el-input class="opacity-input" v-model="opacityValue"></el-input>
<div class="opacity-button" @click="setWaterMarker(6)">设置透明度</div>
</div>
<div class="waterMarker-button clearWaterMark" @click="setWaterMarker(7)">不显示水印</div>
</div>
<div class="waterMarker-config">
<el-descriptions title="配置项 " :column="1" border class="descriptions">
<el-descriptions-item label="content"> 水印内容,默认为 '小香菜今天吃什么' </el-descriptions-item>
<el-descriptions-item label="container"> 水印容器,默认生成在 document.body 下面 </el-descriptions-item>
<el-descriptions-item label="globalAlpha"> 设置图形和图像透明度的值,默认为 0.3 </el-descriptions-item>
<el-descriptions-item label="height"> 水印高度,默认为 240,该值可调整水印的垂直间距 </el-descriptions-item>
<el-descriptions-item label="width"> 水印宽度,默认为 100,该值可调整水印的水平间距 </el-descriptions-item>
<el-descriptions-item label="fillStyle"> 水印颜色,默认为 '#000' </el-descriptions-item>
<el-descriptions-item label="textAlign"> 文字对齐,默认为 'left' </el-descriptions-item>
<el-descriptions-item label="textBaseline"> 基准线,默认为 'bottom' </el-descriptions-item>
<el-descriptions-item label="rotate"> 文字旋转角度,默认为 '16' 计算方式为 (Math.PI * rotate) / 180 </el-descriptions-item>
<el-descriptions-item label="iconStyle"> 图标的样式,默认样式为 { width: "1em", height: " 1em" } </el-descriptions-item>
</el-descriptions>
</div>
</div>
</div>
</template>
<script>
import watermark from '@/utils/waterMarker.js'
import { getColor } from '@/utils/index.js'
export default {
name: 'index',
data(){
return{
opacityValue: 0.2,
selectType: 1,
options: {
rotate: -30,
globalAlpha: 0.2,
},
targetColor: '',
colorList: [],
}
},
mounted () {
this.getRandColor()
this.$nextTick(() =>{
this.setWaterMarker(1)
})
},
methods:{
// 随机生成三十种颜色
getRandColor(){
for (let i = 0; i < 30; i++) {
this.colorList.push(getColor())
}
},
// 生成随机数
getRandom(start, end) {
const differ = end - start
const random = Math.random()
return (start + differ * random).toFixed(0)
},
// 设置水印
setWaterMarker(type){
switch (type) {
case 1:
this.selectType = type
this.options.container = document.getElementsByClassName('yoyo-water-marker')[0]
watermark(this.options)
return;
case 2:
this.selectType = type
delete this.options.container
watermark(this.options)
return;
case 3:
this.options.fillStyle = '#000'
watermark(this.options)
return;
case 4:
this.options.fillStyle = this.targetColor
watermark(this.options)
return;
case 5:
this.options.fillStyle = this.colorList[this.getRandom(0, 30)]
watermark(this.options)
return;
case 6:
this.options.globalAlpha = this.opacityValue
watermark(this.options)
return;
case 7:
this.$nextTick(() => {
const wm = document.getElementsByClassName('__yoyo__wm')[0]
if (wm) {
if(this.selectType===-1){
wm.remove()
}else {
document.body.removeChild(wm)
}
}
})
}
},
}
}
</script>