30分钟掌握Layui工具函数扩展:从自定义方法到插件开发
你是否还在为重复编写日期格式化、数据验证等基础功能而烦恼?是否希望在Layui项目中拥有更灵活的工具函数库?本文将带你从零开始掌握Layui工具函数扩展技巧,通过实用场景案例,让你在30分钟内学会自定义工具方法与插件开发,显著提升开发效率。
读完本文你将学到:
- 如何安全扩展Layui原生工具函数
- 自定义工具方法的3种实现方式
- 开发可复用插件的完整流程
- 5个实用扩展案例(含代码模板)
- 扩展功能的调试与维护技巧
Layui工具函数体系概览
Layui提供了基础但强大的工具函数模块util,位于src/modules/util.js,包含日期处理、DOM操作、事件管理等核心功能。其模块化结构如下:
// 核心工具函数模块结构
layui.define(['lay', 'i18n', 'jquery'], function(exports) {
var util = {
fixbar: function(){}, // 固定工具栏
countdown: function(){}, // 倒计时功能
timeAgo: function(){}, // 时间格式化
digit: function(){}, // 数字补零
toDateString: function(){}, // 日期格式化
// ...更多原生方法
};
exports('util', util); // 对外暴露
});
原生工具函数虽覆盖常用场景,但在实际开发中仍存在扩展需求。Layui提供了两种安全扩展方式:方法扩展(适合单项目)和插件开发(适合多项目复用)。
自定义工具方法:3种实用扩展方式
1. 直接扩展util对象(简单场景)
在项目初始化时通过layui.util直接添加方法,适合简单功能扩展:
// 在入口文件中扩展(如examples/extends/index.js)
layui.use('util', function(){
var util = layui.util;
// 添加数组去重方法
util.uniqueArray = function(arr) {
return [...new Set(arr)];
};
// 添加数据深拷贝方法
util.deepClone = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
// 使用示例
var testArr = [1, 2, 2, 3];
console.log(util.uniqueArray(testArr)); // 输出 [1,2,3]
});
这种方式优势在于简单直接,无需额外配置,但缺点是会污染原生对象,升级Layui版本时需注意兼容性。
2. 封装独立工具模块(推荐)
创建独立工具模块,通过Layui模块化规范对外暴露,避免全局污染。在examples/extends/目录下创建tools.js:
// 自定义工具模块 examples/extends/tools.js
layui.define(['util'], function(exports) {
var util = layui.util;
var customTools = {
// 扩展日期格式化:支持季度显示
formatDateWithQuarter: function(time) {
var date = new Date(time);
var quarter = Math.floor((date.getMonth() + 3) / 3);
return util.toDateString(time, 'yyyy年') + '第' + quarter + '季度';
},
// 金额格式化:分转元并添加千分位
formatMoney: function(amount) {
return '¥' + (amount / 100).toFixed(2).replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,');
}
};
exports('customTools', customTools); // 暴露模块
});
使用时通过layui.use加载:
// 使用自定义工具模块
layui.use('customTools', function(){
var customTools = layui.customTools;
console.log(customTools.formatDateWithQuarter(new Date())); // 输出 "2025年第1季度"
console.log(customTools.formatMoney(1234567)); // 输出 "¥12,345.67"
});
3. 继承扩展法(高级场景)
通过原型继承创建新工具类,保留原生方法并添加新功能:
// 继承扩展示例
layui.define(['util'], function(exports) {
var util = layui.util;
// 创建继承自util的新对象
var advancedUtil = Object.create(util);
// 重写原生方法
advancedUtil.timeAgo = function(time) {
// 先调用原生方法
var result = util.timeAgo(time);
// 添加自定义逻辑:超过3年显示具体年份
if (new Date().getTime() - new Date(time).getTime() > 1000*60*60*24*365*3) {
return new Date(time).getFullYear() + '年';
}
return result;
};
exports('advancedUtil', advancedUtil);
});
开发Layui工具插件:从编码到发布
插件目录结构
遵循Layui插件开发规范,创建标准目录结构:
examples/extends/
├── mod1.js // 插件模块1
├── mod2.js // 插件模块2
├── test/ // 测试目录
│ ├── test1.js // 测试用例1
│ └── test2.js // 测试用例2
└── index.js // 插件入口
完整插件示例:数据验证工具
创建表单数据验证插件examples/extends/validator.js:
/**
* 数据验证插件
* 支持常见表单验证规则
*/
layui.define(['jquery'], function(exports) {
var $ = layui.$;
// 默认验证规则
var rules = {
required: [/^[\s\S]+$/, '必填项不能为空'],
email: [/^[\w.-]+@[\w-]+(\.\w{2,})+$/, '请输入有效的邮箱地址'],
mobile: [/^1[3-9]\d{9}$/, '请输入有效的手机号'],
url: [/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([\/\w .-]*)*\/?$/, '请输入有效的URL'],
number: [/^\d+$/, '请输入数字'],
min: function(len) {
return [new RegExp('^.{'+len+',}$'), '至少输入' + len + '个字符'];
}
};
var Validator = function(options) {
this.options = $.extend({
form: null, // 表单选择器
rules: {}, // 验证规则
messages: {}, // 自定义提示
success: function(){}// 验证通过回调
}, options);
this.init();
};
Validator.prototype = {
init: function() {
var that = this;
$(this.options.form).on('submit', function(e) {
e.preventDefault();
if (that.validate()) {
that.options.success();
}
});
},
validate: function() {
var that = this;
var isValid = true;
// 遍历验证规则
$.each(this.options.rules, function(field, rule) {
var $elem = $(that.options.form).find('[name="' + field + '"]');
var value = $elem.val().trim();
var ruleName = rule;
var ruleParams = [];
// 处理带参数的规则(如min:6)
if (typeof rule === 'object') {
ruleName = Object.keys(rule)[0];
ruleParams = Array.isArray(rule[ruleName]) ? rule[ruleName] : [rule[ruleName]];
}
// 获取验证规则和提示信息
var ruleConfig = rules[ruleName];
var message = that.options.messages[field] || (ruleConfig[1] || '验证失败');
// 执行验证
if (ruleConfig) {
var result;
if (typeof ruleConfig === 'function') {
var ruleFunc = ruleConfig.apply(null, ruleParams);
result = ruleFunc[0].test(value);
message = ruleFunc[1];
} else {
result = ruleConfig[0].test(value);
}
if (!result) {
that.showError($elem, message);
isValid = false;
return false; // 跳出循环
} else {
that.clearError($elem);
}
}
});
return isValid;
},
showError: function(elem, message) {
// 显示错误提示(可结合Layui的layer模块)
var $parent = elem.parent();
$parent.find('.error-tip').remove();
$parent.append('<div class="error-tip" style="color:red;font-size:12px;">' + message + '</div>');
elem.addClass('error-border');
},
clearError: function(elem) {
var $parent = elem.parent();
$parent.find('.error-tip').remove();
elem.removeClass('error-border');
}
};
// 暴露接口
exports('validator', function(options) {
return new Validator(options);
});
});
插件使用示例
// 使用验证插件
layui.use('validator', function() {
var validator = layui.validator;
// 初始化验证器
var formValidator = validator({
form: '#myForm',
rules: {
username: 'required',
email: 'email',
mobile: 'mobile',
password: {min: 6}
},
messages: {
username: '用户名不能为空'
},
success: function() {
alert('表单验证通过!');
}
});
});
5个实用工具扩展案例
1. 数组操作工具集
// examples/extends/arrayTools.js
layui.define(function(exports) {
var arrayTools = {
// 数组扁平化
flatten: function(arr) {
return arr.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(this.flatten(val)) : acc.concat(val), []);
},
// 数组分组
groupBy: function(arr, key) {
return arr.reduce((groups, item) => {
const group = groups[item[key]] || [];
group.push(item);
groups[item[key]] = group;
return groups;
}, {});
}
};
exports('arrayTools', arrayTools);
});
2. 本地存储增强工具
// examples/extends/storage.js
layui.define(function(exports) {
var storage = {
// 带过期时间的localStorage
setWithExpiry: function(key, value, ttl) {
const now = new Date();
const item = {
value: value,
expiry: now.getTime() + ttl
};
localStorage.setItem(key, JSON.stringify(item));
},
// 获取带过期时间的localStorage
getWithExpiry: function(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) return null;
const item = JSON.parse(itemStr);
const now = new Date();
if (now.getTime() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
}
};
exports('storage', storage);
});
3. DOM操作增强工具
// examples/extends/domTools.js
layui.define(['jquery'], function(exports) {
var $ = layui.$;
var domTools = {
// 平滑滚动到锚点
scrollToAnchor: function(anchorId, duration = 500) {
var $target = $('#' + anchorId);
if ($target.length) {
$('html, body').animate({
scrollTop: $target.offset().top - 80
}, duration);
}
},
// 获取元素位置信息
getPosition: function(selector) {
var $elem = $(selector);
if (!$elem.length) return null;
return {
top: $elem.offset().top,
left: $elem.offset().left,
width: $elem.outerWidth(),
height: $elem.outerHeight()
};
}
};
exports('domTools', domTools);
});
4. 浏览器信息检测工具
// examples/extends/browser.js
layui.define(function(exports) {
var browser = {
// 获取浏览器信息
getInfo: function() {
const ua = navigator.userAgent;
return {
isMobile: /mobile/i.test(ua),
isWeixin: /MicroMessenger/i.test(ua),
isChrome: /Chrome/i.test(ua) && !/Edge/i.test(ua),
isFirefox: /Firefox/i.test(ua),
isSafari: /Safari/i.test(ua) && !/Chrome/i.test(ua)
};
},
// 检测是否支持某CSS属性
supportCssProperty: function(prop) {
const prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
const style = document.documentElement.style;
for (let i = 0; i < prefixes.length; i++) {
const prefixedProp = prefixes[i] ?
prefixes[i] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
if (prefixedProp in style) {
return prefixedProp;
}
}
return false;
}
};
exports('browser', browser);
});
5. 数字处理工具
// examples/extends/numberTools.js
layui.define(['util'], function(exports) {
var util = layui.util;
var numberTools = {
// 数字格式化:添加千分位和单位
formatNumber: function(num, precision = 2) {
if (num >= 100000000) {
return (num / 100000000).toFixed(precision) + '亿';
} else if (num >= 10000) {
return (num / 10000).toFixed(precision) + '万';
}
return num.toLocaleString('en-US', {
minimumFractionDigits: precision,
maximumFractionDigits: precision
});
},
// 随机数生成
random: function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
};
exports('numberTools', numberTools);
});
工具扩展的调试与维护
调试技巧
- 使用Layui的hint模块输出错误信息:
var hint = layui.hint();
hint.error('自定义工具函数错误:参数不能为空');
- 在扩展模块中添加版本信息,便于问题追踪:
var customTools = {
version: '1.0.0',
// ...功能方法
};
维护建议
- 定期同步原生util模块更新,确保兼容性
- 为扩展工具编写单元测试,存放在examples/extends/test/目录
- 重要工具函数添加JSDoc注释:
/**
* 金额格式化
* @param {number} amount - 金额(分)
* @param {string} [symbol=¥] - 货币符号
* @returns {string} 格式化后的金额字符串
*/
formatMoney: function(amount, symbol = '¥') {
// 实现代码
}
总结与进阶
通过本文介绍的三种扩展方式,你可以灵活地为Layui添加自定义工具函数,解决实际开发中的特定需求。简单功能推荐使用直接扩展法,项目内复用功能推荐独立模块法,跨项目复用功能则应开发标准插件。
进阶学习建议:
- 研究src/modules/util.js源码,理解原生工具函数实现原理
- 参考官方文档docs/util/detail/demo.md了解更多使用场景
- 探索Layui社区贡献的工具插件,学习最佳实践
掌握工具函数扩展技巧,能够让你的Layui项目更加高效、优雅。赶快尝试将本文介绍的方法应用到实际项目中,提升开发效率吧!
如果本文对你有帮助,欢迎点赞收藏,关注获取更多Layui开发技巧。下期将为大家带来《Layui组件二次封装实战》,敬请期待!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



