diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/vue/src/platforms/web/runtime/directives/model.js | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/vue/src/platforms/web/runtime/directives/model.js')
| -rw-r--r-- | node_modules/vue/src/platforms/web/runtime/directives/model.js | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/node_modules/vue/src/platforms/web/runtime/directives/model.js b/node_modules/vue/src/platforms/web/runtime/directives/model.js new file mode 100644 index 00000000..cba8ded0 --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/model.js @@ -0,0 +1,147 @@ +/** + * Not type checking this file because flow doesn't like attaching + * properties to Elements. + */ + +import { isTextInputType } from 'web/util/element' +import { looseEqual, looseIndexOf } from 'shared/util' +import { mergeVNodeHook } from 'core/vdom/helpers/index' +import { warn, isIE9, isIE, isEdge } from 'core/util/index' + +/* 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') + } + }) +} + +const directive = { + inserted (el, binding, vnode, oldVnode) { + if (vnode.tag === 'select') { + // #6903 + if (oldVnode.elm && !oldVnode.elm._vOptions) { + mergeVNodeHook(vnode, 'postpatch', () => { + directive.componentUpdated(el, binding, vnode) + }) + } else { + setSelected(el, binding, vnode.context) + } + el._vOptions = [].map.call(el.options, getValue) + } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) { + el._vModifiers = binding.modifiers + if (!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 + } + } + } + }, + + componentUpdated (el, binding, vnode) { + if (vnode.tag === 'select') { + setSelected(el, binding, vnode.context) + // in case the options rendered by v-for have changed, + // it's possible that the value is out-of-sync with the rendered options. + // detect such cases and filter out values that no longer has a matching + // option in the DOM. + const prevOptions = el._vOptions + const curOptions = el._vOptions = [].map.call(el.options, getValue) + if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) { + // trigger change event if + // no matching option found for at least one value + const needReset = el.multiple + ? binding.value.some(v => hasNoMatchingOption(v, curOptions)) + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions) + if (needReset) { + trigger(el, 'change') + } + } + } + } +} + +function setSelected (el, binding, vm) { + actuallySetSelected(el, binding, vm) + /* istanbul ignore if */ + if (isIE || isEdge) { + setTimeout(() => { + actuallySetSelected(el, binding, vm) + }, 0) + } +} + +function actuallySetSelected (el, binding, vm) { + const value = binding.value + const isMultiple = el.multiple + if (isMultiple && !Array.isArray(value)) { + process.env.NODE_ENV !== 'production' && warn( + `<select multiple v-model="${binding.expression}"> ` + + `expects an Array value for its binding, but got ${ + Object.prototype.toString.call(value).slice(8, -1) + }`, + vm + ) + return + } + let selected, option + for (let i = 0, l = el.options.length; i < l; i++) { + option = el.options[i] + if (isMultiple) { + selected = looseIndexOf(value, getValue(option)) > -1 + if (option.selected !== selected) { + option.selected = selected + } + } else { + if (looseEqual(getValue(option), value)) { + if (el.selectedIndex !== i) { + el.selectedIndex = i + } + return + } + } + } + if (!isMultiple) { + el.selectedIndex = -1 + } +} + +function hasNoMatchingOption (value, options) { + return options.every(o => !looseEqual(o, value)) +} + +function getValue (option) { + return '_value' in option + ? option._value + : option.value +} + +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) +} + +export default directive |
