前端项目给页面加水印,高效稳定可直接用
平时写代码不能太依赖网上现成的成果,就算有那也的自己有本事消化才行,遇到问题还是要多思考,如果一条路不通,换条路走,如果换条路还不通,那就自己踏出一条路,条条大路通罗马;最后祝愿看到该帖子的小伙子身体健康,事业顺利,从此无bug。
1、遇到的问题
在网上也有一些封装好的插件和组件,我都体验了一下,发现用起来还是有些小问题,比如我遇到的问题就是使用封装好的组件,直接在App.vue中引入使用,发现本地环境是可以正常展示,但是发布到测试环境后发现登录项目页面竟然没有水印,除非手动刷新页面,水印才能展示出来;
查询原因
我在网上找到水印组件,本地环境没问题,发布到测试环境后,发现有水印DOM结构,但是页面上不展示水印,而这个DOM是有宽高的,所以就暂时排除了DOM方面的问题;然后就怀疑是不是逻辑写错了或者是渲染机制的问题,因为之前有遇到过Echarts在DOM还没生成的时候就绘制了,这样肯定会有警告或报错,原因是代码在 DOM 元素尚未完全加载和渲染时就尝试获取其尺寸;
一般解决方法就是 1、把调用创建水印的方法放到mounted里面执行,这里DOM就生成了;
export default {
mounted() {
// 在这里执行需要获取 DOM 尺寸的代码
}
};
2、要么就是延迟执行,如果不能确定 DOM 何时完全加载,可以使用setTimeout
函数延迟执行获取 DOM 尺寸的代码,给页面一些时间来加载和渲染.
setTimeout(function() {
// 在这里执行需要获取 DOM 尺寸的代码
}, 500); // 延迟 500 毫秒执行
然而我使用了很多方法,甚至把组件代码直接放到App.vue里面,调用方法放到mounted里面,发布到测试环境发现还是不行(至今都没搞明白,有没有哪位大佬知道这个问题到底是什么原因呢);最后千钧一发之际,灵机一动,为何不尝试自己用CSS写一个水印呢?进而就有了以下的故事......
方法对比
使用插件或网上现成的组件和直接使用 CSS 样式写水印的对比:
使用插件或网上现成组件:
- 增加项目依赖:引入插件会增加项目的依赖项,可能会带来潜在的兼容性问题。如果插件停止维护或者与项目中的其他库冲突,可能会导致项目出现故障。
- 性能影响:一些复杂的插件可能会对项目的性能产生一定的影响,尤其是在处理大量数据或频繁更新的场景下。
- 学习成本:虽然使用插件相对简单,但仍然需要一定的时间来学习如何配置和使用插件,特别是对于不熟悉该插件的开发者来说。
当然优点也是有的,比如功能丰富,直接使用,不用花费太多的自己的思考时间。
使用css样式:
- 轻量级:不会引入额外的依赖,减少了项目的复杂性和潜在的兼容性问题。
- 性能较好:由于是直接使用 CSS 实现,通常不会对项目性能产生较大的影响,特别是对于小型项目或对性能要求较高的场景。
- 灵活性高:你可以根据项目的具体需求,灵活地调整 CSS 样式来实现不同的水印效果,完全掌控水印的外观和行为。
当前缺点也是有的,比如可维护性相对较差,可能对于一些复杂的水印效果,CSS写起来就不是那么方便了。
2、处理过程
经过大量考究和为了项目的稳定性,我还是决定使用手写CSS来实现水印的效果,前提是我知道我们项目的这个水印一般情况下写好了是不会变动的,也减少后期的维护。
需要思考的是,你想要一行展示多少个(取决于屏幕的宽度 / 每个水印之间的间隔),一个屏幕展示多少行(取决于屏幕的高度 / 每行水印之间的间隔),并且这个水印得根据屏幕大小来更新数量,剩下的就是一些水印本事的样式了(字体大小、颜色、旋转角度等等);最后监听window的宽高就完事了
3、最终结果
以下是以vue文件为例,可以直接使用的文件,开箱即用,无需其他封装
1、在components文件下创建waterMark.vue文件,专门用于水印的组件;
// waterMark.vue
<template>
<div class="watermark-container">
<div
class="watermark-text"
v-for="index in totalWatermarks"
:key="index"
:style="{
top: calculateTop(index),
left: calculateLeft(index),
transform: 'rotate(-30deg)',
}"
>
{{ watermarkText }}
</div>
</div>
</template>
<script>
export default {
props: {
// 外部传入的水印文本
watermarkText: {
type: String,
required: true
}
},
data () {
return {
innerWidth: null,
innerHeight: null
}
},
mounted () {
this.innerWidth = window.innerWidth
this.innerHeight = window.innerHeight
window.addEventListener('resize', this.generateWatermarks)
},
beforeDestroy () {
window.removeEventListener('resize', this.generateWatermarks)
},
computed: {
totalWatermarks () {
const minRows = 3 // 假定至少有3行水印
const widthCount = Math.ceil(this.innerWidth / 300)
const heightCount = Math.max(minRows, Math.ceil(this.innerHeight / 250))
return widthCount * heightCount
}
},
methods: {
// 计算出每个水印的top值
calculateTop (index) {
const widthCount = Math.ceil(this.innerWidth / 300) //每个水印之间的间隔
const row = Math.floor(index / widthCount)
return row * 250 + 'px'
},
// 计算出每个水印的left值
calculateLeft (index) {
const widthCount = Math.ceil(this.innerWidth / 300) //每行水印之间的间隔
return (index % widthCount) * 400 + 'px'
},
generateWatermarks () {
this.innerWidth = window.innerWidth
this.innerHeight = window.innerHeight
const watermarkContainer = this.$el.querySelector('.watermark-container')
if (watermarkContainer) {
const watermarkTexts = watermarkContainer.querySelectorAll('.watermark-text')
watermarkTexts.forEach((watermarkText, index) => {
watermarkText.style.top = this.calculateTop(index)
watermarkText.style.left = this.calculateLeft(index)
})
}
}
}
}
</script>
<style scoped>
.watermark-container {
position: fixed;
top: 70px;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
}
.watermark-text {
position: absolute;
transform: translate(-50%, -50%) rotate(-30deg); // 水印偏移量和旋转角度,这里设置的角度要和上面DOM中的角度设置一致
opacity: 0.2; // 水印透明度
color: #808184; // 字体颜色
font-size: 14px; // 字体大小
}
</style>
2、在所需要的页面直接引入使用即可
由于我的项目要求每个页面都要有水印,所以我直接用在了App.vue里面,如果你需要指定页面加水印的话,直接引入指定的页面即可
// App.vue
<template>
<div id="app">
<router-view />
<Watermark :watermarkText="watermarkText"/>
</div>
</template>
<script>
import Watermark from './components/waterMark/index.vue'
export default {
name: 'App',
components: {
TopAlert,
Watermark
},
data () {
return {
watermarkText: 这是水印文本
}
},
}
</script>
3、最后看下效果图吧
最后发布到测试和线上环境后依然没问题.
4、总结
平时写代码不能太依赖网上现成的成果,就算有那也的自己有本事消化才行,遇到问题还是要多思考,如果一条路不通,换条路走,如果换条路还不通,那就自己踏出一条路,条条大路通罗马;最后祝愿看到该帖子的小伙子身体健康,事业顺利,从此无bug。
更多推荐
所有评论(0)