UniApp/Vue2 通用工具函数库(完整版):覆盖校验、格式、业务全场景

在 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 配置页面,普通页面需用 navigateToredirectTo

  • 空值判断规则isEmpty 会过滤空字符串(含空格),符合表单输入场景的空值判定需求。

六、扩展建议

可根据项目业务需求,补充以下函数扩展工具库:

  • 身份证地址码、出生日期校验;

  • 密码强度校验(含大小写、特殊字符);

  • URL 参数解析/拼接;

  • 数组去重、对象数组排序;

  • UniApp 文件上传/下载封装。

七、总结

这套工具库整合了 UniApp/Vue2 开发中 80% 以上的基础工具需求,通过统一封装实现「一次编写、全局复用」,既减少重复代码,又保证项目代码风格一致。建议在新项目初始化时直接引入,后续根据业务逐步扩展,大幅提升开发效率和代码可维护性。

相关推荐
崔庆才丨静觅30 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax