这是我参与新手入门的第 1 篇文章
图片懒加载
前置知识
大多数 JavaScript 处理的是以下坐标系其中一种:
- 相对于窗口:类似于
position: fixed
,从 窗口 的顶部和两侧计算得出,用clientX
/clientY
表示 - 相对于文档:类似于
position: absolute
,从 文档 的顶部和两侧计算得出,用pageX
/pageY
表示
元素坐标
ele.getBoundingClientRect()
获取窗口坐标,ele
是 DOMRect
对象,具有如下属性:
x
/y
是 矩形原点 相对于 窗口 的坐标width
/height
是矩形的宽高top
/bottom
是顶部/底部矩形边缘的 Y 坐标left
/right
是左/右矩形边缘的 X 坐标
从图中可以得出:
left = x
top = y
right = x + width
bottom = y + height
为什么需要 top
/ left
这种看起来重复的属性?
原点不一定是矩形的左上角,当原点变成例如右下角的时候 left !== x
,top !== y
width
和 height
从右下角开始「增长」,也就变成了负值
IE
不支持 x
/ y
可以自己写一个 polyfill
(在 DomRect.prototype
中添加一个 getter
),或者使用 left
/ top
坐标的 right
/ bottom
与 CSS position
属性不同
相对于窗口(window)的坐标和 CSS position:fixed 之间有明显的相似之处。
但是在 CSS 定位中,right 属性表示距右边缘的距离,而 bottom 属性表示距下边缘的距离。
如果我们再看一下上面的图片,我们可以看到在 JavaScript 中并非如此。窗口的所有坐标都从左上角开始计数,包括这些坐标。
但是我目前不是很理解
文档坐标
获取文档坐标的方式:
pageY
=clientY
+ 文档的垂直滚动出的部分的高度pageX
=clientX
+ 文档的水平滚动出的部分的宽度
function getCoords(ele) {
let rect = ele.getBoundingClientRect()
return {
top: rect.top + window.pageYOffset,
right: rect.right + window.pageXOffset,
bottom: rect.bottom + window.pageYOffset,
left: rect.left + window.pageXOffset
}
}
复制代码
图片懒加载代码
rect.top
是相对于当前窗口 上边 的数值,也就是说当图片在文档的下方时 rect.top > window.innerHeight
,只有当图片经过视窗时才会 rect.top <= window.innerHeight
let img_list = [...document.querySelectorAll('img')]
const num = img_list.length
/**
* 图片懒加载
*/
const img_lazy_load = (() => {
let cnt = 0
return () => {
let deleteIndexList = []
img_list.forEach((img, index) => {
let rect = img.getBoundingClientRect()
console.log(rect.top, window.innerHeight)
if (rect.top < window.innerHeight) {
img.src = img.dataset.src
deleteIndexList.push(index)
cnt++
if (cnt === num) {
document.removeEventListener('scroll', img_lazy_load)
}
}
})
img_list = img_list.filter((_, index) => !deleteIndexList.includes(index))
}
})()
document.addEventListener('scroll', img_lazy_load)
复制代码
数据类型判断
typeof
可以正确识别:
- undefined
- boolean
- number
- string
- symbol
- function
但是对于别的类型都会识别成 object
,利用 Object.prototype.toString
来正确判断类型,截取 [object xxxxx]
中 object
后边到 ]
的文本并且统一转小写:
const type_of = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
type_of(new Date()) // date
type_of({}) // object
type_of(null) // null
type_of([]) // array
复制代码
数组去重
es5,利用 filter
判断当前元素是否是第一次出现在数组中:
const unique = (arr: any[]) => {
return arr.filter((item, index, arr) => arr.indexOf(item) === index)
}
复制代码
es6,使用 Set
数据结构自动去重:
const unique_es6 = (arr) => [...new Set(arr)]
复制代码
不使用 Set
,用空间换时间,模拟 Map
存键值对,时间复杂度 O(n):
const get_type_and_val = (obj) => {
if (typeof obj === 'object' && obj) {
return Object.prototype.toString.call(obj) + JSON.stringify(obj)
}
return Object.prototype.toString.call(obj) + obj.toString()
}
const unique_on = (arr: any[]) => {
const temp = {}
const result = []
for (const item of arr) {
const key = get_type_and_val(item)
if (!temp.hasOwnProperty(key)) {
result.push(item)
temp[key] = true
}
}
return result
}
复制代码
字符串反转
主要利用数组的 join()
方法,反向遍历,最后一种采用 es6 解构
const reverse_1 = (str: string) => str.split('').reverse().join('')
const reverse_2 = (str: string) => {
let result = ''
const len = str.length
for (let i = len - 1; i >= 0; i--) {
result += str[i]
}
return result
}
const reverse_3 = (str: string) => {
const result = []
const len = str.length
for (let i = len - 1; i >= 0; i--) {
result.push(str[i])
}
return result.join('')
}
const reverse_4 = (str: string) => {
const result = str.split('')
const len = str.length
for (let i = 0; i < len >> 1; i++) {
[result[i], result[len - i - 1]] = [result[len - i - 1], result[i]]
}
return result.join('')
}
复制代码
数组扁平化
将数组拍平成一层,并且添加参数控制拍平层数更加符合设计
[1, [2], [3, [4]]].flat(1) // [ 1, 2, 3, [ 4 ] ]
[1, [2], [3, [4]]].flat(2) // [ 1, 2, 3, 4 ]
const flat_es6 = (arr: any[], depth?: number) => {
if (depth) {
for (let i = 0; i < depth; i++) {
if (!arr.some((item) => Array.isArray(item))) break
arr = [].concat(...arr)
}
} else {
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr)
}
}
return arr
}
复制代码
写在最后
这是我发布的第一篇文章,但其实它已经躺在我的草稿箱里很久了,我一直纠结于是否应该发这种前辈称作「水文」的文章,但其实它也是我技术成长的一部分,同时也是我准备秋招必经的道路,借此掘金的活动我发布了它,也希望大佬们能给些意见,我最近正在学习 Dart
和 Flutter
,应该会记录下来我学习的心路历程,敬请期待。