在实际的开发工作过程中,积累了一些常见又超级好用的 Javascript 技巧和代码片段,包括整理的其他大神的 JS 使用技巧,以供大家参考。本人的分享也是自己边学边做的笔记,若笔记内有错误内容或更优雅适合的写法方案,欢迎私信或评论留言互相学习~
在开始前,推荐一款程序员都应该知道的好物——JNPF低代码开发
这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架,包含表单建模、流程设计、报表可视化、代码生成器、系统管理、前端 UI 等组件,这种情况下我们避免了重复造轮子,已内置大量的成熟组件,选择合适的组件进行集成或二次开发复杂功能,即可自主开发一个属于自己的应用系统。
另外,后续会持续分享前端开发的其他相关的知识总结等,那么,我们开始吧~
日期格式化
// 格式化日期类型,fmt格式可选择 function dateFormat(fmt, date) { let ret; let opt = { "Y+": date.getFullYear().toString(), // 年 "M+": (date.getMonth() + 1).toString(), // 月 "D+": date.getDate().toString(), // 日 "h+": date.getHours().toString(), // 时 "m+": date.getMinutes().toString(), // 分 "s+": date.getSeconds().toString(), // 秒 "ms+": date.getMilliseconds().toString() // 毫秒 }; for (let k in opt) { ret = new RegExp("(" + k + ")").exec(fmt); if (ret) { fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0")); } } return fmt; } // 格式化当前时间 dateFormat("YYYY-MM-DD hh:mm:ss.ms", new Date()); // 格式化特定时间 let date = new Date(); let fDate = dateFormat("YYYY-MM-DD hh:mm:ss.ms", new Date(date));
时间转换(秒数转时分秒)
function timeFormat (sec) { let minite = Math.floor((sec / 60 % 60)) < 10 ? '0' + Math.floor((sec / 60 % 60)) : Math.floor((sec / 60 % 60)); let second = Math.floor((sec % 60)) < 10 ? '0' + Math.floor((sec % 60)) : Math.floor((sec % 60)); if (sec < 3600) { return `${minite}:${second}`; } else { let hour = Math.floor(sec / 3600) < 10 ? '0' + Math.floor(sec / 3600) : Math.floor(sec / 3600); return `${hour}:${minite}:${second}`; } }
计算时分秒差值
// 计算时分秒差值 function timeDiffer(beginTime, endTime) { let ret = {}; let date = new Date(); let sTime = Date.parse(dateFormat("YYYY/MM/DD", date) + " " + beginTime); if (beginTime >= endTime) { date.setDate(date.getDate() + 1); } let eTime = Date.parse(dateFormat("YYYY/MM/DD", date) + " " + endTime); let differ = eTime - sTime; let hour = Math.floor(differ / 1000 / 60 / 60); let minute = Math.floor(differ / 1000 / 60 - hour * 60); let second = Math.floor(differ / 1000 - hour * 60 * 60); ret = { differHour: hour, differMinute: minute, differSecond: second }; return ret; } let { differHour, differMinute, differSecond } = timeDiffer(beginTime, endTime);
(数组/对象)(深/浅)拷贝
let list = [{ name: "o" }]; let obj = { stu: { name: "o" } }; // 数组浅拷贝 let listCopy1 = [].concat(list); let listCopy2 = list.slice(); let listCopy3 = Array.from(list); let listCopy4 = [...list]; // 对象浅拷贝 let objCopy1 = Object.assign({}, obj); let objCopy2 = { ...obj }; // 数组|对象深拷贝 let listCopy = JSON.parse(JSON.stringify(list)); let objCopy = JSON.parse(JSON.stringify(obj)); // 深拷贝,即复制并独立一份数据,操作不影响原数据 function deepCopy(obj) { if (typeof obj !== "object") { return obj; } let result = Array.isArray(obj) ? [] : {}; for (let i in obj) { if (obj.hasOwnProperty(i)) { if (typeof obj[i] === "object" && obj[i] !== null) { result[i] = deepCopy(obj[i]); } else { result[i] = obj[i]; } } } return result; } // 深拷贝 function deepClone(obj) { let copyObj = null; if (typeof obj === "object" && obj !== null) { copyObj = Array.isArray(obj) ? [] : {}; for (let i in obj) { copyObj[i] = deepClone(obj[i]); } } else { copyObj = obj; } return copyObj; }
数组去重
// ES6最简方法 let result = []; if (Array.isArray(arr)) { result = new Set(arr); } function unique(arr) { return Array.from(new Set(arr)); } // filter去重 function unique(arr) { return arr.filter((item, index, arr) => { // 当前元素在原数据中的第一个索引等于当前索引值,否则返回当前元素 return arr.indexOf(item, 0) == index; }); } // 数组去重 function unique(arr) { if (!Array.isArray(arr)) { return; } let result = []; for (let i = 0; i < arr.length; i++) { if (result.indexOf(arr[i]) === -1) { result.push(arr[i]); } } return result; } function unique(arr) { if (Array.isArray(arr)) { let result = []; for (let i = 0, len = arr.length; i < len; i++) { if (!result.includes(arr[i])) { result.push(arr[i]); } } return result; } }
数组对象排序
// 数组对象排序,比较两个字符串 list.sort((a, b) => { return a.id.localeCompare(b.id); });
获取上/下个月日期
// 下个月 let date = new Date(this.startDate); let nextMonthDate = date.setMonth(date.getMonth() + 1); this.endDate = dateFormat("YYYY-MM-DD", new Date(nextMonthDate)); // 上个月 let lastMonthDate = date.setMonth(date.getMonth() - 1);
获取前/后7天日期
// 前7天 let date = new Date(this.startDate); let afterDate = date.setDate(date.getDate() + 6); this.endDate = dateFormat("YYYY-MM-DD", new Date(afterDate)); // 后7天 let afterDate = date.setDate(date.getDate() - 6);
一周日期
let weeks=["周一","周二","周三","周四","周五","周六","周日"]; for (let i = 0; i<7; i++){ let date = new Date(); let index = date.getDay() ? date.getDay() - 1 : 6; let nowDate = date.setDate(date.getDate() - index + i); let formatDate = dateFormat("MM-DD", new Date(nowDate)); let week = weeks[i]; let weekDate = `${formatDate}(${week})`; this.weekDateColumns.push(weekDate); }
点击内容切换
let len = this.assistList.length - 1; if (this.index < len) { this.index++; this.assistInfo = this.assistList[this.index]; } else { this.index = 0; this.assistInfo = this.assistList[this.index]; }
时分秒
时:`parseInt(count/60/60)` 分:`parseInt(count/60)%60` 秒:`parseInt(count%60)`
数组对象,拼接字符串
let arr = [ { id: 1, name: "Andy" }, { id: 2, name: "Jim" }, { id: 3, name: "Lucy" }, { id: 4, name: "Cherry" }, ]; let str = arr.map((item) => { return item.name; }).join(",");
当月第一天和最后一天
// 第一天 let date = new Date(); date.setDate(1); console.log(dateFormat("YYYY-MM-DD", date)); // 最后一天 let date = new Date(); let lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0); console.log(dateFormat("YYYY-MM-DD", lastDay));
fetch
接口请求
let api = "https://api.com"; let headerConfig = { headers: { Accept: "application/json", }, }; async function request() { let res = await fetch(api, headerConfig); let data = await res.json(); }
按键处理方法
window.addEventListener("keydown", (e) => { let container = document.querySelector("#container"); let { key, keyCode, code } = e; let template = ""; [ { title: "e.key", content: key == " " ? "Space" : key, }, { title: "e.keyCode", content: keyCode, }, { title: "e.code", content: code, }, ].forEach((item) => { template += `<div class="key"><small>${item.title}</small>${item.content}</div>`; }); container.innerHTML = template; });
返回顶部
html, body { scroll-behavior: smooth; } .back { position: sticky; float: right; top: -110px; margin-top: -50px; border-radius: 50%; background: url("") center no-repeat dodgerblue; background-size: 50%; width: 50px; height: 50px; transform: translateY(calc(100vh + 50px)); }
自适应内部元素
figure { max-width: 300px; max-width: min-content; margin: auto; } figure > img { max-width: inherit; }
iview封装菜单menu
<template> <i-submenu :name="menuList.name"> <!-- 父级菜单 --> <template slot="title">{{ menuList.title }}</template> <template v-for="(item, index) in menuList.children"> <!-- 如果还要子集,继续调用 --> <left-menu-nav v-if="item.hasOwnProperty('children')" :menuList="item"></left-menu-nav> <!-- 无子菜单 --> <i-menu-item v-else :name="item.name">{{ item.title }}</i-menu-item> </template> </i-submenu> </template> <script> export default { name: "leftMenuNav", props: { menuList: { type: Object, default: () => { } } } }; </script> <Layout> <Sider hide-trigger collapsible :width="192" :collapsed-width="64" v-model="collapsed" class="left-sider" :style="{ overflow: 'hidden' }"> <i-menu class="menu-position" ref="menu" :active-name="selectItem" :open-names="menuOpenName" @on-select="changeSelectItem"> <template v-for="(item, index) in menuList" :name="item.name"> <!-- 有子菜单 --> <left-menu-nav v-if="item.hasOwnProperty('children')" :menuList="item"></left-menu-nav> <!-- 无子菜单 --> <i-menu-item v-else :name="item.name">{{ item.title }}</i-menu-item> </template> </i-menu> </Sider> <Content class="main-content-con"> <Layout class="main-layout-con"> <Content class="content-wrapper" style="position: relative"> <router-view style="height: 100%" /> <div v-show="lockEnable" class="lockBox"></div> <ABackTop :height="100" :bottom="80" :right="50" container=".content-wrapper"></ABackTop> </Content> </Layout> </Content> </Layout>
图片懒加载
const images = document.querySelectorAll("img"); const callback = (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const image = entry.target; const data_src = image.getAttribute("data-src"); image.setAttribute("src", data_src); ResizeObserver.unobserver(image); } }); }; const observer = new IntersectionObserver(callback); images.forEach((image) => { observer.observe(image); });CSS多行文本省略
p { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; }
Vue字符串换行
1. 添加`white-space:pre` 2. 使用`<pre>`标签替换
封装iView无限层级菜单
// 子组件 <template> <i-submenu :name="menuList.name"> <!-- 父级菜单 --> <template slot="title">{{menuList.title}}</template> <template v-for="(item,index) in menuList.children"> <!-- 如果还要子集,继续调用 --> <left-menu-nav v-if="item.children&&item.children.length" :menuList="item" :key="item.index"></left-menu-nav> <!-- 子菜单 --> <i-menu-item :key="item.id" :name="item.name">{{item.title}}</i-menu-item> </template> </i-submenu> </template> <script> export default { name: "leftMenuNav", props: { menuList: { type: Object, default: () => { } } } } </script>// 父组件 <i-menu :active-name="selectItem" :open-names="menuOpenName" @on-select="changeSelectItem"> <template v-for="(item, index) in menuList" :name="item.name"> <!-- 有子菜单 --> <left-menu-nav v-if="item.children && item.children.length" :menuList="item" :key="item.name"></left-menu-nav> <!-- 无子菜单 --> <i-menu-item v-else :name="item.name" :key="item.name">{{ item.title }}</i-menu-item> </template> </i-menu>
上传文件
<div class="upload"> <button id="btn" class="btn">上传文件</button> <input type="file" id="input" class="input" /> </div>.upload { width: 100px; height: 100px; position: relative; } .btn { width: 100%; height: 100%; box-sizing: border-box; border: 1px dashed rgb(31, 154, 158); background: #fff; cursor: pointer; } .input { width: 100%; height: 100%; box-sizing: border-box; position: absolute; left: 0; top: 0; opacity: 0; }
CSS
控制禁止点击
pointer-events: none; //(禁止鼠标点击事件)
单行居中,多行顶部对齐
.table-item { height: 100%; box-sizing: border-box; display: flex; flex: 1; flex-wrap: wrap; align-items: center; justify-content: center; font-size: 16upx; text-align: justify; font-weight: 600; span { width: 125upx; height: 65upx; overflow: auto; display: flex; align-items: center; justify-content: center; display: -webkit-box; -webkit-box-orient: vertical; } }
计算传入时间与当前时间相差的秒数
function convertStrToTime (time) { let nowTime = new Date().getTime(); let date = new Date(); let arr = time.split(":"); date.setHours(parseInt(arr[0])); date.setMinutes(parseInt(arr[1])); let endTime = new Date(date).getTime(); let ret = Math.ceil((endTime - nowTime) / 1000); return ret; }