# js-utils **Repository Path**: letttx/js-utils ## Basic Information - **Project Name**: js-utils - **Description**: 常用的js工具或者方法 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-07-03 - **Last Updated**: 2021-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 说明 本项目源自 ,补全了文档、修复了部分报错代码并加入了注释,也新增了一些个人写的工具、和方法,日后会继续维护该项目,欢迎issue和star。 # 目录 > [一、数组](#一、数组) >> [multArray二维数组转换](#multArray二维数组转换) >> [flatten扁平化数组](#flatten扁平化数组) >> [flattenDeep指定层级扁平化数组](#flattenDeep指定层级扁平化数组) >> [isArrayEqual检查两个数组各项相等](#isArrayEqual检查两个数组各项相等) >> [allEqual检查数组各项相等](#allEqual检查数组各项相等) >> [diffArray具有唯一array值的数组](#diffArray具有唯一array值的数组) >> [haveArr具有共同array值的数组](#haveArr具有共同array值的数组) >> [uniqueArray数组去重](#uniqueArray数组去重) >> [uniqueArrayObject数组对象去重](#uniqueArrayObject数组对象去重) >> [treeData生成树结构数据](#treeData生成树结构数据) >> [ascArr数组升序](#ascArr数组升序) >> [descArr数组降序](#descArr数组降序) >> [shuffle随机排序](#shuffle随机排序) >> [takeArray截取数组开始指定的元素](#takeArray截取数组开始指定的元素) >> [takeLastArray截取数组最后指定的元素](#takeLastArray截取数组最后指定的元素) >> [cloneArray克隆数组](#cloneArray克隆数组) >> [maxArray数组中最大值](#maxArray数组中最大值) >> [validArray去除数组中的无效值](#validArray去除数组中的无效值) > [二、对象](#二、对象) >> [isObjectEqual检查两个对象各项值相等](#isObjectEqual检查两个对象各项值相等) >> [cloneObject克隆对象](#cloneObject克隆对象) > [三、函数](#三、函数) >> [debounce函数防抖](#debounce函数防抖) >> [throttle函数节流](#throttle函数节流) >> [typeFn类型判断](#typeFn类型判断) >> [calcFn加减乘除运算](#calcFn加减乘除运算) >[四、字符串](#四、字符串) >> [isNil值是否是null或undefined](#isNil值是否是null或undefined) >> [padStart遮住字符串](#padStart遮住字符串) >> [thousands数字每隔三位数加分号](#thousands数字每隔三位数加分号) >> [toHump下划线转驼峰](#toHump下划线转驼峰) >> [toLine驼峰转下划线](#toLine驼峰转下划线) >> [firstUpperHump下划线转首字母大写的驼峰](#firstUpperHump下划线转首字母大写的驼峰) > [五、数字](#五、数字) >> [randomNumber指定范围的随机整数](#randomNumber指定范围的随机整数) >> [average求平均值](#average求平均值) >> [averageBy检查数组对象各项相等](#averageBy检查数组对象各项相等) >> [aboutEqual两个值是否约等于](#aboutEqual两个值是否约等于) >> [getLineSize计算两点之间的距离](#getLineSize计算两点之间的距离) >> [sum数组中值总和](#sum数组中值总和) > [六、浏览器](#六、浏览器) >> [copyTextH5复制文本](#copyTextH5复制文本) >> [getCurrentURL获取当前的URL地址](#getCurrentURL获取当前的URL地址) >> [scrollToTop返回顶部](#scrollToTop返回顶部) >> [smoothScroll平滑滚动页面](#smoothScroll平滑滚动页面) >> [isCurrentPage是否是当前页面](#isCurrentPage是否是当前页面) ## 一、数组 ## multArray二维数组转换 将数组(array)拆分成多个子数组,并将这些子数组组成一个新数组。 multArray(array, count) > 参数 array需要处理的数组 count = 8子数组需要的长度 > 示例 multArray([1, 2, 3, 4, 5, 6, 7], 2) => [[1, 2], [3, 4], [5, 6], [7]] multArray(['a', 'b', 'c', 'd'], 3) => [['a', 'b', 'c'], ['d']] > 源码 function multArray(arr, count = 8) { let pages = [] arr.forEach((item, index) => { const page = Math.floor(index / count) if (!pages[page]) pages[page] = [] pages[page].push(item) }) return pages } ## flatten扁平化数组 将多层嵌套数组(array)拆分成一个数组 flatten(array) > 参数 array多层嵌套数组 > 示例 flatten([1, [2], [3], [4, 5]]) // [1, 2, 3, 4, 5] > 源码 // 扁平化 Map 方法 const flatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? flatten(v) : v))) // 扁平化 reduce 方法 const flatten = arr => arr.reduce((a, c) => a.concat(Array.isArray(c) ? flatten(c) : c), []) flattenDeep指定层级扁平化数组 将多层嵌套数组(array)拆分成指定层级数组 ## flattenDeep(array, depth) > 参数 array多层嵌套数组 2.depth = 1 减少的嵌套层级数 > 示例 flattenDeep([1, [2, [3, [4]], 5]], 1) // => [1, 2, [3, [4]], 5] // ES6方法 `flat(depth)` ;[1, [2, [3, [4]], 5]].flat(1) // => [1, 2, [3, [4]], 5] > 源码 const flattenDeep = (arr, depth = 1) => arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []) ## isArrayEqual检查两个数组各项相等 比较两个数组内的各项值是否相等,返回一个Boolean值 isArrayEqual(array, array) > 参数 array 要检查的数组 array 要检查的数组 > 示例 isArrayEqual([6, 5, 2, 4, 1, 3], [1, 2, 3, 4, 5, 6]) // => true isArrayEqual([6, 5, 2, 7, 1, 3], [1, 2, 3, 4, 5, 6]) // => false > 源码 const isArrayEqual = (a, b, has = true) => { if (a.length !== b.length) return (has = false) const s = new Set(b) if (a.find(x => !s.has(x))) return (has = false) return has } ## allEqual检查数组各项相等 allEqual(array) > 参数 array 要检查的数组 > 示例 allEqual([1, 2, 3, 4, 5, 6]) // => false allEqual([1, 1, 1, 1]) // => true > 源码 const allEqual = arr => arr.every(val => val === arr[0]) ## diffArray具有唯一array值的数组 创建一个具有唯一 array 值的数组,每个值不包含在其他给定的数组中 diffArray(array, array2) > 参数 array 要检查的数组 array2 要排除的数组 > 示例 diffArray([1, 2, 6, 7], [1, 2, 9, 5]) // => [ 6, 7 ] > 源码 const diffArray = (a, b) => { const s = new Set(b) let arr = a.filter(x => !s.has(x)) return arr } ## haveArr具有共同array值的数组 创建一个具有共同 array 值的数组,每个值包含在其他给定的数组中 haveArr(array, array2) > 参数 array 要检查的数组 array2要包含的数组 > 示例 haveArr([1, 2, 6, 7], [1, 2, 9, 5]) // => [ 1, 2 ] > 源码 const haveArr = (a, b) => { const s = new Set(b) return a.filter(x => s.has(x)) } // ES6 includes const haveArr = (arr, values) => arr.filter(v => values.includes(v)) uniqueArray数组去重 创建一个去重后的 array 数组副本 ## uniqueArray(array) > 参数 array 要去重的数组 > 示例 uniqueArray([1, 2, 2, 3, 4, 4, 5]) // => [ 1, 2, 3, 4, 5 ] > 源码 const uniqueArray = (...arr) => [...new Set(arr)] const uniqueArray = (...arr) => Array.from(new Set(arr)) ## uniqueArrayObject数组对象去重 创建一个去重后的 array 数组对象副本 uniqueArrayObject(array) > 参数 array 要去重的数组 key 要去重的对象属性值 > 示例 const responseList = [ { id: 1, a: 1 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, ] uniqueArrayObject(responseList, 'id') // => [ { id: 1, a: 1 }, { id: 2, a: 2 }, { id: 3, a: 3 } ] > 源码 const uniqueArrayObject = (arr, key) => { return arr.reduce((acc, cur) => { const ids = acc.map(item => item[key]) return ids.includes(cur[key]) ? acc : [...acc, cur] }, []) } ## treeData生成树结构数据 该函数传入一个数组, 每项id对应其父级数据parent_id,返回一个树结构数组 treeData(array, id, parent_id) > 参数 array 要生成树结构的数组 id 自定义属性名 parent_id 父级自定义属性名 > 示例 const comments = [ { id: 1, parent_id: null }, { id: 2, parent_id: 1 }, { id: 3, parent_id: 1 }, { id: 4, parent_id: 2 }, { id: 5, parent_id: 4 }, ] treeData(comments) // => [ { id: 1, parent_id: null, children: [ [Object], [Object] ] } ] > 源码 const treeData = (arr, id = null, link = 'parent_id') => arr.filter(item => item[link] === id).map(item => ({ ...item, children: treeData(arr, item.id) })) ## ascArr数组升序 返回升序后的新数组 sort()方法会改变原数组,默认按 unicode 码顺序排列 ascArr(array) > 参数 array 要检查的排序数组 > 示例 ascArr([3, 2, 3, 4, 1]) // => [ 1, 2, 3, 3, 4 ] > 源码 // 通过ES6 ...展开运算符浅拷贝一份新数组 const ascArr = arr => [...arr].sort((a, b) => a - b) ## descArr数组降序 返回降序后的新数组 descArr(array) > 参数 array 要检查的排序数组 > 示例 descArr([3, 2, 3, 4, 1]) // => [ 1, 2, 3, 3, 4 ] > 源码 const descArr = arr => [...arr].sort((a, b) => b - a) ## shuffle随机排序 使用Fisher-Yates算法随机排序数组的元素 shuffle(array) > 参数 array 要随机的数组 > 示例 ```javascript shuffle([2, 3, 1]) // => [3, 1, 2] ``` > 源码 ```javascript const shuffle = ([...arr]) => { let m = arr.length while (m) { const i = Math.floor(Math.random() * m--) ;[arr[m], arr[i]] = [arr[i], arr[m]] } return arr } ``` ## takeArray截取数组开始指定的元素 从 array 数组的最开始一个元素开始提取 n 个元素takeArray(array, n) > 参数 array 要检索的数组。 n=1要提取的元素n个数。 > 示例 ```javascript takeArray([2, 3, 1], 2) // => [2, 3] ``` > 源码 ```javascript const takeArray = (arr, n = 1) => arr.slice(0, n) ``` ## takeLastArray截取数组最后指定的元素 从 array 数组的最后一个元素开始提取 n 个元素 takeLastArray(array, n) > 参数 array要检索的数组。 n=1要提取的元素n个数。 > 示例 ```javascript takeArray([2, 3, 1], 2) // => [3, 1] ``` > 源码 ```javascript const takeLastArray = (arr, n = 1) => arr.slice(0, -n) ``` ## cloneArray克隆数组 浅拷贝一份数组副本 cloneArray(array) > 参数 array要复制的数组 > 示例 ```javascript cloneArray([1, 24]) // => [1, 24] ``` > 源码 ```javascript // ES6 ... const cloneArray = arr => [...arr] // ES6 Array.from const cloneArray = arr => Array.from(arr) // concat() const cloneArray = arr => [].concat(arr) // map() const cloneArray = arr => arr.map(x => x) cloneArray([1, 24]) // [1, 24] ``` ## maxArray数组中最大值 过滤原数组中所有的非假值元素,返回数组中的最大值 maxArray(array) > 参数 array 待处理的数组 > 示例 ```javascript maxArray([0, -1, -2, -3, false]) // => 0 ``` > 源码 ```javascript const maxArray = arr => Math.max(...arr.filter(v => Boolean(v) || v === 0)) ``` ## minArray数组中最小值 过滤原数组中所有的非假值元素,返回数组中的最小值 minArray(array) > 参数 array待处理的数组 > 示例 ```javascript minArray([0, -1, -2, -3, false]) // => -3 ``` > 源码 ```javascript const minArray = (arr) => Math.min(...arr.filter((v) => Boolean(v) || v === 0)); ``` ## validArray去除数组中的无效值 创建一个新数组,包含原数组中所有的非假值元素。例如false, null,0, "", undefined, 和 NaN 都是被认为是“假值”。 validArray(array) > 参数 array待处理的数组 > 示例 ```javascript minArray([0, 1, false, 2, '', 3]) // => [1, 2, 3] ``` > 源码 ```javascript const validArray = arr => arr.filter(Boolean) ``` *** # 二、对象 ## isObjectEqual检查两个对象各项值相等 isObjectEqual(object, object2) > 参数 object待检索的对象 object2待检索的对象 > 示例 ```javascript isObjectEqual({ a: 2, b: 4 }, { b: 4, a: 2 }) // => true isObjectEqual({ a: 2, b: 4, c: 6 }, { b: 4, a: 2 }) // => false ``` > 源码 ```javascript function isObjectEqual(obj1, obj2, has = true) { // 判断类型 const o1 = obj1 instanceof Object const o2 = obj2 instanceof Object if (!o1 || !o2) return obj1 === obj2 // 判断长度 const keys1 = Object.getOwnPropertyNames(obj1) const keys2 = Object.getOwnPropertyNames(obj2) if (keys1.length !== keys2.length) return false // 各项对比 for (let o in obj1) { let t1 = obj1[o] instanceof Object let t2 = obj2[o] instanceof Object if (t1 && t2) { has = diffByObj(obj1[o], obj2[o]) } else if (obj1[o] !== obj2[o]) { has = false break } } return has } ``` ## cloneObject克隆对象 浅拷贝一份对象副本 cloneObject(object) > 参数 object要复制的对象 > 示例 ```javascript const a = { x: 1, y: 1 } const b = cloneObject(a) // => a !== b ``` > 源码 ```javascript // ES6 ... const cloneObject = (obj, temp = {}) => (temp = { ...obj }) // Object.assign() const cloneObject = obj => Object.assign({}, obj) ``` *** # 三、函数 ## debounce函数防抖 在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时。 debounce(fn, wait) > 参数 fn 要防抖动的函数 wait=500需要延迟的毫秒数 > 示例 ```javascript debounce(()=> { console.log('debounce') }, 1000) // => 1秒后打印'debounce' ``` > 源码 ```javascript /** * * 防抖 * @parmas fn 回调函数 * @parmas time 规定时间 */ const debounce = (function () { let timer = {} return function (func, wait = 500) { let context = this // 注意 this 指向 let args = arguments // arguments中存着e let name = arguments[0].name || 'arrow' //箭头函数 if (timer[name]) clearTimeout(timer[name]) timer[name] = setTimeout(() => { func.apply(this, args) }, wait) } })() ``` ## throttle函数节流 规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。 throttle(fn, wait) > 参数 fn 要节流的函数 wait=500需要延迟的毫秒数 > 示例 ```javascript throttle(() => { console.log('throttle') }, 1000) // 1秒多次触发打印一次`throttle` ``` > 源码 ```javascript /** * * 节流(规定的时间才触发) * @parmas fn 结束完运行的回调 * @parmas delay 规定时间 */ export const throttle = (function () { let timeout = null return function (func, wait) { let context = this let args = arguments if (!timeout) { timeout = setTimeout(() => { timeout = null func.apply(context, args) }, wait) } } })() throttle(fn, 300) ``` ## typeFn类型判断 判断是否是 Array Object String Number类型 typeFn.type(value) > 参数 type 数据类型 value要检验的值 > 示例 ```javascript typeFn.String('1') typeFn.Number(1) typeFn.Boolean(false) typeFn.Null(null) typeFn.Array([1, 2]) typeFn.Object({ a: 1 }) typeFn.Function(() => {}) // => true ``` > 源码 ```javascript let typeFn = {} const curring = (fn, arr = []) => { let len = fn.length return (...args) => { arr = arr.concat(args) if (arr.length < len) { return curring(fn, arr) } return fn(...arr) } } function isType(type, content) { return Object.prototype.toString.call(content) === `[object ${type}]` } ;['String', 'Number', 'Boolean', 'Null', 'Array', 'Object', 'Function'].forEach(type => { typeFn[type] = curring(isType)(type) }) ``` calcFn加减乘除运算 因为 JavaScript 遵循 IEEE 754 数学标准,使用 64 位浮点数进行运算。在进行十进制运算时会导致精度丢失。 calcFn.add(value1, value2, value3) > 参数 add、sub、mul、div运算符 value要计算的值 > 示例 ```javascript 解决 0.1+0.2 !== 0.3 问题 //加法 calcFn.add(0.1, 0.2) // 0.3 //减法 calcFn.sub(0.1, 0.2) // 0.1 //乘法 calcFn.mul(0.2, 0.3) // 0.06 // 乘法 calcFn.add(0.1, 0.2) // 0.5 ``` > 源码 ```javascript const calcFn = { add() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accAdd(total, num); }); }, sub() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accAdd(total, -num); }); }, mul() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accMul(total, num); }); }, div() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accDiv(total, num); }); } } function accAdd(arg1, arg2) { let r1, r2, m; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); return (arg1 * m + arg2 * m) / m; } function accMul(arg1, arg2) { let m = 0, s1 = arg1.toString(), s2 = arg2.toString(); try { m += s1.split(".")[1].length; } catch (e) {} try { m += s2.split(".")[1].length; } catch (e) {} return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); } function accDiv(arg1, arg2) { let t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toString().split(".")[1].length; } catch (e) {} try { t2 = arg2.toString().split(".")[1].length; } catch (e) {} r1 = Number(arg1.toString().replace(".", "")); r2 = Number(arg2.toString().replace(".", "")); return (r1 / r2) * Math.pow(10, t2 - t1); } ``` # 四、字符串 ## isNil值是否是null或undefined isNil(value) > 参数 value 要检验的值 > 示例 ```javascript isNil(null) isNil(undefined) // => true ``` > 源码 ```javascript const isNil = val => val === undefined || val === null ``` ## padStart遮住字符串 padStart(value, n, maskChar) > 参数 value 要遮住字符串 n = 4 填充的长度 maskChar 填充字符 > 示例 ```javascript padStart('18659808664') // => 1865******* ``` > 源码 ```javascript const padStart = (str, n = 4, maskChar = '*') => str.slice(0, n).padStart(str.length, maskChar) thousands数字每隔三位数加分号 thousands(number) ``` > 参数 number 数字或者浮点数 > 示例 ```javascript thousands(12255555.2323) // => 12,255,555.2323 ``` > 源码 ```javascript const thousands = num => num.toString().replace(num.toString().indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(\d{3})+$)/g, '$1,') ``` ## toHump下划线转驼峰 toHump(str) 将下划线变量转换为驼峰 > 参数 str 需要转换的字符串 > 示例 ```javascript toHump('a_to_serve') // aToServe ``` ## toLine驼峰转下划线 toLine(str) 将驼峰变量转换为下划线 > 参数 str 需要转换的字符串 > 示例 ```javascript toLine('aToServe') // a_to_serve ``` ## firstUpperHump下划线转首字母大写的驼峰 firstUpperHump(str) 将下划线转首字母大写的驼峰 > 参数 str 需要转换的字符串 > 示例 ```javascript firstUpperHump('a_to_serve') // AToServe ``` # 五、数字 ## randomNumber指定范围的随机整数 randomNumber(min, max) > 参数 min 指定范围最小值 max 指定范围最大值 > 示例 ```javascript randomNumber(0, 10) // => 7 // => 2 ``` > 源码 ```javascript const randomNumber = (min = 0, max = 10) => Math.floor(Math.random() * (max - min + 1)) + min ``` ## average求平均值 average(value1, value2, value3) > 参数 value 数字 > 示例 ```javascript average(...[1, 2, 3]) average(1, 2, 3) // => 2 ``` > 源码 ```javascript const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length ``` ## averageBy检查数组对象各项相等 averageBy(array, fn) > 参数 array 要迭代的数组 fn 迭代函数 > 示例 ```javascript averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n) averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n') // => 5 ``` > 源码 ```javascript const averageBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / arr.length ``` ## aboutEqual两个值是否约等于 传入两个数字是否大致相等,误差在可接受范围内 aboutEqual(n1, n2, epsilon) > 参数 n1 n2 要比较的数字 epsilon 误差可接受范围内 > 示例 ```javascript aboutEqual(1.25, 1.2, 0.06) // => true ``` > 源码 ```javascript const aboutEqual = (n1, n2, epsilon = 0.001) => Math.abs(n1 - n2) < epsilon ``` ## getLineSize计算两点之间的距离 勾股定理计算两点之间的距离 getLineSize = (x1, y1, x2, y2) > 参数 x1 y1 x2 y2坐标点 > 示例 ```javascript getLineSize(0, 0, 3, 4) ``` // => 5 > 源码 ```javascript const getLineSize = (x1, y1, x2, y2) => Math.hypot(x2 - x1, y2 - y1) ``` ## sum数组中值总和 sum(value1, value2, value3) > 参数 value1 value2 value3要迭代的数字 > 示例 ```javascript sum(1, 2, 3, 4) sum(...[1, 2, 3, 4]) // => 10 ``` > 源码 ```javascript const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0) ``` # 六、浏览器 ## copyTextH5复制文本 copyText(content, callback) > 参数 content要复制文字 callback 回调用户提示 > 示例 ```javascript copyText(content, text => { this.$toast(text) }) ``` > 源码 ```javascript function copyText(content, callback) { if (!document.queryCommandSupported('copy')) { //为了兼容有些浏览器 queryCommandSupported 的判断 console.log('浏览器不支持') return } let textarea = document.createElement('textarea') textarea.value = content textarea.readOnly = 'readOnly' document.body.appendChild(textarea) textarea.select() // 选择对象 textarea.setSelectionRange(0, content.length) //核心 let result = document.execCommand('copy') // 执行浏览器复制命令 callback && callback(result ? '复制成功~~' : '复制失败~~') textarea.remove() } ``` ## getCurrentURL获取当前的URL地址 该函数返回当前页面的 URL 地址。 > 示例 ```javascript getCurrentURL() // => ``` > 源码 ```javascript const getCurrentURL = () => window.location.href ``` ## scrollToTop返回顶部 平滑地滚动到当前页面的顶部。 > 示例 ```javascript scrollToTop() // => 当前页面的顶部 ``` > 源码 ```javascript const scrollToTop = () => { const c = document.documentElement.scrollTop || document.body.scrollTop if (c > 0) { window.requestAnimationFrame(scrollToTop) window.scrollTo(0, c - c / 8) } } ``` ## smoothScroll平滑滚动页面 平滑滚动到浏览器窗口的可见区域 > 示例 ```javascript smoothScroll('#fooBar'); // => 平滑滚动到ID为fooBar的元素 smoothScroll ('.fooBar' ); // => 使用fooBar类平滑滚动到第一个元素 ``` > 源码 ```javascript const smoothScroll = element => document.querySelector(element).scrollIntoView({ behavior: 'smooth', }) ```