npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ruan-feiyang/front-end-utils

v1.0.3

Published

前端常用工具库 - 集成浏览器判断、字符串处理、日期处理、对象处理、验证函数等常用工具

Downloads

111

Readme

@ruan-feiyang/front-end-utils

前端常用工具库 - 集成浏览器判断、字符串处理、日期处理、对象处理、验证函数等常用工具。

安装

npm install @ruan-feiyang/front-end-utils

使用方法

ES6 模块导入

// 方式1:按需导入特定模块
import { browser, string, date, validate, func, storage } from '@ruan-feiyang/front-end-utils';

// 方式2:导入所有模块(默认导出)
import utils from '@ruan-feiyang/front-end-utils';
// 使用示例:utils.browser.isChrome()

// 方式3:直接导入特定工具
import { isChrome, isMobile } from '@ruan-feiyang/front-end-utils/browser';
import { format, fromNow } from '@ruan-feiyang/front-end-utils/date';
import { trim, capitalize } from '@ruan-feiyang/front-end-utils/string';

CommonJS 模块导入

// 方式1:导入所有模块
const utils = require('@ruan-feiyang/front-end-utils');
// 使用示例:utils.browser.isChrome()

// 方式2:导入特定模块
const { browser, string, date } = require('@ruan-feiyang/front-end-utils');

浏览器直接使用(UMD)

<script src="https://unpkg.com/@ruan-feiyang/front-end-utils/dist/index.umd.js"></script>
<script>
  // 全局变量 window.frontEndUtils
  console.log(window.frontEndUtils.browser.isChrome());
  console.log(window.frontEndUtils.string.trim('  hello  '));
</script>

工具模块

browser - 浏览器判断

import { browser } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { isChrome, isMobile } from '@ruan-feiyang/front-end-utils/browser';

browser.isChrome()           // 判断是否为 Chrome 浏览器
browser.isFirefox()          // 判断是否为 Firefox 浏览器
browser.isSafari()           // 判断是否为 Safari 浏览器
browser.isEdge()             // 判断是否为 Edge 浏览器
browser.isIE()               // 判断是否为 IE 浏览器
browser.isMobile()           // 判断是否为移动端
browser.isWechat()           // 判断是否为微信浏览器
browser.isIOS()              // 判断是否为 iOS
browser.isAndroid()          // 判断是否为 Android
browser.getBrowserName()     // 获取浏览器名称: 'Chrome', 'Firefox', 'Safari', 'Edge', 'IE', 'Unknown'
browser.getBrowserVersion()  // 获取浏览器版本号

// 示例
if (browser.isChrome()) {
  console.log('您正在使用 Chrome 浏览器');
}
if (browser.isMobile()) {
  console.log('移动端设备');
}

string - 字符串处理

import { string } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { trim, capitalize } from '@ruan-feiyang/front-end-utils/string';

// 基本处理
string.trim('  hello  ')                      // 去除两端空白: 'hello'
string.trimAll('a  b   c')                    // 去除所有空白: 'abc'
string.escapeHtml('<div>test</div>')          // 转义 HTML: '&lt;div&gt;test&lt;/div&gt;'
string.unescapeHtml('&lt;div&gt;test&lt;/div&gt;') // 反转义 HTML: '<div>test</div>'

// 格式转换
string.capitalize('hello world')              // 首字母大写: 'Hello world'
string.camelCase('hello-world')               // 驼峰命名: 'helloWorld'
string.camelCase('hello_world test')          // 驼峰命名: 'helloWorldTest'
string.snakeCase('helloWorld')                // 下划线命名: 'hello_world'
string.kebabCase('helloWorld')                // 中划线命名: 'hello-world'

// 截断与处理
string.truncate('这是一段很长的文本需要截断', 10) // 截断: '这是一段很长...'
string.truncate('Short text', 20)             // 不截断: 'Short text'

// 脱敏处理
string.hideMobile('13812345678')              // 隐藏手机号: '138****5678'
string.maskMobile('13812345678')              // 默认中间脱敏: '138****5678'
string.maskMobile('13812345678', { mode: 'prefix' })     // 前置可见: '*******5678'
string.maskMobile('13812345678', { mode: 'suffix' })     // 后置可见: '138*******'
string.maskMobile('13812345678', { mode: 'all' })        // 全部脱敏: '***********'
string.maskMobile('13812345678', { mode: 'middle', visiblePrefix: 4, visibleSuffix: 3 }) // 自定义可见位数: '1381***678'
string.hideIdCard('110101199001011234')      // 隐藏身份证: '110101********1234'

// 示例
const userMobile = '13812345678';
console.log(`用户手机号:${string.hideMobile(userMobile)}`); // 用户手机号:138****5678

const htmlContent = '<script>alert("xss")</script>';
const safeContent = string.escapeHtml(htmlContent); // &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;

date - 日期处理

import { date } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { format, fromNow } from '@ruan-feiyang/front-end-utils/date';

// 日期格式化
date.format(new Date())                       // 默认格式: '2024-01-01 10:30:00'
date.format(new Date(), 'YYYY/MM/DD')         // 自定义格式: '2024/01/01'
date.format(new Date(), 'YYYY年MM月DD日 HH:mm') // 中文格式: '2024年01月01日 10:30'
date.format(1700000000000, 'YYYY-MM-DD')      // 时间戳格式化: '2023-11-15'

// 相对时间
date.fromNow(Date.now() - 3600000)            // '1小时前'
date.fromNow(Date.now() - 86400000)           // '1天前'
date.fromNow(Date.now() - 3000)               // '刚刚'

// 日期范围
date.getWeekStart()                           // 获取本周开始日期(周一)
date.getWeekStart(new Date('2024-01-15'))     // 获取指定日期所在周的开始日期
date.getMonthStart()                          // 获取本月开始日期
date.getMonthStart(new Date('2024-06-15'))    // 获取指定日期所在月的开始日期

// 日期比较
date.isSameDay(new Date('2024-01-01'), new Date('2024-01-01 14:30')) // true
date.isSameDay(new Date('2024-01-01'), new Date('2024-01-02'))        // false

// 示例
const now = new Date();
console.log(`当前时间:${date.format(now)}`);
console.log(`发布时间:${date.fromNow(now.getTime() - 7200000)}`); // 2小时前

const orderDate = new Date('2024-01-15 14:30:00');
if (date.isSameDay(orderDate, new Date())) {
  console.log('这是今天的订单');
}

object - 对象处理

import { object } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { deepClone, merge } from '@ruan-feiyang/front-end-utils/object';

// 深拷贝
const original = { a: 1, b: { c: 2 }, d: new Date() };
const cloned = object.deepClone(original);   // 完全独立的副本
console.log(cloned === original);           // false
console.log(cloned.b === original.b);       // false

// 合并对象
const base = { name: '张三', age: 25 };
const updated = object.merge(base, { age: 26, city: '北京' });
console.log(updated);                       // { name: '张三', age: 26, city: '北京' }

// 支持多个源对象
const user = { name: '张三' };
const result = object.merge(user, { age: 25 }, { city: '北京' }, { email: '[email protected]' });
console.log(result);                        // { name: '张三', age: 25, city: '北京', email: '[email protected]' }

// 获取嵌套值
const data = { user: { profile: { name: '张三', age: 25 } } };
object.get(data, 'user.profile.name')       // '张三'
object.get(data, 'user.profile.email')      // undefined
object.get(data, 'user.profile.email', '[email protected]') // '[email protected]'
object.get(data, 'user.address.city', '未知') // '未知'

// 设置嵌套值
const obj = {};
object.set(obj, 'user.profile.name', '张三');
console.log(obj.user.profile.name);         // '张三'

// 创建嵌套结构
const config = {};
object.set(config, 'database.host', 'localhost');
object.set(config, 'database.port', 3306);
object.set(config, 'app.name', 'MyApp');
console.log(config);
// {
//   database: { host: 'localhost', port: 3306 },
//   app: { name: 'MyApp' }
// }

// 示例
const originalUser = {
  id: 1,
  name: '张三',
  profile: {
    email: '[email protected]',
    address: {
      city: '北京'
    }
  }
};

// 安全修改
const modifiedUser = object.deepClone(originalUser);
object.set(modifiedUser, 'profile.address.city', '上海');
console.log(originalUser.profile.address.city); // '北京'(保持不变)
console.log(modifiedUser.profile.address.city); // '上海'

// 安全读取
const email = object.get(originalUser, 'profile.email', '未知邮箱');
const phone = object.get(originalUser, 'profile.phone', '未知电话');
console.log(email, phone); // '[email protected]', '未知电话'

validate - 验证函数

import { validate } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { isMobile, isEmail } from '@ruan-feiyang/front-end-utils/validate';

// 手机号验证
validate.isMobile('13812345678')              // true
validate.isMobile('02812345678')              // false(区号格式)
validate.isMobile('1381234567')               // false(位数不足)
validate.isMobile('19812345678')              // true(198号段)

// 邮箱验证
validate.isEmail('[email protected]')          // true
validate.isEmail('[email protected]') // true
validate.isEmail('test@example')              // false(缺少域名后缀)
validate.isEmail('test example.com')          // false(缺少@符号)

// 身份证验证
validate.isIdCard('110101199001011234')       // true(18位)
validate.isIdCard('11010119900101123X')       // true(末尾X)
validate.isIdCard('110101900101123')          // true(15位)
validate.isIdCard('11010119900101123')        // false(17位)

// URL 验证
validate.isUrl('https://example.com')         // true
validate.isUrl('http://www.example.com/path') // true
validate.isUrl('example.com')                 // true(自动补全协议)
validate.isUrl('ftp://example.com')           // false(仅支持 http/https)

// IP 地址验证
validate.isIPv4('192.168.1.1')                // true
validate.isIPv4('255.255.255.255')            // true
validate.isIPv4('192.168.1.256')              // false(超出范围)
validate.isIPv4('192.168.1')                  // false(格式错误)

// 中文名验证
validate.isChineseName('张三')                // true
validate.isChineseName('张三丰')              // true
validate.isChineseName('张')                  // false(太短)
validate.isChineseName('张三张三张三张三张') // false(太长)
validate.isChineseName('John')                // false(非中文)

// 密码强度验证
validate.checkPasswordStrength('123456')       // 'weak'(纯数字)
validate.checkPasswordStrength('abcdef')       // 'weak'(纯字母)
validate.checkPasswordStrength('Abc123')       // 'medium'(字母+数字,长度6)
validate.checkPasswordStrength('Abc123!')      // 'strong'(字母+数字+特殊字符,长度7)
validate.checkPasswordStrength('Abcdefg123!@#') // 'strong'(混合字符,长度12)

// 示例 - 表单验证
function validateUserForm(formData) {
  const errors = {};
  
  if (!formData.name || !validate.isChineseName(formData.name)) {
    errors.name = '请输入2-10位中文姓名';
  }
  
  if (!formData.mobile || !validate.isMobile(formData.mobile)) {
    errors.mobile = '请输入有效的手机号';
  }
  
  if (!formData.email || !validate.isEmail(formData.email)) {
    errors.email = '请输入有效的邮箱地址';
  }
  
  if (!formData.password) {
    errors.password = '请输入密码';
  } else {
    const strength = validate.checkPasswordStrength(formData.password);
    if (strength === 'weak') {
      errors.password = '密码强度太弱,请使用字母、数字和特殊字符组合';
    }
  }
  
  return { isValid: Object.keys(errors).length === 0, errors };
}

// 使用示例
const formData = {
  name: '张三',
  mobile: '13812345678',
  email: '[email protected]',
  password: 'Abc123!'
};

const result = validateUserForm(formData);
console.log(result.isValid); // true
console.log(result.errors); // {}

func - 函数工具

import { func } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { debounce, throttle } from '@ruan-feiyang/front-end-utils/func';

// 防抖(debounce)
// 在事件被触发n秒后执行函数,如果在这n秒内又被触发,则重新计时
const searchInput = document.getElementById('search');
const handleSearch = (event) => {
  console.log('搜索:', event.target.value);
  // 发送搜索请求...
};

const debouncedSearch = func.debounce(handleSearch, 300);
searchInput.addEventListener('input', debouncedSearch);

// 示例:输入框实时搜索,避免频繁请求
const searchApi = (keyword) => {
  console.log(`搜索关键词: ${keyword}`);
  // fetch(`/api/search?q=${keyword}`)...
};

const debouncedSearchApi = func.debounce(searchApi, 500);
document.getElementById('search-input').addEventListener('input', (e) => {
  debouncedSearchApi(e.target.value);
});

// 节流(throttle)
// 在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效
const handleScroll = () => {
  console.log('滚动位置:', window.scrollY);
};

const throttledScroll = func.throttle(handleScroll, 200);
window.addEventListener('scroll', throttledScroll);

// 示例:窗口resize事件
const handleResize = () => {
  console.log('窗口大小:', window.innerWidth, window.innerHeight);
  // 更新布局...
};

const throttledResize = func.throttle(handleResize, 100);
window.addEventListener('resize', throttledResize);

// 柯里化(curry)
// 将多参数的函数转换成一系列单参数函数
const add = (a, b, c) => a + b + c;
const curriedAdd = func.curry(add);

// 使用方式
const add5 = (b, c) => curriedAdd([5, b, c]);
console.log(add5(3, 4)); // 12

// 或直接调用
console.log(curriedAdd([1, 2, 3])); // 6

// 一次性函数(once)
// 确保函数只执行一次,后续调用返回undefined或第一次的结果
const initializeApp = () => {
  console.log('应用初始化完成');
  return 'initialized';
};

const initializeOnce = func.once(initializeApp);

console.log(initializeOnce()); // '应用初始化完成',返回 'initialized'
console.log(initializeOnce()); // undefined(不再执行)
console.log(initializeOnce()); // undefined

// 示例:支付按钮防重复点击
const handlePayment = () => {
  console.log('支付请求发送...');
  // 发送支付请求...
  return 'payment_sent';
};

const safePayment = func.once(handlePayment);

document.getElementById('pay-button').addEventListener('click', () => {
  const result = safePayment();
  if (result) {
    console.log('支付处理中...');
  } else {
    console.log('请勿重复点击');
  }
});

// 组合使用示例
class SearchComponent {
  constructor() {
    this.search = func.debounce(this._performSearch.bind(this), 300);
    this.initialize = func.once(this._initialize.bind(this));
  }
  
  _performSearch(keyword) {
    console.log(`执行搜索: ${keyword}`);
    // 实际搜索逻辑
  }
  
  _initialize() {
    console.log('组件初始化');
    // 初始化逻辑
  }
  
  onInput(keyword) {
    this.initialize(); // 只初始化一次
    this.search(keyword); // 防抖搜索
  }
}

// 使用
const searchComponent = new SearchComponent();
searchComponent.onInput('react'); // 初始化 + 防抖搜索
searchComponent.onInput('react hooks'); // 只触发防抖搜索

number - 数字处理

number.formatThousands(1234567)               // 千分位: '1,234,567'
number.padZero(5, 2)                          // 补零: '05'
number.round(3.14159, 2)                      // 四舍五入: 3.14
number.randomInt(1, 100)                     // 随机整数
number.toChinese(123)                        // 数字转中文: '一百二十三'

array - 数组处理

array.unique([1, 2, 2, 3])                    // 去重: [1, 2, 3]
array.shuffle([1, 2, 3])                     // 乱序
array.groupBy(items, 'category')              // 分组
array.sortBy(items, 'age', 'asc')             // 排序
array.flat([1, [2, 3]], 1)                   // 扁平化
array.difference([1, 2, 3], [2])             // 差集: [1, 3]
array.intersection([1, 2, 3], [2, 3])         // 交集: [2, 3]

storage - localStorage

import { storage } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { set, get } from '@ruan-feiyang/front-end-utils/storage';

// 设置数据(自动 JSON 序列化)
storage.set('user', { name: '张三', age: 25 });
storage.set('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
storage.set('settings', { theme: 'dark', language: 'zh-CN' });

// 获取数据(自动 JSON 反序列化)
const user = storage.get('user');           // { name: '张三', age: 25 }
const token = storage.get('token');         // 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
const settings = storage.get('settings');   // { theme: 'dark', language: 'zh-CN' }

// 获取不存在的键(返回默认值)
const cart = storage.get('cart', []);       // [](默认值)
const history = storage.get('history');     // null(无默认值)

// 检查是否存在
if (storage.has('user')) {
  console.log('用户信息已保存');
}

// 删除数据
storage.remove('token');                    // 删除 token
storage.remove('tempData');                 // 删除临时数据

// 清空所有数据
// storage.clear();                         // 谨慎使用,会清空所有 localStorage

// 示例:用户会话管理
class UserSession {
  private static readonly USER_KEY = 'user_session';
  private static readonly TOKEN_KEY = 'auth_token';
  
  static login(userData: { id: number; name: string; email: string }, token: string) {
    storage.set(this.USER_KEY, userData);
    storage.set(this.TOKEN_KEY, token);
  }
  
  static logout() {
    storage.remove(this.USER_KEY);
    storage.remove(this.TOKEN_KEY);
  }
  
  static getCurrentUser() {
    return storage.get<{ id: number; name: string; email: string }>(this.USER_KEY);
  }
  
  static getToken() {
    return storage.get<string>(this.TOKEN_KEY);
  }
  
  static isLoggedIn() {
    return storage.has(this.USER_KEY) && storage.has(this.TOKEN_KEY);
  }
}

// 使用示例
UserSession.login(
  { id: 1, name: '张三', email: '[email protected]' },
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
);

console.log(UserSession.isLoggedIn());      // true
console.log(UserSession.getCurrentUser());  // { id: 1, name: '张三', email: '[email protected]' }

UserSession.logout();
console.log(UserSession.isLoggedIn());      // false

// 示例:购物车管理
class ShoppingCart {
  private static readonly CART_KEY = 'shopping_cart';
  
  static addItem(item: { id: number; name: string; price: number; quantity: number }) {
    const cart = storage.get<Array<{ id: number; name: string; price: number; quantity: number }>>(this.CART_KEY, []);
    const existingItem = cart.find(i => i.id === item.id);
    
    if (existingItem) {
      existingItem.quantity += item.quantity;
    } else {
      cart.push(item);
    }
    
    storage.set(this.CART_KEY, cart);
    return cart;
  }
  
  static removeItem(itemId: number) {
    const cart = storage.get<Array<{ id: number; name: string; price: number; quantity: number }>>(this.CART_KEY, []);
    const filteredCart = cart.filter(item => item.id !== itemId);
    storage.set(this.CART_KEY, filteredCart);
    return filteredCart;
  }
  
  static getCart() {
    return storage.get<Array<{ id: number; name: string; price: number; quantity: number }>>(this.CART_KEY, []);
  }
  
  static clearCart() {
    storage.set(this.CART_KEY, []);
  }
  
  static getTotal() {
    const cart = this.getCart();
    return cart.reduce((total, item) => total + (item.price * item.quantity), 0);
  }
}

// 使用示例
ShoppingCart.addItem({ id: 1, name: '商品A', price: 100, quantity: 2 });
ShoppingCart.addItem({ id: 2, name: '商品B', price: 200, quantity: 1 });

console.log(ShoppingCart.getCart());
// [
//   { id: 1, name: '商品A', price: 100, quantity: 2 },
//   { id: 2, name: '商品B', price: 200, quantity: 1 }
// ]

console.log(`总价:${ShoppingCart.getTotal()}`); // 总价:400

ShoppingCart.removeItem(1);
console.log(ShoppingCart.getCart()); // [{ id: 2, name: '商品B', price: 200, quantity: 1 }]

sessionStorage - 会话存储

sessionStorage.set('key', value)           // 设置
sessionStorage.get('key')                    // 获取
sessionStorage.remove('key')                // 删除
sessionStorage.clear()                      // 清空
sessionStorage.has('key')                   // 是否存在

cache - 内存缓存

cache.set('key', value, ttl)                 // 设置缓存,ttl=秒数
cache.get('key')                             // 获取
cache.remove('key')                         // 删除
cache.clear()                               // 清空
cache.has('key')                             // 是否存在
cache.keys()                               // 所有缓存键
cache.cleanup()                             // 清理过期缓存

withCache - 带缓存的异步函数

const data = await withCache('key', () => fetchApi(), 300)
// 自动缓存结果,避免重复请求

cacheBatch - 批量缓存操作

cacheBatch.getMultiple(['key1', 'key2'])   // 批量获取
cacheBatch.setMultiple({ k1: v1, k2: v2 })  // 批量设置
cacheBatch.removeMultiple(['key1'])         // 批量删除

cookie

cookie.set('name', 'value', 7)              // 设置
cookie.get('name')                         // 获取
cookie.remove('name')                      // 删除

其他工具

copyToClipboard('text')                      // 复制到剪贴板
downloadFile('content', 'file.txt')          // 下载文件
formatMoney(1234.56)                        // 金额格式化: '¥1,234.56'
formatFileSize(1024 * 1024)                 // 文件大小: '1.00 MB'
getFileExtension('file.txt')                 // 获取扩展名: 'txt'
generateUUID()                              // 生成 UUID
sleep(1000)                                // 等待指定毫秒

url - URL 工具

import { url } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { encode, decode } from '@ruan-feiyang/front-end-utils/url';

// URL 编码
url.encode('测试 & 数据')                   // 编码: '%E6%B5%8B%E8%AF%95%20%26%20%E6%95%B0%E6%8D%AE'

// URL 解码
url.decode('%E6%B5%8B%E8%AF%95')           // 解码: '测试'

// 解析 URL 参数
url.parseParams('https://example.com?name=张三&age=25') // { name: '张三', age: '25' }

// 构建 URL 参数
url.buildParams({ name: '张三', age: '25' }) // 'name=%E5%BC%A0%E4%B8%89&age=25'

// 获取 URL 中的指定参数
url.getParam('name', 'https://example.com?name=张三&age=25') // '张三'

// 从 URL 中移除指定参数
url.removeParams('https://example.com?name=张三&age=25', ['age']) // 'https://example.com?name=张三'

// 示例:处理 URL 参数
const currentUrl = window.location.href;
const params = url.parseParams(currentUrl);
console.log('当前页面参数:', params);

// 构建带参数的 URL
const baseUrl = 'https://api.example.com';
const queryParams = { page: '1', limit: '10', keyword: '测试' };
const fullUrl = `${baseUrl}?${url.buildParams(queryParams)}`;
console.log('完整 URL:', fullUrl);

page - 页面工具

page.scrollToTop()                          // 滚动到顶部
page.goBack()                             // 回到上一页
page.reload()                            // 刷新页面
page.getQueryParam('id')                  // 获取 URL 参数
page.getAllQueryParams()                  // 获取所有 URL 参数
page.getHash()                           // 获取锚点

device - 设备工具

import { device } from '@ruan-feiyang/front-end-utils';
// 或直接导入:import { getNetworkType, isTouchDevice } from '@ruan-feiyang/front-end-utils/device';

// 获取网络类型
device.getNetworkType()                    // 'wifi', '4g', '3g', '2g', 'unknown'
// 注意:需要浏览器支持 navigator.connection

// 检测触摸设备
device.isTouchDevice()                     // true(支持触屏)/ false

// 获取设备像素比
device.getDevicePixelRatio()               // 1, 1.5, 2, 3(Retina 显示)

// 获取屏幕尺寸
device.getScreenWidth()                    // 屏幕宽度(像素)
device.getScreenHeight()                   // 屏幕高度(像素)

// 获取窗口尺寸
device.getWindowWidth()                    // 可视区域宽度(像素)
device.getWindowHeight()                   // 可视区域高度(像素)

// 示例:响应式设计
function checkDeviceCapabilities() {
  const capabilities = {
    isMobile: device.isTouchDevice() && device.getScreenWidth() < 768,
    isTablet: device.isTouchDevice() && device.getScreenWidth() >= 768 && device.getScreenWidth() < 1024,
    isDesktop: !device.isTouchDevice() || device.getScreenWidth() >= 1024,
    pixelRatio: device.getDevicePixelRatio(),
    networkType: device.getNetworkType(),
    screenSize: {
      width: device.getScreenWidth(),
      height: device.getScreenHeight()
    },
    windowSize: {
      width: device.getWindowWidth(),
      height: device.getWindowHeight()
    }
  };
  
  return capabilities;
}

// 使用示例
const caps = checkDeviceCapabilities();
if (caps.isMobile) {
  console.log('移动端设备,启用移动端优化');
  // 加载移动端组件...
} else if (caps.isTablet) {
  console.log('平板设备,启用平板布局');
  // 加载平板组件...
} else {
  console.log('桌面端设备,启用完整功能');
  // 加载桌面端组件...
}

// 根据像素比优化图片
if (caps.pixelRatio >= 2) {
  console.log('高分辨率屏幕,加载高清图片');
  // img.src = '[email protected]';
} else {
  console.log('普通分辨率屏幕,加载普通图片');
  // img.src = 'image.png';
}

// 根据网络类型优化加载策略
if (caps.networkType === '4g' || caps.networkType === 'wifi') {
  console.log('高速网络,加载高质量资源');
  // 加载高清视频、大图等
} else {
  console.log('低速网络,加载轻量资源');
  // 加载低质量图片、压缩资源等
}

更多工具模块

除了上述主要模块外,库还包含以下实用工具:

数组处理 (array)

  • array.unique() - 数组去重
  • array.shuffle() - 数组乱序
  • array.groupBy() - 按属性分组
  • array.sortBy() - 按属性排序
  • array.flat() - 数组扁平化
  • array.difference() - 数组差集
  • array.intersection() - 数组交集

数字处理 (number)

  • number.formatThousands() - 千分位格式化
  • number.padZero() - 数字补零
  • number.round() - 四舍五入
  • number.randomInt() - 随机整数
  • number.toChinese() - 数字转中文

Cookie 操作 (cookie)

  • cookie.set() - 设置 Cookie
  • cookie.get() - 获取 Cookie
  • cookie.remove() - 删除 Cookie

缓存管理 (cache)

  • cache.set() - 设置内存缓存
  • cache.get() - 获取缓存
  • cache.remove() - 删除缓存
  • cache.clear() - 清空缓存
  • cache.has() - 检查缓存是否存在
  • cache.keys() - 获取所有缓存键
  • cache.cleanup() - 清理过期缓存
  • withCache() - 带缓存的异步函数
  • cacheBatch - 批量缓存操作

页面工具 (page)

  • page.scrollToTop() - 滚动到顶部
  • page.goBack() - 回到上一页
  • page.reload() - 刷新页面
  • page.getQueryParam() - 获取 URL 参数
  • page.getAllQueryParams() - 获取所有 URL 参数
  • page.getHash() - 获取锚点

URL 工具 (url)

  • url.encode() - URL 编码
  • url.decode() - URL 解码
  • url.parseParams() - 解析 URL 参数
  • url.buildParams() - 构建 URL 参数
  • url.getParam() - 获取 URL 中的指定参数
  • url.removeParams() - 从 URL 中移除指定参数

杂项工具 (misc)

  • copyToClipboard() - 复制到剪贴板
  • downloadFile() - 下载文件
  • formatMoney() - 金额格式化
  • formatFileSize() - 文件大小格式化
  • getFileExtension() - 获取文件扩展名
  • generateUUID() - 生成 UUID
  • sleep() - 等待指定毫秒

TypeScript 支持

本库完全使用 TypeScript 编写,提供完整的类型定义:

import { browser, string, date } from '@ruan-feiyang/front-end-utils';

// 类型安全的使用
const isChrome: boolean = browser.isChrome();
const trimmed: string = string.trim('  hello  ');
const formattedDate: string = date.format(new Date());

// 泛型支持
interface User {
  id: number;
  name: string;
  email: string;
}

const user: User = { id: 1, name: '张三', email: '[email protected]' };
const clonedUser: User = object.deepClone(user);

开发指南

本地开发

# 克隆仓库
git clone <repository-url>
cd front_end_utils

# 安装依赖
npm install

# 开发模式(监听文件变化)
npm run dev

# 构建生产版本
npm run build

# 运行测试
npm test

项目结构

src/
├── index.ts          # 主入口文件,导出所有模块
├── browser.ts        # 浏览器判断工具
├── string.ts         # 字符串处理工具
├── date.ts           # 日期处理工具
├── object.ts         # 对象处理工具
├── validate.ts       # 验证函数工具
├── func.ts           # 函数工具
├── number.ts         # 数字处理工具
├── array.ts          # 数组处理工具
├── storage.ts        # localStorage 工具
├── sessionStorage.ts # sessionStorage 工具
├── cache.ts          # 缓存管理工具
├── cookie.ts         # Cookie 操作工具
├── misc.ts           # 杂项工具
├── page.ts           # 页面工具
├── device.ts         # 设备工具
└── url.ts            # URL 工具

添加新工具

  1. src/ 目录下创建新的模块文件
  2. 实现工具函数并导出
  3. src/index.ts 中导出新模块
  4. 运行测试确保功能正常
  5. 更新 README.md 文档

构建与发布

构建项目

npm run build

构建产物位于 dist/ 目录,包含:

  • CommonJS 格式 (.js)
  • ES Module 格式 (.esm.js)
  • TypeScript 类型定义 (.d.ts)

发布到 npm

# 登录 npm
npm login

# 更新版本号
npm version patch  # 或 minor、major

# 发布
npm publish --access public

测试

项目使用 Jest 进行单元测试:

# 运行所有测试
npm test

# 运行特定测试文件
npm test -- string.test.ts

# 查看测试覆盖率
npm test -- --coverage

贡献指南

  1. Fork 项目仓库
  2. 创建功能分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add some amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 创建 Pull Request

许可证

MIT License

联系方式