第一次碰到添加水印的需求在此做个小记录,如有更好的建议还请告知。(采用的是vue3,原生JQ的写法: 区别是将获取元素的方法进行修改)
参考文章:使用JS给页面添加水印效果_tansci的博客-CSDN博客_js 加水印
let watermark_text = ref("大傻蛋子");
let watermarks = ref(null);
onMounted(() => {
watermark();
});
const Salarys = reactive(salary);
const watermark = (settings) => {
//默认设置
let defaultSettings = {
watermarl_element: "watermark-wrapper",
watermark_txt: watermark_text.value,
watermark_x: 10, //水印起始位置x轴坐标
watermark_y: 10, //水印起始位置Y轴坐标
watermark_rows: 20, //水印行数
watermark_cols: 20, //水印列数
watermark_x_space: 50, //水印x轴间隔
watermark_y_space: 50, //水印y轴间隔
watermark_color: "#ccc", //水印字体颜色
watermark_alpha: 0.5, //水印透明度
watermark_fontsize: "15px", //水印字体大小
watermark_font: "微软雅黑", //水印字体
watermark_width: 100, //水印宽度
watermark_height: 100, //水印长度
watermark_angle: 25, //水印倾斜度数
};
//采用配置项替换默认值,作用类似jquery.extend
if (settings && typeof settings === "object") {
let src = settings[0] || {};
for (key in src) {
if (
src[key] &&
defaultSettings[key] &&
src[key] === defaultSettings[key]
) {
continue;
} else if (src[key]) {
defaultSettings[key] = src[key];
}
}
}
let oTemp = document.createDocumentFragment();
let maskElement = watermarks.value;
//获取页面最大宽度
let page_width = maskElement.offsetWidth;
//获取页面最大高度
let page_height = maskElement.offsetHeight;
//水印数量自适应元素区域尺寸
defaultSettings.watermark_cols = Math.floor(
page_width /
(defaultSettings.watermark_x_space + defaultSettings.watermark_width)
);
defaultSettings.watermark_rows = Math.ceil(
page_height /
(defaultSettings.watermark_y_space + defaultSettings.watermark_height)
);
defaultSettings.watermark_x =
(page_width -
defaultSettings.watermark_cols * defaultSettings.watermark_width) /
4;
defaultSettings.watermark_y =
(page_width -
defaultSettings.watermark_cols * defaultSettings.watermark_width) /
6;
let x;
let y;
for (let i = 0; i < defaultSettings.watermark_rows; i++) {
y =
defaultSettings.watermark_y +
(defaultSettings.watermark_y_space + defaultSettings.watermark_height) *
i;
for (let j = 0; j < defaultSettings.watermark_cols; j++) {
x =
defaultSettings.watermark_x +
(defaultSettings.watermark_width + defaultSettings.watermark_x_space) *
j;
if (j % 2 == 0) {
y += 50;
} else {
y -= 50;
}
let mask_div = document.createElement("div");
mask_div.id = "mask_div" + i + j;
mask_div.className = "mask_div";
//mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));
mask_div.innerHTML = defaultSettings.watermark_txt;
//设置水印div倾斜显示
mask_div.style.webkitTransform =
"rotate(-" + defaultSettings.watermark_angle + "deg)";
mask_div.style.MozTransform =
"rotate(-" + defaultSettings.watermark_angle + "deg)";
mask_div.style.msTransform =
"rotate(-" + defaultSettings.watermark_angle + "deg)";
mask_div.style.OTransform =
"rotate(-" + defaultSettings.watermark_angle + "deg)";
mask_div.style.transform =
"rotate(-" + defaultSettings.watermark_angle + "deg)";
mask_div.style.visibility = "";
mask_div.style.position = "absolute";
mask_div.style.left = x + "px";
mask_div.style.top = y + "px";
mask_div.style.overflow = "hidden";
mask_div.style.zIndex = "1029"; // 9999
// pointer-events:none 让水印不遮挡页面的点击事件
mask_div.style.pointerEvents = "none";
// 设置边框
// 兼容IE9以下的透明度设置
mask_div.style.filter = "alpha(opacity=50)";
mask_div.style.opacity = defaultSettings.watermark_alpha;
mask_div.style.fontSize = defaultSettings.watermark_fontsize;
mask_div.style.fontFamily = defaultSettings.watermark_font;
mask_div.style.color = defaultSettings.watermark_color;
mask_div.style.textAlign = "center";
mask_div.style.width = defaultSettings.watermark_width + "px";
mask_div.style.height = defaultSettings.watermark_height + "px";
mask_div.style.display = "block";
oTemp.appendChild(mask_div);
}
}
maskElement.appendChild(oTemp);
};
二、迭代器 ES6 (Symbol.iterator)
iteration 被称为迭代,也可以称为遍历。
根据ES6的定义iteration由3个部分组成:Iterable、Iterator、IteratorResult
1. Iterable
interface Iterable {
[Symbol.iterator]() : Iterator;
}
Iterable表示的是该对象中有可以遍历的数据,且会生成一个Iterator工厂函数
2.Iterator
interface Iterator {
next() : IteratorResult;
}
可以从Iterable中构建Iterator。Iterator是一个类似游标的概念,可以通过next访问IteratorResult。
3. IteratorResult
interface IteratorResult {
value: any;
done: boolean;
}
IteratorResult是通过调用next()获取到的数据,value是值,done是判断是否遍历完成
示例:
var arr = [1,2,3,4]
var a = arr[Symbol.iterator]()
a.next() // value:1,done:false
a.next() // value:2,done:false
a.next() // value:3,done:false
a.next() // value:4,done:false
a.next() // value:undefined,done:true
Iterable对象包含:Arrays、Strings、Maps、Sets、DOMs
1.Arrays
示例:
var arr = [1,2,3,4]
var a = arr[Symbol.iterator]()
a.next() // value:1,done:false
a.next() // value:2,done:false
a.next() // value:3,done:false
a.next() // value:4,done:false
a.next() // value:undefined,done:true
更简单的方法使用for...of
for (const x of ['a', 'b']) {
console.log(x);
}
// Output:
// 'a'
// 'b'
2.Strings(基础类型的String在遍历的时候,会自动转换成为String对象)
var a = 'avcbfa'[Symbol.iterator]()
undefined
a.next()
{value: 'a', done: false}
a.next()
{value: 'v', done: false}
a.next()
{value: 'c', done: false}
a.next()
{value: 'b', done: false}
a.next()
{value: 'f', done: false}
a.next()
{value: 'a', done: false}
a.next()
{value: undefined, done: true}
a.next()
{value: undefined, done: true}
3.Maps
Maps是通过遍历entries来实现的
const map = new Map().set('a', 1).set('b', 2);
for (const pair of map) {
console.log(pair);
}
// Output:
// ['a', 1]
// ['b', 2]
JS中对于Map通常需要维护两个数组, 第一个数组存储着key,另一个数组存储着value,每次添加和删除item时,需要同时操作两个数组,导致其存在2个缺点。
(1)每次查找Map中的元素时,都需要先去遍历key数组中拿到index,再去第二个数组中通过index来查找到对应的value
(2)Map中key和value是强绑定的,即使不在使用也不会被垃圾回收机制回收。
根据以上两个缺陷引入了weakMap的概念。
weakMap中key和value并不是强绑定关系,key不在使用时就会被垃圾回收机制回收。但是weakMap并不支持key的遍历仅有增删改的功能
4.Sets
const set = new Set().add('a').add('b');
for (const x of set) {
console.log(x);
}
// Output:
// 'a'
// 'b'
也可以遍历arguments对象,也可以遍历大部分DOM对象
function printArgs() {
for (const x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');
// Output:
// 'a'
// 'b'
for (const node of document.querySelectorAll('div')) {
···
}
5. 普通对象是不可遍历的
在JS中,Array、Map、Set是普通对象中的一种特例(可遍历对象),在普通对象中是不存在Symbol.iterator这个属性所以是不可以遍历的
for (const x of {}) { // TypeError
console.log(x);
}
虽然不能直接遍历普通对象,但是我们可以通过使用objectEntries方法来遍历普通对象。
// objectEntries的实现方法
function objectEntries(obj) {
let iter = Reflect.ownKeys(obj)[Symbol.iterator]()
return {
[Symbol.iterator]() {
return this
},
next() {
let {done, value:key} = iter.next();
if (done) {
return { done: true };
}
return { value: [key, obj[key]] };
}
}
}
以下是具体的使用,也可以通过类似方法获取key,value
const obj = { first: 'Jane', last: 'Doe' };
for (const [key,value] of objectEntries(obj)) {
console.log(`{key}:{value}`);
}
// Output:
// first: Jane
// last: Doe
6.自定义iterables
function iterateOver(...args) {
let index = 0;
const iterable = {
[Symbol.iterator]() {
const iterator = {
next() {
if (index < args.length) {
return { value: args[index++] };
} else {
return { done: true };
}
}
};
return iterator;
}
}
return iterable;
}
iterateOver方法会返回一个iterable对象。在这个对象中,我们实现了Symbol.iterator为key的方法。这个方法返回一个iterator,在iterator中,我们实现了next方法。
// Using `iterateOver()`:
for (const x of iterateOver('fee', 'fi', 'fo', 'fum')) {
console.log(x);
}
// Output:
// fee
// fi
// fo
// fum
如果Symbol.iterator返回的对象是iterable本身,那么iterable也是一个iterator。
function iterateOver(...args) {
let index = 0;
const iterable = {
[Symbol.iterator]() {
return this;
},
next() {
if (index < args.length) {
return { value: args[index++] };
} else {
return { done: true };
}
},
};
return iterable;
}
这样做的好处就是,我们可以使用for-of同时遍历iterables和iterators,如下所示:
const arr = ['a', 'b'];
const iterator = arr[Symbol.iterator]();
for (const x of iterator) {
console.log(x); // a
break;
}
// Continue with same iterator:
for (const x of iterator) {
console.log(x); // b
}
8.关闭iterators
通过实现return方法,我们可以在程序中断的时候(break,return,throw)调用iterators的return。
function createIterable() {
let done = false;
const iterable = {
[Symbol.iterator]() {
return this;
},
next() {
if (!done) {
done = true;
return { done: false, value: 'a' };
} else {
return { done: true, value: undefined };
}
},
return() {
console.log('return() was called!');
},
};
return iterable;
}
for (const x of createIterable()) {
console.log(x);
break;
}
// Output:
// a
// return() was called!
、通过break来中断遍历,最终导致return方法的调用