在 UniApp/Vue2 开发中,重复编写基础工具函数是低效且易出错的行为。本文整理了一套「一站式通用工具库」,涵盖数据校验、格式转换、通用工具、UniApp 业务辅助四大核心模块,所有函数均经过实战验证,可直接复制到项目中使用,大幅提升开发效率。
一、工具库核心优势
-
全场景覆盖:聚焦前端高频需求,从表单校验到业务封装,无需额外补充基础函数;
-
适配性强:专为 UniApp/Vue2 设计,兼容小程序、APP、H5 多端运行环境;
-
调用灵活:支持全局挂载(组件内直接调用)和局部引入(纯 JS 文件按需使用);
-
健壮性佳:做了参数兼容、异常处理,避免空值、格式错误导致的页面崩溃。
二、完整代码(validate.js)
建议放在项目 utils/ 目录下,作为全局工具库统一维护。
javascript
/**
* UniApp/Vue2 通用工具函数库
* 模块:数据校验、格式转换、通用工具、UniApp业务辅助
* 用法:全局挂载后组件内 this.$validate.xxx() 调用
*/
// ======================== 一、数据校验类 ========================
/**
* 验证金额格式(最多两位小数,支持纯0、整数、合法小数)
* @param {String/Number} money 金额
* @returns {Boolean} 是否合法
*/
export function isMoney(money) {
const reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
return reg.test(money);
}
/**
* 验证中国大陆11位手机号
* @param {String/Number} phone 手机号
* @returns {Boolean} 是否合法
*/
export function checkPhone(phone) {
const reg = /^1(3|4|5|6|7|8|9)\d{9}$/;
return reg.test(phone);
}
/**
* 验证邮箱格式(支持字母、数字、下划线、中划线)
* @param {String} email 邮箱地址
* @returns {Boolean} 是否合法
*/
export function checkEmail(email) {
const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
return reg.test(email);
}
/**
* 验证18位身份证号(含校验位,提升准确性)
* @param {String} idCard 身份证号
* @returns {Boolean} 是否合法
*/
export function checkIdCard(idCard) {
const reg = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
if (!reg.test(idCard)) return false;
// 校验位验证逻辑
const factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const checkCode = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
const idCardArr = idCard.split('');
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += idCardArr[i] * factor[i];
}
const check = sum % 11;
return checkCode[check].toUpperCase() === idCardArr[17].toUpperCase();
}
/**
* 验证6位数字验证码
* @param {String/Number} code 验证码
* @returns {Boolean} 是否合法
*/
export function checkVerifyCode(code) {
const reg = /^\d{6}$/;
return reg.test(code);
}
/**
* 校验纯数字(可指定小数位数,默认不限)
* @param {String/Number} num 数字
* @param {Number} decimal 小数位数(-1=不限,0=仅整数)
* @returns {Boolean} 是否合法
*/
export function checkNumber(num, decimal = -1) {
if (decimal === -1) {
return /^[0-9]+(\.[0-9]+)?$/.test(num);
} else if (decimal === 0) {
return /^[0-9]+$/.test(num);
} else {
const reg = new RegExp(`^[0-9]+(\\.[0-9]{1,${decimal}})?$`);
return reg.test(num);
}
}
// ======================== 二、格式转换类 ========================
/**
* 时间戳转指定格式日期(支持秒/毫秒级时间戳)
* @param {Number} timestamp 时间戳
* @param {String} format 格式(默认 YYYY-MM-DD HH:mm:ss)
* @returns {String} 格式化日期
*/
export function formatTime(timestamp, format = 'YYYY-MM-DD HH:mm:ss') {
if (!timestamp) return '';
// 秒级时间戳转毫秒
if (timestamp.toString().length === 10) timestamp *= 1000;
const date = new Date(timestamp);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return format.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
}
/**
* 金额分转元(保留两位小数,适配后端分单位存储)
* @param {Number/String} fen 金额(分)
* @returns {String} 金额(元)
*/
export function fenToYuan(fen) {
if (!fen) return '0.00';
return (Number(fen) / 100).toFixed(2);
}
/**
* 金额元转分(去除小数位,避免精度问题)
* @param {Number/String} yuan 金额(元)
* @returns {Number} 金额(分)
*/
export function yuanToFen(yuan) {
if (!yuan) return 0;
return Math.round(Number(yuan) * 100);
}
/**
* 金额千分位格式化(提升视觉体验)
* @param {Number/String} money 金额
* @param {Number} decimal 小数位数(默认2)
* @returns {String} 千分位格式金额
*/
export function formatMoney(money, decimal = 2) {
if (!money) return '0.00';
const num = Number(money).toFixed(decimal);
return num.replace(/\d(?=(\d{3})+\.)/g, '$&,');
}
// ======================== 三、通用工具类 ========================
/**
* 函数防抖(高频触发仅执行最后一次,如按钮点击、输入框搜索)
* @param {Function} fn 目标函数
* @param {Number} delay 延迟时间(毫秒,默认500)
* @returns {Function} 防抖后函数
*/
export const Debounce = (fn, delay = 500) => {
let timer = null;
return function () {
const args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, delay);
};
};
/**
* 函数节流(固定间隔仅执行一次,如滚动加载、resize事件)
* @param {Function} fn 目标函数
* @param {Number} delay 间隔时间(毫秒,默认500)
* @returns {Function} 节流后函数
*/
export const Throttle = (fn, delay = 500) => {
let timer = null;
return function () {
const args = arguments;
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, delay);
}
};
};
/**
* 深拷贝(支持对象/数组/日期/正则,避免引用修改问题)
* @param {Any} obj 待拷贝数据
* @returns {Any} 拷贝后新数据
*/
export function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const cloneObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
/**
* 精准判断数据类型(比 typeof 更全面)
* @param {Any} data 待判断数据
* @returns {String} 数据类型(如 array、object、number)
*/
export function getType(data) {
return Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
}
/**
* 判断空值(覆盖 undefined/null/空字符串/空数组/空对象)
* @param {Any} data 待判断数据
* @returns {Boolean} 是否为空
*/
export function isEmpty(data) {
const type = getType(data);
if (type === 'undefined' || type === 'null') return true;
if (type === 'string') return data.trim() === '';
if (type === 'array') return data.length === 0;
if (type === 'object') return Object.keys(data).length === 0;
return false;
}
/**
* 生成随机字符串(验证码、唯一标识场景可用)
* @param {Number} length 长度(默认6)
* @param {Boolean} onlyNumber 是否仅数字(默认false)
* @returns {String} 随机字符串
*/
export function randomStr(length = 6, onlyNumber = false) {
const chars = onlyNumber
? '0123456789'
: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let str = '';
for (let i = 0; i < length; i++) {
str += chars[Math.floor(Math.random() * chars.length)];
}
return str;
}
// ======================== 四、UniApp业务辅助类 ========================
/**
* 图片路径转换(兼容网络路径、本地路径)
* @param {String} path 图片路径
* @returns {String} 转换后路径
*/
export function formatImagePath(path) {
if (!path) return '';
// 网络路径直接返回
if (path.startsWith('http://') || path.startsWith('https://')) return path;
// 本地路径转绝对路径(UniApp专用)
return uni.resolveLocalFileSystemURL ? uni.resolveLocalFileSystemURL(path) : path;
}
/**
* 页面跳转封装(避免重复跳转、适配tabBar页面)
* @param {String} url 跳转地址(如 /pages/home/index)
* @param {String} type 跳转方式(navigateTo/redirectTo/switchTab,默认navigateTo)
*/
export function navigateTo(url, type = 'navigateTo') {
const pages = getCurrentPages();
const currentPath = pages[pages.length - 1].route;
// switchTab 仅适配tabBar页面
if (type === 'switchTab') {
uni.switchTab({ url });
return;
}
// 避免跳转到当前页面
if (currentPath === url.replace(/^\//, '')) return;
// 执行跳转
uni[type]({ url });
}
/**
* 提示框封装(统一样式,防止触摸穿透)
* @param {String} title 提示文字
* @param {String} icon 图标(none/success/loading,默认none)
* @param {Number} duration 显示时长(默认2000毫秒)
*/
export function showToast(title, icon = 'none', duration = 2000) {
uni.showToast({
title,
icon,
duration,
mask: true // 透明蒙层,防止触发下层事件
});
}
三、全局挂载配置(Vue2)
在项目入口文件 main.js 中挂载,实现组件内无需引入直接调用。
javascript
import Vue from 'vue';
import App from './App';
// 引入工具函数库
import * as validate from '@/utils/validate.js';
// 挂载到Vue原型链(核心配置)
Vue.prototype.$validate = validate;
Vue.config.productionTip = false;
App.mpType = 'app';
const app = new Vue({
...App
});
app.$mount();
四、详细使用指南
4.1 调用方式
方式1:全局调用(推荐,组件内)
挂载后,所有 Vue 组件内可直接通过 this.$validate.函数名() 调用,无需重复引入。
javascript
// 组件内使用示例
this.$validate.checkPhone('13800138000'); // 校验手机号
this.$validate.formatTime(Date.now()); // 时间戳转日期
this.$validate.showToast('操作成功', 'success'); // 显示提示
方式2:局部引入(纯JS文件/按需使用)
在纯 JS 文件(如请求拦截器 request.js)中,按需引入所需函数即可。
javascript
// 按需引入
import { checkEmail, Debounce } from '@/utils/validate.js';
// 纯JS文件中调用
const isLegal = checkEmail('test@163.com');
const debounceFn = Debounce(() => { console.log('防抖执行'); }, 800);
4.2 核心函数实战示例
以下是开发中高频场景的使用案例,覆盖表单校验、数据处理、交互封装三大场景。
场景1:表单提交校验
javascript
// 表单提交方法
submitForm() {
const { phone, email, money } = this;
// 手机号校验
if (!this.$validate.checkPhone(phone)) {
this.$validate.showToast('请输入合法手机号');
return;
}
// 邮箱校验
if (!this.$validate.checkEmail(email)) {
this.$validate.showToast('邮箱格式错误');
return;
}
// 金额校验
if (!this.$validate.isMoney(money)) {
this.$validate.showToast('金额最多保留两位小数');
return;
}
// 校验通过,执行接口提交
this.submitApi();
}
场景2:防抖/节流使用
javascript
methods: {
// 按钮防重复点击(防抖,800ms内仅执行最后一次)
handleSubmit: this.$validate.Debounce(function() {
this.$validate.showToast('提交中...');
this.submitOrder();
}, 800),
// 页面滚动加载(节流,500ms内仅执行一次)
onScroll: this.$validate.Throttle(function() {
if (this.isLoading) return;
this.loadMoreData();
}, 500),
// 输入框实时搜索(防抖,500ms后执行搜索)
search: this.$validate.Debounce(function() {
if (this.$validate.isEmpty(this.keyword)) {
this.$validate.showToast('请输入搜索关键词');
return;
}
this.getSearchResult();
}, 500)
}
场景3:数据格式处理
javascript
// 1. 时间戳转日期(自定义格式)
const createTime = this.$validate.formatTime(1735660800000, 'YYYY-MM-DD'); // 2025-01-01
// 2. 金额分转元 + 千分位格式化(适配后端分单位)
const amountFen = 123456;
const amountYuan = this.$validate.fenToYuan(amountFen); // "1234.56"
const formatAmount = this.$validate.formatMoney(amountYuan); // "1,234.56"
// 3. 深拷贝对象(避免引用修改原数据)
const original = { name: '张三', age: 25 };
const clone = this.$validate.deepClone(original);
clone.age = 30;
console.log(original.age); // 25(原数据未修改)
// 4. 生成6位数字验证码
const code = this.$validate.randomStr(6, true); // 如 "689543"
场景4:UniApp 业务交互
javascript
// 1. 页面跳转(避免重复跳转)
this.$validate.navigateTo('/pages/detail/index'); // 普通跳转
this.$validate.navigateTo('/pages/home/index', 'switchTab'); // tabBar页面跳转
// 2. 图片路径处理(兼容多端)
const imgPath = this.$validate.formatImagePath('/static/img/logo.png');
// 3. 统一提示框
this.$validate.showToast('操作成功', 'success'); // 成功提示
this.$validate.showToast('加载中...', 'loading'); // 加载提示
五、注意事项
-
防抖/节流 this 指向 :内部通过
fn.apply(this, args)绑定组件实例,无需额外处理 this 指向问题; -
金额校验扩展 :默认不支持负数,若需适配负数场景,可修改
isMoney正则为/^(^-?[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^-?0$)|(^-?0\.[0-9]([0-9])?$)/; -
身份证校验范围:仅做格式+校验位验证,若需精准校验地址码、出生日期,可扩展对应逻辑;
-
页面跳转限制 :
switchTab仅支持 tabBar 配置页面,普通页面需用navigateTo或redirectTo; -
空值判断规则 :
isEmpty会过滤空字符串(含空格),符合表单输入场景的空值判定需求。
六、扩展建议
可根据项目业务需求,补充以下函数扩展工具库:
-
身份证地址码、出生日期校验;
-
密码强度校验(含大小写、特殊字符);
-
URL 参数解析/拼接;
-
数组去重、对象数组排序;
-
UniApp 文件上传/下载封装。
七、总结
这套工具库整合了 UniApp/Vue2 开发中 80% 以上的基础工具需求,通过统一封装实现「一次编写、全局复用」,既减少重复代码,又保证项目代码风格一致。建议在新项目初始化时直接引入,后续根据业务逐步扩展,大幅提升开发效率和代码可维护性。