JS 自定义事件
· 阅读需 4 分钟
今天在写代码时候,遇到两个组件关联的情况,最终通过 js 自定义事件进行了解决。
场景简单复现
当时的情况比较复杂。大致是使用Vue-elementUI封装了input组件,自己封装了表单元素读取与写入组件。input 组件有相应验证功能,如果是用户输入,那么没有任何问题。如果是通过自己封装的表单操作组件,直接写入input 的
value,那么没办法触发 input 的 input
change
事件,也就没办法进行监控了。
把这个场景简单复原一下。
一个组件是输入框组件,有一个验证功能。
一个组件是表单修改数据组件,负责修改 input 的值。
<form id="J_Form" action="javascript:void 0">
<input id="J_Input" name="age" value="18"/>
<button id="J_Btn">修改 input 值为200</button>
</form>
<script>
const checkInputValue = el => {
el.addEventListener('change', e => {
console.log('触发 change:', e.target.value)
})
el.addEventListener('input', e => {
console.log('触发 input:', e.target.value)
})
}
const formInputSetter = (form, name, value) => {
form.elements[name].value = value
}
</script>
<script>
const $input = document.querySelector('#J_Input')
const $btn = document.querySelector('#J_Btn')
const $form = document.querySelector('#J_Form')
checkInputValue($input)
$btn.addEventListener('click', () => {
formInputSetter($form, 'age', 200)
})
</script>
代码比较简单,无需多解释。
为什么不触发 change
input
事件呢?
首先说 change
事件,要想触发它,必须是 input 元素值变化了,并且从焦点状态变为非焦点状态。
在说下 input
事件,这个简单,必须是用户键盘敲击输入,类似 keypress 等事件。
很明显的,通过 js 修改 value 值,不在这两个事件范围内。
通过自定义事件解决
对此,我考虑采用自定义事件,实现广播。让第二个组件修改数值后,广播给第一个组件。
为什么不模拟广播
change
事件呢?主要是项目中change
事件还有其他作用,如果此时模拟,会导致误触发。所以自定义一个事件来实现。
知道了原理,那么解决起来也很简单:
<form id="J_Form" action="javascript:void 0">
<input id="J_Input" name="age" value="18"/>
<button id="J_Btn">修改 input 值为200</button>
</form>
<script>
const checkInputValue = el => {
el.addEventListener('change', e => {
console.log('触发 change:', e.target.value)
})
el.addEventListener('input', e => {
console.log('触发 input:', e.target.value)
})
// 增加自定义事件接收
el.addEventListener('push', e => {
console.log('触发 push:', e)
})
}
const formInputSetter = (form, name, value) => {
form.elements[name].value = value
}
</script>
<script>
const $input = document.querySelector('#J_Input')
const $btn = document.querySelector('#J_Btn')
const $form = document.querySelector('#J_Form')
checkInputValue($input)
$btn.addEventListener('click', () => {
formInputSetter($form, 'age', 200)
// 创建并分发自定义事件
let event = new CustomEvent('push', {detail: {k1: 'a', k2: 'b'}})
$input.dispatchEvent(event)
})
</script>
通过 new CustomEvent
创建自定义事件,在进行接收就可以处理了。
这里要注意一点:自定义事件的传参,只能定义到 detail
上,其他字段不能写入。接收的时候,也是 e.detail
进行接收。
== EOF ===