diff --git a/components/_util/antInputDirective.js b/components/_util/antInputDirective.js
new file mode 100644
index 000000000..c6812322e
--- /dev/null
+++ b/components/_util/antInputDirective.js
@@ -0,0 +1,74 @@
+/**
+ * Not type checking this file because flow doesn't like attaching
+ * properties to Elements.
+ */
+
+export const inBrowser = typeof window !== 'undefined'
+export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
+export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
+function makeMap (
+ str,
+ expectsLowerCase
+) {
+ const map = Object.create(null)
+ const list = str.split(',')
+ for (let i = 0; i < list.length; i++) {
+ map[list[i]] = true
+ }
+ return expectsLowerCase
+ ? val => map[val.toLowerCase()]
+ : val => map[val]
+}
+const isTextInputType = makeMap('text,number,password,search,email,tel,url')
+
+function onCompositionStart (e) {
+ e.target.composing = true
+}
+
+function onCompositionEnd (e) {
+ // prevent triggering an input event for no reason
+ if (!e.target.composing) return
+ e.target.composing = false
+ trigger(e.target, 'input')
+}
+
+function trigger (el, type) {
+ const e = document.createEvent('HTMLEvents')
+ e.initEvent(type, true, true)
+ el.dispatchEvent(e)
+}
+
+/* istanbul ignore if */
+if (isIE9) {
+ // http://www.matts411.com/post/internet-explorer-9-oninput/
+ document.addEventListener('selectionchange', () => {
+ const el = document.activeElement
+ if (el && el.vmodel) {
+ trigger(el, 'input')
+ }
+ })
+}
+
+export default {
+ install: (Vue, options) => {
+ Vue.directive('ant-input', {
+ inserted (el, binding, vnode, oldVnode) {
+ if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
+ if (!binding.modifiers || !binding.modifiers.lazy) {
+ el.addEventListener('compositionstart', onCompositionStart)
+ el.addEventListener('compositionend', onCompositionEnd)
+ // Safari < 10.2 & UIWebView doesn't fire compositionend when
+ // switching focus before confirming composition choice
+ // this also fixes the issue where some browsers e.g. iOS Chrome
+ // fires "change" instead of "input" on autocomplete.
+ el.addEventListener('change', onCompositionEnd)
+ /* istanbul ignore if */
+ if (isIE9) {
+ el.vmodel = true
+ }
+ }
+ }
+ },
+ })
+ },
+}
diff --git a/components/input/Input.jsx b/components/input/Input.jsx
index 2364f58aa..dd7fa76a3 100644
--- a/components/input/Input.jsx
+++ b/components/input/Input.jsx
@@ -52,7 +52,9 @@ export default {
} else {
this.$forceUpdate()
}
- this.$emit('change.value', e.target.value)
+ if (!e.target.composing) {
+ this.$emit('change.value', e.target.value)
+ }
this.$emit('change', e)
this.$emit('input', e)
},
@@ -185,6 +187,9 @@ export default {
class: classNames(getInputClassName(), getClass(this)),
ref: 'input',
}
+ if ($listeners['change.value']) {
+ inputProps.directives = [{ name: 'ant-input' }]
+ }
return this.renderLabeledIcon(
}
diff --git a/components/input/TextArea.jsx b/components/input/TextArea.jsx
index 2fdd2800d..1ff5a6cde 100644
--- a/components/input/TextArea.jsx
+++ b/components/input/TextArea.jsx
@@ -96,9 +96,11 @@ export default {
})
} else {
this.$forceUpdate()
+ }
+ if (!e.target.composing) {
this.$emit('change.value', e.target.value)
- this.$emit('change', e)
}
+ this.$emit('change', e)
this.$emit('input', e)
},
@@ -133,6 +135,9 @@ export default {
input: handleTextareaChange,
},
}
+ if ($listeners['change.value']) {
+ textareaProps.directives = [{ name: 'ant-input' }]
+ }
return (