前言
开发过程中,总免不了遇坑,遇坑不要紧,填坑是紧要. 文中不会对问题有过多的解释,这里会先列出对应的解决方案,如果要解释其中缘由必定篇幅过长,且当这是一个简单的填坑指南.
填坑
Number.prototype.toFixed()
方法对保留对应小数位不正确问题?
原因可看这篇文章 toFixed四舍五入的不准确性.
注意:js 中的 Number 类型计算时存在精度缺失问题
Number 类型使用 IEEE 754 格式表示 整数 和 浮点值(在某些语言中也叫双精度值),通常在 js
中通过计算正常都会使用十进制,但实际上计算过程是 十进制 --> 转成二进制 --> 二进制进行计算 --> 转成十进制
,这时候就会有精度问题.
解决方法
既然 Number.prototype.toFixed()
方法既然存在四舍五入问题,那么最简单的就是重写这个方法:
// 重写方法
Number.prototype.toFixed = function (d) {
var s = this + '' // number -> string
if (!d) d = 0 // 参数默认值
if (s.indexOf('.') == -1) s += '.' // 格式化数字字符串,如 '100' -> '100.')
s += new Array(d + 1).join('0') //若 d = 2, 则 '100.' -> '100.00', '100.123' -> '100.12300'
if (
new RegExp('^(-|\\+)?(\\d+(\\.\\d{0,' + (d + 1) + '})?)\\d*$').test(s)
) {
var s = '0' + RegExp.$2, // $2 为匹配到完整数字,如 '100.666' -> '0100.666'
pm = RegExp.$1, // $1 正负符号
a = RegExp.$3.length, // $3 获取包含 . 即后面需要 d + 1 长度的数值
b = true
if (a == d + 2) {
// a 长度包含了 . 和 对应 d 长度的后一位
a = s.match(/\d/g) // 获取数字部分字符串
// 判断最后完整数字字符最后一位是否 > 4, 即是否需要四舍五入
if (parseInt(a[a.length - 1]) > 4) {
for (var i = a.length - 2; i >= 0; i--) {
// 倒序遍历
a[i] = parseInt(a[i]) + 1 // 进一
if (a[i] == 10) {
// 满 10 进制,本位置 0 ,前一位进一
a[i] = 0
b = i != 1 // 当前遍历是到第二位时,b = false,第一位为 0
} else break // 没满 10 直接跳出循环
}
}
// 只获取小数点前后的数字,通过 . 拼接
s = a
.join('')
.replace(new RegExp('(\\d+)(\\d{' + d + '})\\d$'), '$1.$2')
}
if (b) s = s.substr(1) // 删除首位的 0
return (pm + s).replace(/\.$/, '') // 以 . 结尾替换成空字符
}
// 不符合正则,直接转 string 返回
return this + ''
}
复制代码
window.open()
方法被浏览器拦截?
原因:浏览器出于安全考虑,不允许非用户操作情况下打开新的页面.
示例代码
<button onclick="getUrlAndOpen()">点我</button>
<script>
async function getUrlAndOpen() {
let res = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('http://www.baidu.com')
}, 500)
})
console.log("异步请求结果:", res)
window.open(res)
}
</script>
复制代码
解决方法:在调用异步请求之前先通过
window.open()
打开页面,获取这个窗口的引用,等待异步响应之后去设置新开窗口的 url
示例代码
<button onclick="getUrlAndOpen()">点我</button>
<script>
async function getUrlAndOpen() {
let newWindowReference = window.open();
let res = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('http://www.baidu.com')
}, 500)
})
console.log("异步请求结果:", res)
newWindowReference.location.href = res;
}
</script>
复制代码
<img draggable="true" />
时,在浏览器中拖拽图片时会自动下载或新开页面预览?
直接通过效果来解释:
<img id="img1" src="./img/xm.jpg" alt="xm">
复制代码
如上图所示,在不同浏览器下,对于图片、链接等元素的 draggable
属性的默认值是不同的,这就导致了它们在浏览器上进行拖拽后产生了差异,下面就以 谷歌浏览器 和 QQ 浏览器进行对比:
-
QQ 浏览器:
draggable = true
时拖拽图片,鼠标下会有图片缩影,放开鼠标后,浏览器会打开新页面并访问对应资源的url
地址 -
Google 浏览器:
draggable = true || false
都不会有上述的行为产生
问题描述
QQ 浏览器中对图片进行拖拽时,若 img
标签中是预览地址,则打开新页面后会访问这个预览地址,若当前 img
标签中是下载地址,则会询问是否需要下载这个图片资源.
解决方法
- 给普通的
img
或a
标签设置draggable="false"
,禁止拖拽行为产生 - 若当前
img
元素需要进行拖拽,即draggable="true"
,此时只能通过ondragover
事件处理程序中使用ev.preventDefault();
阻止浏览器的默认行为
下面是示例代码:
<div class="box" ondrop="drop(event)" ondragover="dragover(event)"></div>
<div class="box" ondrop="drop(event)" ondragover="dragover(event)">
<img id="img1" src="./img/xm.jpg" ondragstart="dragstart(event)" draggable="true" alt="xm">
</div>
<script>
function dragover(ev) {
ev.preventDefault();
}
function dragstart(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
复制代码