能否在HTML的onblur等事件属性中直接调用类内部方法?
提问:OOP开发模式下如何在HTML的onblur属性中调用类方法
我遇到了一个无法解决的小问题:
此前我通常按照如下方式做表单校验:
function checkFirst(field) { if (field.value.length < 2 || !regLetters.test(field.value)) { //do something } else { //do something else firstNameOk = true; } }
在HTML侧通过onblur="checkFirst(this)"触发校验。
现在我改用OOP模式开发,无法直接在onblur的HTML属性中调用类的方法,不知道该如何在HTML的onblur属性中调用类相关逻辑。
我已经找到了无需在HTML中写onblur的替代方案,但还是想确认直接在HTML的onblur属性中调用类方法是否可行。
恳请大家帮忙解答,谢谢!
补充:为了避免大家推荐我使用addEventListener实现,我先展示目前可用但不符合我预期的实现方案:
this.data.forEach(item => item.addEventListener('blur', function () { console.log(item.id) // check first name field // if (item.id === "first") { if (item.value.length < 2 || !this.regLetters.test(item.value)) { // if this field length = this.highlightField(item, true); } else { this.highlightField(item, false); this.errorMessagesReset(item); this.firstNameOk = true; } // check last name field // } else if (item.id === "last") { if (item.value.length < 2 || !this.regLetters.test(item.value)) { this.highlightField(item, true); } else { this.highlightField(item, false); this.errorMessagesReset(item); this.lastNameOk = true; } // check email field // } else if (item.id === "email") { if (item.value.length < 2 || !this.regmail.test(item.value)) { this.highlightField(item, true); } else { this.highlightField(item, false); this.errorMessagesReset(item); this.emailOk = true; } // check textarea field // } else if (item.id === "message") { if (item.value.length < 1 || item.value > 100) { // if length of item is sup or equal to 1 and this.highlightField(item, true); } else { this.highlightField(item, false); this.errorMessagesReset(item); this.messageOk = true; } } }.bind(this)));
解答
可行性结论
直接在HTML的onblur属性中调用类方法是完全可行的,核心需要解决行内事件默认执行上下文为全局window对象,类实例方法默认不在全局作用域的问题。
具体实现方案
方案1:类实例挂载到全局window对象
这是最直接的实现方式,步骤如下:
- 类实例化后将实例挂载到
window对象的自定义属性上 - 类的方法提前绑定
this指向实例,避免行内调用时this指向window
示例代码:
class FormValidator { constructor() { this.regLetters = /^[a-zA-Z]+$/; this.regmail = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; // 绑定方法this指向实例 this.checkField = this.checkField.bind(this); } checkField(field) { // 校验逻辑 } } // 实例挂载到全局 window.formValidator = new FormValidator();
对应HTML写法:
<input type="text" id="first" onblur="formValidator.checkField(this)">
方案2:全局中转方法调用
如果不想暴露整个类实例到全局,可以只暴露一个中转方法到window,内部调用类实例逻辑:
const validator = new FormValidator(); // 仅暴露中转方法到全局 window.triggerCheck = (field) => { validator.checkField(field); }
对应HTML写法:
<input type="text" id="first" onblur="triggerCheck(this)">
该实现方式的弊端
虽然可以实现,但不推荐生产环境使用,问题如下:
- 全局污染:不管是挂载实例还是中转方法,都需要占用window的属性名,多人协作时容易出现命名冲突
- 维护成本高:事件触发逻辑拆分在HTML和JS文件中,后续迭代找对应逻辑成本更高
- 管控能力弱:无法方便的移除事件、批量调整事件触发逻辑
现有实现优化建议
你目前使用的addEventListener方案是更符合前端开发规范的实现,现在的多分支判断可以通过配置表简化:
// 提前定义校验规则配置 const validateRules = { first: { reg: this.regLetters, minLength: 2, okFlag: 'firstNameOk' }, last: { reg: this.regLetters, minLength: 2, okFlag: 'lastNameOk' }, email: { reg: this.regmail, minLength: 2, okFlag: 'emailOk' }, message: { minLength: 1, maxLength: 100, okFlag: 'messageOk' } } this.data.forEach(item => { item.addEventListener('blur', () => { const rule = validateRules[item.id]; let hasError = false; if (rule.minLength && item.value.length < rule.minLength) hasError = true; if (rule.maxLength && item.value.length > rule.maxLength) hasError = true; if (rule.reg && !rule.reg.test(item.value)) hasError = true; this.highlightField(item, hasError); if (!hasError) { this.errorMessagesReset(item); this[rule.okFlag] = true; } }) })
优化后代码更精简,后续新增校验字段只需在配置表中新增对应规则即可。
内容的提问来源于stack exchange,提问作者lowriider74
相关产品推荐
相关产品推荐

