yjr-utils
v7.4.0
Published
utils for js/ts
Downloads
29
Maintainers
Readme
yjr-utils 在线文档 点击进入
下载安装
此包采用 ESModule 规范编写
npm i yjr-utils
pnpm i yjr-utils
yarn add yjr-utils
如何使用
全部加载
import * as yjrUtils from 'yjr-utils';
按需引入
import { fillZero, cloneDeep } from 'yjr-utils';
目录
1.单数补 0
单独补 0
import { fillZero } from 'yjr-utils';
fillZero('3'); // '03'
fillZero('13'); // '13'
支持分隔符来批量补 0
fillZero('1:5:9', ':'); // '01:05:09'
fillZero('13:6:29', ':'); // '13:06:29'
2.深拷贝
推荐使用 js 原生的深拷贝方法 structuredClone
/**
* 如果担心兼容性可手动引入以下路径来充当垫片;
* ( yjr-utils 内置了core-js )
*/
import 'core-js/actual/structured-clone';
const data = [
{
array: [1, 2, 3],
},
];
const data_2 = structuredClone(data);
data === data_2; // false
或者使用 lodash 的 cloneDeep
// yjr-utils 内部直接转发 lodash 的 cloneDeep
import { cloneDeep } from 'yjr-utils';
const obj = {
arr: [1, 2, 3],
};
const obj_2 = cloneDeep(obj);
obj === obj_2; // false
3.数组去重 ( 浅拷贝 )
基本数据类型去重
import { toSet } from 'yjr-utils';
toSet(['str', 'str', 110, 110, true, true]);
// 运行结果
['str', 110, true];
引用数据类型去重(根据某个路径)
import { toSet } from 'yjr-utils';
toSet(
[
{ info: [180, 1] },
{ info: [177, 2] },
{ info: [178, 3] },
{ info: [178, 3] },
{ info: [171, 5] },
],
'info[0]',
);
// 运行结果
[
{ info: [180, 1] },
{ info: [177, 2] },
{ info: [178, 3] },
{ info: [171, 5] },
];
4.数组排序 ( 浅拷贝 )
基本数据类型
import { doSort } from 'yjr-utils';
doSort([1, 7, 9, 5]);
// [ 1, 5, 9, 7 ]
doSort([1, 7, 9, 5], 'desc');
// [ 9, 7, 5, 1 ]
doSort(['a', 'b', 'd', 'c'], 'asc', 'english');
// [ 'a', 'b', 'c', 'd' ]
doSort(['a', 'b', 'd', 'c'], 'desc', 'english');
// [ 'd', 'c', 'b', 'a' ]
doSort(['花', '园', '宝', '宝'], 'asc', 'chinese');
// [ '宝', '宝', '花', '园' ]
doSort(['花', '园', '宝', '宝'], 'desc', 'chinese');
// [ '园', '花', '宝', '宝' ]
引用数据类型
import { doSort } from 'yjr-utils';
const data = [
{ a: { c: { d: 20 } }, b: 10 },
{ a: { c: { d: 18 } }, b: 10 },
{ a: { c: { d: 17 } }, b: 10 },
];
doSort(data, 'asc', 'number', 'a.c.d');
// 结果
[
{ a: { c: { d: 17 } }, b: 10 },
{ a: { c: { d: 18 } }, b: 10 },
{ a: { c: { d: 20 } }, b: 10 },
];
5.获得最大/小值 ( 浅拷贝 )
import { getExtreme } from 'yjr-utils';
getExtreme([1, 2, 99]); // 99
getExtreme([1, 2, 99], 'min'); // 1
// 引用数据类型使用
const data = [
{ a: { c: { d: 20 } } },
{ a: { c: { d: 18 } } },
{ a: { c: { d: 17 } } },
];
getExtreme(data, 'min', 'a.c.d'); // { a: { c: { d: 17 } } }
getExtreme(data, 'max', 'a.c.d'); // { a: { c: { d: 20 } } }
6.时间格式化
第二个参数是格式化模版,默认值是'YYYY-MM-DD HH:mm:ss'
import { timeFormat } from 'yjr-utils';
timeFormat('1999-05-12');
// '1999-05-12 08:00:00'
timeFormat(1662622488019, 'YYYY年MM月DD日 HH点mm分ss秒');
// '2022年09月08日 15点34分48秒'
7.获得时间差
传入两个时间,返回一个 [ 天,时,分,秒 ] 组成的数组
import { timeGap } from 'yjr-utils';
timeGap('2022-09-08 07:23:46', '2022-09-05 10:43:43');
// ['02','20','40','03'] 两个时间相差2天20小时40分钟3秒
timeGap(1662521026000, 1661999899000);
// ['06','00','45','26'] 两个时间相差6天0小时45分钟26秒
传入模板则直接返回格式化好的字符串
timeGap('2022-09-08 22:23:46', '2022-09-08 10:43:43', '还剩HH小时mm分钟ss秒');
// '还剩11小时40分钟03秒'
timeGap('2022-09-08 13:23:46', '2022-09-05 19:54:34', 'DD天HH时mm分ss秒');
// '02天17时29分12秒'
timeGap(1662521026000, 1661999899000, 'DD天HH时mm分ss秒');
// '06天00时45分26秒'
8.排序效仿 ( 浅拷贝 )
import { sortImitate } from 'yjr-utils';
const target = [
{ type: 'A', name: '小王' },
{ type: 'S', name: '小明' },
{ type: 'SS', name: '小红' },
];
const source = [
{ type: 'SS', name: '小强' },
{ type: 'A', name: '小刚' },
{ type: 'S', name: '小金' },
];
sortImitate(target, source, 'type');
// 结果
[
{ type: 'A', name: '小刚' },
{ type: 'S', name: '小金' },
{ type: 'SS', name: '小强' },
];
9.对象成员过滤(回调)
import { pickBy } from 'yjr-utils';
const obj = {
a: 1,
ac2: 2,
a3: 3,
ac4: 4,
};
pickBy(obj, (val) => val >= 2);
// { ac2: 2, a3: 3, ac4: 4 }
pickBy(obj, (_val, key) => key.startsWith('ac'));
// { ac2: 2, ac4: 4 }
10.对象成员过滤(回调),逆向
import { omitBy } from 'yjr-utils';
const obj = {
a: 1,
ac2: 2,
a3: 3,
ac4: 4,
};
omitBy(obj, (val) => val >= 2);
// { a: 1 }
omitBy(obj, (_val, key) => key.startsWith('ac'));
// { a: 1, a3: 3 }
11.防抖
import { debounce } from 'yjr-utils';
const func = () => console.log('resizing');
window.onresize = debounce(func, 500, {
// 不等待第一个定时器结束,直接执行
leading: true,
// 如果一直被阻塞无法执行代码,则2秒内必定执行一次
maxWait: 2000,
});
// 取消
window.onresize.cancel();
// 刷新
window.onresize.flush();
12.节流
import { throttle } from 'yjr-utils';
const func = () => console.log('resizing');
window.onscroll = throttle(func, 200, {
// 不等待第一个定时器结束,直接执行
leading: true,
});
// 取消
window.onscroll.cancel();
// 刷新
window.onscroll.flush();
13.数组分割
import { chunk } from 'yjr-utils';
chunk([1, 2, 3, 4], 2);
// [[1,2],[3,4]] 两个成员一组来分组
chunk([1, 2, 3, 4], 3);
// [[1,2,3],[4]] 三个成员一组来分组
const data = [
{ a: 1, b: 1 },
{ a: 2, b: 2 },
{ a: 3, b: 3 },
{ a: 4, b: 4 },
];
chunk(data, 2);
// 结果
[
[
{ a: 1, b: 1 },
{ a: 2, b: 2 },
],
[
{ a: 3, b: 3 },
{ a: 4, b: 4 },
],
];
14.获得一个随机数
import { random } from 'yjr-utils';
random(-10, 20); // -2
random(5, 10); // 7
random(1.2, 5.2); // 3.4508875522514773
// 不返回整数
random(0, 4, true); // 3.154170094134428
random(0, 4); // 3
15. 文字超出省略
支持 空格-汉字-数字-字母-特殊字符-字体图标-表情 等 7 种字符省略处理
import { textEllipsis } from 'yjr-utils';
textEllipsis('Ab&_12看看 👀🆕😊❤️', 10);
// 'Ab&_12看看 👀...'
textEllipsis('🉑️23', 3);
// '🉑️2...' 某些非常特殊的字体图标会占用2个位置
textEllipsis('❤️ab', 3);
// '❤️a...' 某些非常特殊的字体图标会占用2个位置
textEllipsis('abcdef', 4, true);
// 'a...' 开启严格模式,'...'也会消费你传入的长度
16.剩余时间
timeGap 的简化版本,直接传入一个差值时间戳
import { remainTime } from 'yjr-utils';
remainTime(7081940);
// ['00', '01', '58', '02']
remainTime(7081940, '还剩DD天HH小时mm分钟ss秒');
// '还剩00天01小时58分钟02秒'
17.监听元素是否可见
<div id="box"></div>
import { watchDomIsVisible } from 'yjr-utils';
const dom = document.getElementById('box');
const handler = (e) => {
console.log(e ? '元素可见' : '元素不可见');
};
const { watch, unwatch } = watchDomIsVisible(dom, handler);
watch(); // 开始监听 元素露出50%算作可见,反之不可见
unwatch(); // 停止监听
还可以设置阈值
// 阈值默认为0.5 可传0-1
const { watch, unwatch } = watchDomIsVisible(dom, handler, 0.3);
watch(); // 开始监听 元素露出30%算作可见,反之不可见
unwatch(); // 停止监听
18.获取数据类型
import { getType } from 'yjr-utils';
getType([1, 2, 3]);
// 'array'
getType({ a: 10 });
// 'object'
getType(null);
// 'null'
19.合并数据
import { merge } from 'yjr-utils';
const base = {
a: [{ b: 2 }, { d: 4 }],
};
const other = {
a: [{ c: 3 }, { e: 5 }],
};
merge(base, other);
// 结果
{
a: [
{ b: 2, c: 3 },
{ d: 4, e: 5 },
];
}
20.判断两个变量是否相等
import { isEqual } from 'yjr-utils';
const base = {
a: [1, 2, 3],
};
const other = {
a: [1, 2, 3],
};
isEqual(base, other); // true 结构完全相同
base === other; // false 内存地址不一样
21.使用未发布的数组 Api
如果你想使用 findLast,findLastIndex,with,toSpliced,toReversed
这些已经在 ESNext.d.ts 中出现但未发布的数组方法,导入该模块即可
import 'yjr-utils/src/arrayPolyfills.js';
如果是 ts 项目,则还需要在你项目中的 d.ts 文件中引入声明文件
/// <reference types="yjr-utils/src/arrayPolyfills.d.ts" />
导入以上文件后就可以在你的项目中使用这些 Api 了
[1, 2, 3].with(1, 90); // [1,90,3]
[1, 2, 3].toReversed(); // [3,2,1]
[1, 2, 3].toSpliced(1, 0, 2, 3); // [1,2,3,2,3]
22.拉平嵌套对象 ( 浅拷贝 )
import { flatObj } from 'yjr-utils';
const nest = [
{
id: 1,
pid: 0,
children: [
{
id: 2,
pid: 1,
children: [
{
id: 3,
pid: 2,
},
],
},
],
},
];
flatObj(nest);
// 结果
[
{
id: 1,
pid: 0,
},
{
id: 2,
pid: 1,
},
{
id: 3,
pid: 2,
},
];
const nest2 = [
{
route: 'home',
pRoute: '',
children: [
{
route: 'home/main',
pRoute: 'home',
children: [
{
route: 'home/main/index',
pRoute: 'home/main',
},
],
},
],
},
];
flatObj(nest2);
// 结果
[
{
route: 'home',
pRoute: '',
},
{
route: 'home/main',
pRoute: 'home',
},
{
route: 'home/main/index',
pRoute: 'home/main',
},
];
23.使平级对象嵌套 ( 浅拷贝 )
import { nestedObj } from 'yjr-utils';
const flat = [
{
id: 1,
pid: 0,
},
{
id: 2,
pid: 1,
},
{
id: 3,
pid: 2,
},
];
nestedObj(flat, 'id', 'pid');
// 结果
[
{
id: 1,
pid: 0,
children: [
{
id: 2,
pid: 1,
children: [
{
id: 3,
pid: 2,
},
],
},
],
},
];
const flat2 = [
{
route: 'home',
pRoute: '',
},
{
route: 'home/main',
pRoute: 'home',
},
{
route: 'home/main/index',
pRoute: 'home/main',
},
];
nestedObj(flat, 'route', 'pRoute');
// 结果
[
{
route: 'home',
pRoute: '',
children: [
{
route: 'home/main',
pRoute: 'home',
children: [
{
route: 'home/main/index',
pRoute: 'home/main',
},
],
},
],
},
];
24.获取滚动条宽度
import { getScrollBarWidth } from 'yjr-utils';
getScrollBarWidth(); // 17
25.对象成员过滤
import { pick, omit } from 'yjr-utils';
const object = { a: 1, b: '2', c: 3 };
omit(object, ['a', 'c']);
// { 'b': '2' }
pick(object, ['a', 'c']);
// { 'a': 1, 'c': 3 }
26.对象转查询字符串
值为 null 或 undefined 会被自动过滤掉
import { queryString } from 'yjr-utils';
const obj = {
number: 1,
null: null,
undefined: undefined,
string: 'str',
bool: true,
};
queryString(obj);
// number=1&string=str&bool=true
27.获取地址栏参数
import { getURLParameters } from 'yjr-utils';
window.location.href =
'https://www.npmjs.com/package/yjr-utils?activeTab=versions';
getURLParameters();
// { activeTab : 'versions' };
28.货币格式化
import { currencyFormat } from 'yjr-utils';
currencyFormat(123456); // '123,456'
currencyFormat(1234567); // '1,234,567'
currencyFormat(123456.86); // '123,456.86'
29.浮点型精准计算
import { preciseCalculation } from 'yjr-utils';
// 未处理前 0.1 + 0.2 = 0.30000000000000004
preciseCalculation(0.1, 0.2, '+'); // 0.3;
// 未处理前 0.8 - 0.1 = 0.7000000000000001
preciseCalculation(0.8, 0.1, '-'); // 0.7;
// 未处理前 0.1 * 0.2 = 0.020000000000000004
preciseCalculation(0.1, 0.2, '*'); // 0.02;
// 未处理前 0.6 / 0.2 = 2.9999999999999996
preciseCalculation(0.6, 0.2, '/'); // 3;
30.监听页面可视状态
import { pageIsVisible } from 'yjr-utils';
const handler = (e) => {
console.log(e === 'visible' ? '页面可见' : '页面不可见');
};
const { watch, unwatch } = pageIsVisible(handler);
watch(); // 开始监听
unwatch(); // 停止监听
31.对比两组数据间的差异
import { jsDiff } from 'yjr-utils';
const obj1 = {
a: 100,
b: 50,
c: 6,
};
const obj2 = {
a: 101,
b: 50,
d: 99,
};
jsDiff(obj1, obj2);
// 结果
[
{
path: 'a',
desc: '修改',
_old: 100,
_new: 101,
},
{
path: 'd',
desc: '新增',
_new: 99,
_old: undefined,
},
{
path: 'c',
desc: '删除',
_old: 6,
_new: undefined,
},
];
32.是否是移动设备/是否是 IOS
import { isMobile, isIOS } from 'yjr-utils';
isMobile(); // true || false
isIOS(); // true || false
33. H5 应用适配 IOS 键盘
import { fitKeyboardInIOS } from 'yjr-utils';
/**
* 如果你的H5应用被以下问题所困扰,直接引入此方法即可
* 1.ios键盘弹起导致导航栏被顶走
* 2.ios键盘切换输入法或者切到表情面板导致页面底部被盖住
*/
// 在主应用节点第一次渲染完毕后获取,然后传给fitKeyboardInIOS即可
<div id="root">
<div id="App">your node</div>
</div>;
const App = document.getElementById('App');
fitKeyboardInIOS(App);
34. useEffect 依赖项记录助手
import { depsRecorderWithUEF } from 'yjr-utils';
/** 帮助记录 useEffect 每次更新是那些依赖改变了,也可单独使用,不依赖react框架 */
function Com({ a, b, c, d, e }) {
/**
* 创建一个depsRecorder
* 每个新的useEffect都要新建一个depsRecorder,depsRecorder不可共享
*/
const depsRecorder = useMemo(() => depsRecorderWithUEF(), []);
const depsRecorder2 = useMemo(() => depsRecorderWithUEF(), []);
const deps = [a, b, c, d, e];
const deps2 = [a, e];
useEffect(() => {
const [isFirstUpdate, changedList] = depsRecorder(deps);
console.log(isFirstUpdate, changedList);
if (changedList.includes(1)) {
/**
* 属性 b 改变时做些事情
*/
}
const mainArraySet = new Set([1, 2, 3]); // 代表 b c d 属性的下标
const allItemsExist = changedList.every((item) => mainArraySet.has(item));
if (allItemsExist) {
/**
* 属性 b c d 同时改变时做些事情
*/
}
const someItemsExist = changedList.some((item) => mainArraySet.has(item));
if (someItemsExist) {
/**
* 属性 b c d 任意一个发生改变时做些事情
*/
}
/**
* your other code
*/
}, deps);
useEffect(() => {
const [isFirstUpdate, changedList] = depsRecorder2(deps2);
/**
* your other code
*/
}, deps2);
return <div></div>;
}
// 举例:比如你的组件更新了3次,初始化一次
// 日志: true,[0,1,2,3,4] 首次 全部更新 (a b c d e)
<Com a={'你好'} b={666} c={true} d={[1, 2, 3]} e={{ a: 'aaa', b: 'bbb' }} />;
// 日志: false,[0,3,4] 第一次 下标为 0 3 4 的依赖发生了改变 ( a d e )
<Com a={'我不好'} b={666} c={true} d={[1, 2, 3]} e={{ a: 'aaa', b: 'bbb' }} />;
const arr = [1, 1, 1];
// 日志: false,[1,2,3,4] 第二次 下标为 1 2 3 4 的依赖发生了改变 ( b c d e )
<Com a={'我不好'} b={777} c={false} d={arr} e={{ a: 'aaa', b: 'bbb' }} />;
arr[1] = 100; // 改变成员
// 日志: false,[4] 第三次 下标为 4 的依赖发生了改变 ( e )
<Com a={'我不好'} b={777} c={false} d={arr} e={{ a: 'aaa', b: 'bbb' }} />;
35. Cookie 解析器
import { cookieParse } from 'yjr-utils';
const cookie = cookieParse();
// 访问某个cookie的值
cookie.hng; // zh-cn
cookie.sid; // "89c7xw19"
动画效果
仅 2.8.0 版本及以上支持,动画效果构建产物来自 Animate.css
yjrUtils 自带以下 9 种动画效果
1.fadeIn
2.fadeInLeft
3.fadeInRight
4.fadeInUp
5.flipInX
6.flipInY
7.rotateInDownLeft
8.rotateInDownRight
9.zoomIn
动画效果为可选,如需使用,引入该文件即可
import 'yjr-utils/yjrani.css';
1.通过类名使用
yjranimated 是固定前缀 动画效果为 yjr + 具体动画名
<div class="yjranimated yjrzoomIn">An animated element</div>
通过添加 yjrdelay 前缀来延迟动画 比如这里延迟 2 秒触发
<div class="yjranimated yjrzoomIn yjrdelay-2s">An animated element</div>
类似的还有控制速度和重复次数
<div class="yjranimated yjrzoomIn yjrfaster yjrrepeat-3">
An animated element
</div>
2.通过 @keyframes 方式使用
只需填入动画名即可使用动画效果
.className {
animation: zoomIn 0.5s ease 0s infinite;
}
3.自定义 CSS 变量
局部变量 改变 zoomIn 这个动画持续时间为 2s
.yjranimated.yjrzoomIn {
--animate-duration: 2s;
}
全局变量 所有动画效果都是延迟 900 毫秒且持续时间为 800 毫秒
:root {
--animate-duration: 800ms;
--animate-delay: 0.9s;
}
4.使用注意
为了确保动画不影响你原有的样式,建议每个动画元素都加上这句 css 代码
.demo {
animation-fill-mode: both;
}