|
| 1 | +# 表单事件 |
| 2 | + |
| 3 | +## 表单事件的种类 |
| 4 | + |
| 5 | +### input 事件 |
| 6 | + |
| 7 | +`input`事件当`<input>`、`<select>`、`<textarea>`的值发生变化时触发。对于复选框(`<input type=checkbox>`)或单选框(`<input type=radio>`),用户改变选项时,也会触发这个事件。另外,对于打开`contenteditable`属性的元素,只要值发生变化,也会触发`input`事件。 |
| 8 | + |
| 9 | +`input`事件的一个特点,就是会连续触发,比如用户每按下一次按键,就会触发一次`input`事件。 |
| 10 | + |
| 11 | +`input`事件对象继承了`InputEvent`接口。 |
| 12 | + |
| 13 | +该事件跟`change`事件很像,不同之处在于`input`事件在元素的值发生变化后立即发生,而`change`在元素失去焦点时发生,而内容此时可能已经变化多次。也就是说,如果有连续变化,`input`事件会触发多次,而`change`事件只在失去焦点时触发一次。 |
| 14 | + |
| 15 | +下面是`<select>`元素的例子。 |
| 16 | + |
| 17 | +```javascript |
| 18 | +/* HTML 代码如下 |
| 19 | +<select id="mySelect"> |
| 20 | + <option value="1">1</option> |
| 21 | + <option value="2">2</option> |
| 22 | + <option value="3">3</option> |
| 23 | +</select> |
| 24 | +*/ |
| 25 | + |
| 26 | +function inputHandler(e) { |
| 27 | + console.log(e.target.value) |
| 28 | +} |
| 29 | + |
| 30 | +var mySelect = document.querySelector('#mySelect'); |
| 31 | +mySelect.addEventListener('input', inputHandler); |
| 32 | +``` |
| 33 | + |
| 34 | +上面代码中,改变下拉框选项时,会触发`input`事件,从而执行回调函数`inputHandler`。 |
| 35 | + |
| 36 | +### select 事件 |
| 37 | + |
| 38 | +`select`事件当在`<input>`、`<textarea>`里面选中文本时触发。 |
| 39 | + |
| 40 | +```javascript |
| 41 | +// HTML 代码如下 |
| 42 | +// <input id="test" type="text" value="Select me!" /> |
| 43 | + |
| 44 | +var elem = document.getElementById('test'); |
| 45 | +elem.addEventListener('select', function (e) { |
| 46 | + console.log(e.type); // "select" |
| 47 | +}, false); |
| 48 | +``` |
| 49 | + |
| 50 | +选中的文本可以通过`event.target`元素的`selectionDirection`、`selectionEnd`、`selectionStart`和`value`属性拿到。 |
| 51 | + |
| 52 | +### Change 事件 |
| 53 | + |
| 54 | +`Change`事件当`<input>`、`<select>`、`<textarea>`的值发生变化时触发。它与`input`事件的最大不同,就是不会连续触发,只有当全部修改完成时才会触发,另一方面`input`事件必然伴随`change`事件。具体来说,分成以下几种情况。 |
| 55 | + |
| 56 | +- 激活单选框(radio)或复选框(checkbox)时触发。 |
| 57 | +- 用户提交时触发。比如,从下列列表(select)完成选择,在日期或文件输入框完成选择。 |
| 58 | +- 当文本框或`<textarea>`元素的值发生改变,并且丧失焦点时触发。 |
| 59 | + |
| 60 | +下面是一个例子。 |
| 61 | + |
| 62 | +```javascript |
| 63 | +// HTML 代码如下 |
| 64 | +// <select size="1" onchange="changeEventHandler(event);"> |
| 65 | +// <option>chocolate</option> |
| 66 | +// <option>strawberry</option> |
| 67 | +// <option>vanilla</option> |
| 68 | +// </select> |
| 69 | + |
| 70 | +function changeEventHandler(event) { |
| 71 | + console.log(event.target.value); |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +如果比较一下上面`input`事件的例子,你会发现对于`<select>`元素来说,`input`和`change`事件基本是等价的。 |
| 76 | + |
| 77 | +### invalid 事件 |
| 78 | + |
| 79 | +用户提交表单时,如果表单元素的值不满足校验条件,就会触发`invalid`事件。 |
| 80 | + |
| 81 | +```html |
| 82 | +<form> |
| 83 | + <input type="text" required oninvalid="console.log('invalid input')" /> |
| 84 | + <button type="submit">提交</button> |
| 85 | +</form> |
| 86 | +``` |
| 87 | + |
| 88 | +上面代码中,输入框是必填的。如果不填,用户点击按钮提交时,就会触发输入框的`invalid`事件,导致提交被取消。 |
| 89 | + |
| 90 | +### reset 事件,submit 事件 |
| 91 | + |
| 92 | +这两个事件发生在表单对象`<form>`上,而不是发生在表单的成员上。 |
| 93 | + |
| 94 | +`reset`事件当表单重置(所有表单成员变回默认值)时触发。 |
| 95 | + |
| 96 | +`submit`事件当表单数据向服务器提交时触发。注意,`submit`事件的发生对象是`<form>`元素,而不是`<button>`元素,因为提交的是表单,而不是按钮。 |
| 97 | + |
| 98 | +## InputEvent 接口 |
| 99 | + |
| 100 | +`InputEvent`接口主要用来描述`input`事件的实例。该接口继承了`Event`接口,还定义了一些自己的实例属性和实例方法。 |
| 101 | + |
| 102 | +浏览器原生提供`InputEvent()`构造函数,用来生成实例对象。 |
| 103 | + |
| 104 | +```javascript |
| 105 | +new InputEvent(type, options) |
| 106 | +``` |
| 107 | + |
| 108 | +`InputEvent`构造函数可以接受两个参数。第一个参数是字符串,表示事件名称,该参数是必需的。第二个参数是一个配置对象,用来设置事件实例的属性,该参数是可选的。配置对象的字段除了`Event`构造函数的配置属性,还可以设置下面的字段,这些字段都是可选的。 |
| 109 | + |
| 110 | +- `inputType`:字符串,表示发生变更的类型(详见下文)。 |
| 111 | +- `data`:字符串,表示插入的字符串。如果没有插入的字符串(比如删除操作),则返回`null`或空字符串。 |
| 112 | +- `dataTransfer`:返回一个 DataTransfer 对象实例,该属性通常只在输入框接受富文本输入时有效。 |
| 113 | + |
| 114 | +`InputEvent`的实例属性主要就是上面三个属性,这三个实例属性都是只读的。 |
| 115 | + |
| 116 | +**(1)InputEvent.data** |
| 117 | + |
| 118 | +`InputEvent.data`属性返回一个字符串,表示变动的内容。 |
| 119 | + |
| 120 | +```javascript |
| 121 | +// HTML 代码如下 |
| 122 | +// <input type="text" id="myInput"> |
| 123 | +var input = document.getElementById('myInput'); |
| 124 | +input.addEventListener('input', myFunction, false); |
| 125 | + |
| 126 | +function myFunction(e) { |
| 127 | + console.log(e.data); |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +上面代码中,如果手动在输入框里面输入`abc`,控制台会先输出`a`,再在下一行输出`b`,再在下一行输出`c`。然后选中`abc`,一次性将它们删除,控制台会输出`null`或一个空字符串。 |
| 132 | + |
| 133 | +**(2)InputEvent.inputType** |
| 134 | + |
| 135 | +`InputEvent.inputType`属性返回一个字符串,表示字符串发生变更的类型。 |
| 136 | + |
| 137 | +对于常见情况,Chrome 浏览器的返回值如下。完整列表可以参考[文档](https://w3c.github.io/input-events/index.html#dom-inputevent-inputtype)。 |
| 138 | + |
| 139 | +- 手动插入文本:`insertText` |
| 140 | +- 粘贴插入文本:`insertFromPaste` |
| 141 | +- 向后删除:`deleteContentBackward` |
| 142 | +- 向前删除:`deleteContentBackward` |
| 143 | + |
| 144 | +**(3)InputEvent.dataTransfer** |
| 145 | + |
| 146 | +`InputEvent.dataTransfer`属性返回一个 DataTransfer 实例。该属性只在文本框接受粘贴内容(insertFromPaste)或拖拽内容(`insertFromDrop`)时才有效。 |
| 147 | + |
| 148 | +## CustomEvent 接口 |
| 149 | + |
| 150 | +CustomEvent 接口用于生成自定义的事件实例。那些浏览器预定义的事件,虽然可以手动生成,但是往往不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,就可以使用 CustomEvent 接口生成的自定义事件对象。 |
| 151 | + |
| 152 | +浏览器原生提供`CustomEvent()`构造函数,用来生成 CustomEvent 事件实例。 |
| 153 | + |
| 154 | +```javascript |
| 155 | +new CustomEvent(type, options) |
| 156 | +``` |
| 157 | + |
| 158 | +`CustomEvent()`构造函数接受两个参数。第一个参数是字符串,表示事件的名字,这是必须的。第二个参数是事件的配置对象,这个参数是可选的。`CustomEvent`的配置对象除了接受 Event 事件的配置属性,只有一个自己的属性。 |
| 159 | + |
| 160 | +- `detail`:表示事件的附带数据,默认为`null`。 |
| 161 | + |
| 162 | +下面是一个例子。 |
| 163 | + |
| 164 | +```javascript |
| 165 | +var event = new CustomEvent('build', { 'detail': 'hello' }); |
| 166 | + |
| 167 | +function eventHandler(e) { |
| 168 | + console.log(e.detail); |
| 169 | +} |
| 170 | + |
| 171 | +document.body.addEventListener('build', function (e) { |
| 172 | + console.log(e.detail); |
| 173 | +}); |
| 174 | + |
| 175 | +document.body.dispatchEvent(event); |
| 176 | +``` |
| 177 | + |
| 178 | +上面代码中,我们手动定义了`build`事件。该事件触发后,会被监听到,从而输出该事件实例的`detail`属性(即字符串`hello`)。 |
| 179 | + |
| 180 | +下面是另一个例子。 |
| 181 | + |
| 182 | +```javascript |
| 183 | +var myEvent = new CustomEvent('myevent', { |
| 184 | + detail: { |
| 185 | + foo: 'bar' |
| 186 | + }, |
| 187 | + bubbles: true, |
| 188 | + cancelable: false |
| 189 | +}); |
| 190 | + |
| 191 | +el.addEventListener('myevent', function (event) { |
| 192 | + console.log('Hello ' + event.detail.foo); |
| 193 | +}); |
| 194 | + |
| 195 | +el.dispatchEvent(myEvent); |
| 196 | +``` |
| 197 | + |
| 198 | +上面代码也说明,CustomEvent 的事件实例,除了具有 Event 接口的实例属性,还具有`detail`属性。 |
| 199 | + |
0 commit comments