今天在写代码时候,遇到两个组件关联的情况,最终通过 js 自定义事件进行了解决。
场景简单复现
当时的情况比较复杂。大致是使用Vue-elementUI封装了input组件,自己封装了表单元素读取与写入组件。input 组件有相应验证功能,如果是用户输入,那么没有任何问题。如果是通过自己封装的表单操作组件,直接写入input 的 value,那么没办法触发 input 的 input
change
事件,也就没办法进行监控了。
把这个场景简单复原一下。
一个组件是输入框组件,有一个验证功能。
一个组件是表单修改数据组件,负责修改 input 的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <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
事件还有其他作用,如果此时模拟,会导致误触发。所以自定义一个事件来实现。
知道了原理,那么解决起来也很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <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 ===