记录一些很实用的小方法,方便在以后的查询,持续更新中。
js
使用JSON
格式化输出
1 2 3 4 5 6 7 8 9
|
JSON.stringify(obj, null, 4);
|
一个数的奇偶性判断
1 2 3 4 5 6 7 8 9 10
|
if (num & 1) console.log('奇数'); else console.log('偶数');
|
求 2 的 n 次方
两个变量互换
1
| [var1, var2] = [var2, var1];
|
浅拷贝
1
| Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
|
深拷贝
1 2 3 4 5 6 7 8 9 10 11 12
| function deepCopy(obj) { if (typeof obj !== 'object') { return; } const newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
|
计算滚动条的宽度
1
| content.offsetHeight - content.scrollHeight;
|
监听 App 自带返回键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
const visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
const onVisibilityChange = function () { if (!document[hiddenProperty]) { console.log('页面非激活'); } else { console.log('页面激活'); } };
document.addEventListener(visibilityChangeEvent, onVisibilityChange);
|
帧率计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| let lastTime = performance.now(); let frame = 0; let lastFameTime = performance.now(); const loop = () => { const now = performance.now(); const fs = now - lastFameTime; lastFameTime = now; let fps = Math.round(1000 / fs); frame += 1; if (now > 1000 + lastTime) { fps = Math.round((frame * 1000) / (now - lastTime));
frame = 0; lastTime = now; } console.log(fps); window.requestAnimationFrame(loop); }; window.requestAnimationFrame(loop);
|
函数扁平化 compose
1 2 3 4 5 6 7 8 9 10 11
| function compose(...funcs) { return function anonymous(...args) { if (funcs.length === 0) return args; if (funcs.length === 1) return funcs[0](...args); return funcs.reduce((n, func) => { return Array.isArray(n) ? func(...n) : func(n); }, args); }; }
|
函数柯理化 currying
1 2 3 4 5 6 7 8 9 10
| function currying(fn, ...args) { if (fn.length === args.length) { return fn(...args); } else { return function anonymous(...newArgs) { let allArgs = [...args, ...newArgs]; return currying(fn, ...allArgs); }; } }
|
将字符串渲染为 DOM 节点
主要是用 innerHTML
来实现,让浏览器帮我们进行转换,返回的是一个节点数组:
1 2 3 4 5
| function parseDom(arg) { const objE = document.createElement('div'); objE.innerHTML = arg; return objE.childNodes; }
|
缓动小算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Math.easeout = function (A, B, rate, callback) { if (A == B || typeof A !== 'number') { return; }
B = B || 0; rate = rate || 2;
const step = function () { A = A + (B - A) / rate;
if (Math.abs(A - B) < 1) { callback(B, true); return; } callback(A, false); requestAnimationFrame(step); }; step(); };
|
快速实现折线图
在图标上定位好每个点的位置后,获取这些点,然后调用下列函数:
1 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
| const fnLineChart = function (eleDots) { [].slice.call(eleDots).forEach(function (ele, index) { const eleNext = eleDots[index + 1]; if (!eleNext) return; const eleLine = ele.querySelector('i'); if (!eleLine) { eleLine = document.createElement('i'); eleLine.setAttribute('line', ''); ele.appendChild(eleLine); } const boundThis = ele.getBoundingClientRect(); const boundNext = eleNext.getBoundingClientRect(); const x1 = boundThis.left; const y1 = boundThis.top; const x2 = boundNext.left; const y2 = boundNext.top; const distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); const radius = Math.atan((y2 - y1) / (x2 - x1)); eleLine.style.width = distance + 'px'; eleLine.style.msTransform = 'rotate(' + radius + 'rad)'; eleLine.style.transform = 'rotate(' + radius + 'rad)'; }); };
|
折线的样式需要自定义:
1 2 3 4 5
| i[line] { position: absolute; transform-origin: left center; ...; }
|
转载自 不借助 Echarts 等图形框架原生 JS 快速实现折线图效果
JSON 树查找子节点的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public findNodePath = (id: number, nodes: any[], path?: any[]): any => { let item: any; path = path || []; for (item of nodes) { const tmpPath: any[] = path.slice(); tmpPath.push(item.id); if (id === item.id) { return tmpPath; } if (item.children) { const findResult = this.findNodePath(id, item.children, tmpPath); if (findResult) { return findResult; } } } };
|
或者
1 2 3 4 5 6 7 8 9 10 11 12
| function findTopParents(menuJson, childId, result) { result = result || []; let menuStr = typeof menuJson === 'string' ? menuJson : JSON.stringify(menuJson); let reg = new RegExp('id":"([^"]+)"[^\\}\\]\\[\\{]+\\[\\{[^\\}\\]\\[\\{]+id":"' + childId);
if (reg.test(menuStr)) { result.push(menuStr.match(reg)[1]); return findTopParents(menuStr, menuStr.match(reg)[1], result); } else { return result; } }
|
正则
对数字添加千分位符号
1 2 3 4 5 6 7
| String(Number).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
String(123456789).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
Number.toLocaleString('en-US');
(123456789).toLocaleString('en-US');
|
手机号替换
1 2 3
| const phone = '15112345678'; phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
|
常用的一些匹配
1 2
| 匹配中文字符 /[\u4e00-\u9fa5]/
|
1 2 3
| 匹配双字节字符(包括汉字在内) /[^\x00-\xff]/ /[^-~]/g
|
1 2
| 匹配邮箱 /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/
|
css
滚动嵌套时让父滚动不触发
1
| overscroll-behavior: contain;
|
IOS 滚动不平滑
1
| -webkit-overflow-scrolling: touch;
|
镂空字体(让文字显示背景色或图片)
1 2
| webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
配合文本描边 -webkit-text-stroke
会有更不错的表现
清除 Chrome 浏览器自动填充输入框的背景色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, input:-webkit-autofill:active { -webkit-animation: autofill 0s forwards; animation: autofill 0s forwards; }
@keyframes autofill { 100% { background: transparent; color: inherit; } }
@-webkit-keyframes autofill { 100% { background: transparent; color: inherit; } }
|
深色模式匹配
css 使用媒体查询 @media(prefers-color-scheme: dark)
适配:
1 2 3 4 5 6 7 8 9 10
| body { background: #f2f2f2; color: #333; } @media (prefers-color-scheme: dark) { body { background: #222; color: #eee; } }
|
js 使用 matchMedia
适配:
1 2 3 4 5 6 7 8 9 10 11
| if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { }
window.matchMedia('(prefers-color-scheme: dark)').addListener(e => { if (e.matches) { console.log('dark mode is enabled'); } else { console.log('dark mode is disabled'); } });
|
一行 css 实现简单的深色模式:
1
| filter: invert(1) hue-rotate(180deg);
|
1 2 3 4 5
| button[ant-click-animating-without-extra-node]:after { border: 0 none; opacity: 0; animation: none 0 ease 0 1 normal; }
|
图片加载失败兜底处理
在图片加载失败的时候,改变默认的展示。在img
标签上添加加载失败处理:
1
| <img src="xxx.png" alt="xxx" onerror="this.classList.add('error');">
|
添加全局css样式如下:
1 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
| img.error { display: inline-block; transform: scale(1); content: ''; color: transparent; } img.error::before { content: ''; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: #f5f5f5 url(break.svg) no-repeat center / 50% 50%; } img.error::after { content: attr(alt); position: absolute; left: 0; bottom: 0; width: 100%; padding: 0 8px 0; box-sizing: border-box; line-height: 2; background-color: rgba(0,0,0,.5); color: white; font-size: 12px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
node
判断模块的运行方式
检测一个node
模块(一个文件),是直接运行,还是被引入(require
):
1 2 3
| if (module === require.main) { console.log('直接运行'); }
|
node
中快速加载 当前文件夹下所有文件
在 node
中经常会实现按类型对文件进行分类,再通过 index.js
来引入统一导出。可以通过以下方法来实现:
1 2 3 4 5 6 7 8
| const fs = require('fs');
const handler = fs .readdirSync(__dirname) .filter(value => value !== 'index.js') .map(value => require('./' + value));
|
会生成一个数组,每一项是一个文件是导出的内容,如果我们想合并为一个对象:
1 2 3
| module.exports = pageHandles.reduce((a, b) => { return { ...a, ...b }; }, {});
|
设置 iOS 中 H5 字体跟随系统改变
ios 系统
- 默认中文字体是 Heiti SC
- 默认英文字体是 Helvetica
- 默认数字字体是 HelveticaNeue
- 无微软雅黑字体
android 系统
- 默认中文字体是 Droidsansfallback
- 默认英文和数字字体是 Droid Sans
- 无微软雅黑字体
1
| font-family: -apple-system, Helvetica, 'Heiti SC';
|
webpack
在 webpack 中使用 dart-sass
替换 node-sass
1 2 3 4 5
| # 卸载node-sass $ yarn remove node-sass
# 安装dart-sass $ yarn add node-sass@npm:sass
|
在 package.json
文件中增加:
1 2 3
| "resolution": { "node-sass": "npm:sass" },
|
其他
禁止 Chrome 自动翻译网页
在 head
里加上
1
| <meta name="google" content="notranslate" />
|