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

相关推荐
GGGG寄了2 小时前
HTML——图像标签及多媒体标签
前端·html
小小码农Come on2 小时前
QPushButton QSS(一):按钮常用qss
前端·javascript·css·qt5
Booksort2 小时前
React+js环境配置(极速版)
前端·javascript·react.js
YAY_tyy2 小时前
Cesium 基础:地球场景初始化与视角控制
前端·cesium
椰羊~王小美2 小时前
前后端 格式化货币的方法
java·前端
苯酸氨酰糖化物2 小时前
HTML+CSS学信网学籍学历查询页面-支持任意修改内容信息
前端·css3·html5·娱乐
幻云20102 小时前
Next.js 之道:从入门到精通
前端·javascript·vue.js·人工智能·python
2501_944521592 小时前
Flutter for OpenHarmony 微动漫App实战:标签筛选功能实现
android·开发语言·前端·javascript·flutter
2501_915909062 小时前
在无需越狱的前提下如何对 iOS 设备进行文件管理与数据导出
android·macos·ios·小程序·uni-app·cocoa·iphone