# 16. 遇到的坑
- window.addEventListener('scroll', function)事件不会触发
- 事件参考
- input输入框浏览器保存密码后,初始会自动填充输入框
- font-size: 0有啥用?
- JSON.stringify路由的url参数,原始值改变的问题
- from的submit事件和button关系
- css flex布局中最右边的节点如何靠最右放置
- 给一个元素的css设置一个 超过100W PX的值后, 再获取这个值就 变成了 1+e6
- 在相同域名下的其他页面(如一个新标签或 iframe)通信,通过 StorageEvent 响应存储的变化
- vue中data函数和设置immediate的watch方法谁先执行?
- new Image请求图片加了crossOrigin = 'anonymous'照样跨域的问题。
- innerText和textContent有啥区别
# window.addEventListener('scroll', function)事件不会触发
scroll 事件不会冒泡,这个带来的影响就是,当我们去做事件委托的时候,其它的大部分事件可以在冒泡阶段的时候完成委托,而 scroll 事件必须在捕获阶段完成委托。
scroll 事件无法取消( 没有冒泡的基本都没法取消 ),scroll 回调中的 preventDefault 和 stopPropagation 都是无效的。
参考:JavaScript 中那些不会冒泡的事件 (opens new window)
removeEventListener事件时需要同样匹配冒泡true/捕获false标志。
参考:EventTarget.removeEventListener() (opens new window)
# 事件参考
https://developer.mozilla.org/zh-CN/docs/Web/Events (opens new window)
# input输入框浏览器保存密码后,初始会自动填充输入框
input框初始接受浏览器自动填充的值不会触发change事件,切换不同的填充值后才会触发。input,blur,focus会触发
# font-size: 0有啥用?
CSS 中使用 font-size: 0
的主要目的是为了消除元素之间的空格,通常是为了解决行内块元素之间因为空格而产生的间隔问题。
替代 font-size: 0
的方法有很多种,以下是一些可能的解决方案:
- 使用
display: flex
或display: grid
布局,这些布局方式不会产生元素之间的空格。 - 使用
letter-spacing
属性设置字母间距为负值,例如letter-spacing: -1em
。 - 使用
margin
和padding
属性来控制元素之间的间距。 - 使用伪元素
::before
或::after
来添加空白字符,例如content: ""
,并设置其font-size
属性为需要的值。 请注意,这些替代方案的适用性取决于具体的情况,需要根据实际情况进行选择。
# JSON.stringify路由的url参数,原始值改变的问题
var obj = {
"custid": "28521998890000000000000000003997",
"custName": "[H]Mybells\u0007 .●ΒuЪù!@$%^{\\\\r",
"custflag": 1,
}
2
3
4
5
希望将obj转为字符串。
JSON.stringify(obj); // '{"custid":"28521998890000000000000000003997","custName":"[H]Mybells\\u0007 .●ΒuЪù!@$%^{\\\\\\\\r","custflag":1}'
可以看到obj.custName和原始值不同。
obj.custName = encodeURIComponent(obj.custName); // '%5BH%5DMybells%07%20.%E2%97%8F%CE%92u%D0%AA%C3%B9!%40%24%25%5E%26%23123%5C%5Cr'
JSON.stringify(obj); // '{"custid":"28521998890000000000000000003997","custName":"%5BH%5DMybells%07%20.%E2%97%8F%CE%92u%D0%AA%C3%B9!%40%24%25%5E%26%23123%5C%5Cr","custflag":1}'
decodeURIComponent('{"custid":"28521998890000000000000000003997","custName":"%5BH%5DMybells%07%20.%E2%97%8F%CE%92u%D0%AA%C3%B9!%40%24%25%5E%26%23123%5C%5Cr","custflag":1}'); // '{"custid":"28521998890000000000000000003997","custName":"[H]Mybells\x07 .●ΒuЪù!@$%^{\\\\r","custflag":1}'
2
3
浏览器访问时会自动对url后的参数执行decodeURIComponent,保证访问后参数不会改变。
# from的submit事件和button关系
在 HTML 中,<button>
标签可以被用来提交表单数据。如果 <button>
标签没有设置 type
属性或者设置为 type="submit"
,则在点击该按钮时,会触发包含该按钮的最近的表单的 submit
事件。
这个行为是由 HTML 规范定义的,主要是为了方便用户提交表单数据。如果想要避免 <button>
标签触发 submit
事件,可以将 type
属性设置为 "button"
,或者使用 <input>
标签并设置 type="button"
。同时,也可以在 submit
事件处理函数中通过 event.preventDefault()
方法来阻止表单的默认提交行为。
<form @submit="submit">
<button type="button">不提交</button>
<button type="text">提交</button>
<button type="submit">提交</button>
</form>
2
3
4
5
# css flex布局中最右边的节点如何靠最右放置
使用CSS Flex布局,可以使用justify-content: flex-end;
将弹性容器中的所有项目都靠右对齐。如果只想将最右边的项目靠右对齐,可以将该项目的margin-left: auto;
设置为自动,这将使项目向右移动,直到它与容器的右侧对齐。
# 给一个元素的css设置一个 超过100W PX的值后, 再获取这个值就 变成了 1+e6
如果需要正确地获取一个元素的CSS属性值,即使该值超过了100W像素,可以使用getComputedStyle方法来获取。该方法返回的是一个CSSStyleDeclaration对象,其中包含了元素的所有计算样式属性,包括超过100W像素的属性值。可以通过该对象的getPropertyValue方法来获取指定属性的值,例如:
const elem = document.getElementById('my-element');
const computedStyle = window.getComputedStyle(elem);
const widthValue = computedStyle.getPropertyValue('width');
console.log(widthValue); // 输出元素的宽度值,包含单位,例如:2000000px
2
3
4
使用getComputedStyle方法获取的属性值是字符串类型,如果需要进行数值计算,可以使用parseFloat方法将字符串转换为数值类型,例如:
const widthNumber = parseFloat(widthValue);
console.log(widthNumber); // 输出元素的宽度数值,例如:2000000
2
# 在相同域名下的其他页面(如一个新标签或 iframe)通信,通过 StorageEvent 响应存储的变化
Web Storage 包含如下两种机制:
sessionStorage 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
localStorage 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。
这两种机制是通过 Window.sessionStorage 和 Window.localStorage 属性使用(更确切的说,在支持的浏览器中 Window 对象实现了 WindowLocalStorage 和 WindowSessionStorage 对象并挂在其 localStorage 和 sessionStorage 属性下)—— 调用其中任一对象会创建 Storage 对象,通过 Storage 对象,可以设置、获取和移除数据项。对于每个源(origin)sessionStorage 和 localStorage 使用不同的 Storage 对象——独立运行和控制。
无论何时,Storage 对象发生变化时(即创建/更新/删除数据项时,重复设置相同的键值不会触发该事件,Storage.clear() 方法至多触发一次该事件),StorageEvent 事件会触发。在同一个页面内发生的改变不会起作用——在相同域名下的其他页面(如一个新标签或 iframe)发生的改变才会起作用。在其他域名下的页面不能访问相同的 Storage 对象。
在事件结果页面中的 JavaScript 如下所示(可见 events.js):
window.addEventListener("storage", function (e) {
document.querySelector(".my-key").textContent = e.key;
document.querySelector(".my-old").textContent = e.oldValue;
document.querySelector(".my-new").textContent = e.newValue;
document.querySelector(".my-url").textContent = e.url;
document.querySelector(".my-storage").textContent = e.storageArea;
});
2
3
4
5
6
7
这里,我们为 window 对象添加了一个事件监听器,在当前域名相关的 Storage 对象发生改变时该事件监听器会触发。正如你在上面看到的,此事件相关的事件对象有多个属性包含了有用的信息——改变的数据项的键,改变前的旧值,改变后的新值,改变的存储对象所在的文档的 URL,以及存储对象本身。
https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
效果: https://twitter.com/nonfigurativ/status/1727322594570027343
# vue中data函数和设置immediate的watch方法谁先执行?
# new Image请求图片加了crossOrigin = 'anonymous'照样跨域的问题。
背景:点击预览图片,然后点击copy按钮,复制图片到粘贴板,报错跨域。 原因:点击预览图片会第一次请求图片,点击copy会第二次请求图片,这时浏览器会存在缓存,会走缓存header中不会携带crossOrigin = 'anonymous',导致跨域。 解决方法:加time唯一标识,不走缓存。 参考:https://juejin.cn/post/7043642128861233189
// 点击复制图片
handleCopy(imageUrl) {
this.convertImgToBase64(imageUrl || this.currentImg, async (base64Img) => {
try {
const data = await fetch(base64Img);
const blob = await data.blob();
if (navigator.clipboard) {
this.$message.success('已复制图片到剪贴板');
await navigator.clipboard.write([
// eslint-disable-next-line no-undef
new ClipboardItem({
[blob.type]: blob,
}),
]);
} else {
this.$message.error('无法复制图片到剪贴板,请在https协议下操作');
}
} catch (error) {
this.$message.error(`复制图片失败:${error}`);
}
});
},
convertImgToBase64(url, callback, outputFormat) {
let canvas = document.createElement('CANVAS');
const ctx = canvas.getContext('2d');
const img = new Image;
let retryCount = 0;
const loadImg = () => {
img.crossOrigin = 'anonymous';
// 跨域请求图片不能走缓存,否则之后请求会使用缓存导致跨域报错。加唯一标识
img.src = `${url}${url.includes('?') ? '&' : '?'}time=${new Date().valueOf()}`;
img.onload = () => {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL(outputFormat || 'image/png');
callback.call(this, dataURL);
canvas = null;
};
img.onerror = () => {
if (retryCount < 1) {
retryCount += 1;
loadImg(); // 调用加载图片的函数
} else {
// 重试一次后仍加载失败的处理
this.$message.error('图片加载失败,请重试');
}
};
};
loadImg(); // 调用加载图片的函数
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# innerText和textContent有啥区别
innerText
和 textContent
都用于获取或设置DOM节点的文本内容,但它们之间有一些区别:
innerText:
innerText
返回元素内的文本内容,不包括HTML标签。innerText
会受CSS样式的影响,只返回可见文本内容。- 当元素包含
<script>
或<style>
标签时,innerText
会返回空字符串。 innerText
是相对慢的属性,因为它会触发重排和重绘。
textContent:
textContent
返回元素内的所有文本内容,包括文本节点和注释节点,但不包括HTML标签。textContent
不受CSS样式的影响,会返回所有文本内容,包括隐藏的文本。textContent
会保留空白文本节点,而innerText
会移除空白文本节点。textContent
是更快的属性,因为它不会触发重排和重绘。
因此,根据需求选择使用 innerText
还是 textContent
。如果需要获取或设置可见文本内容,并受CSS样式影响,可以使用 innerText
。如果需要获取或设置所有文本内容,包括隐藏的文本和空白文本节点,可以使用 textContent
。