mirror of
https://gitee.com/vuejs/vue.git
synced 2024-11-30 02:57:43 +08:00
implement all v-model types
This commit is contained in:
parent
6cca5ec8a8
commit
8c00a1d724
@ -69,6 +69,13 @@ function genData (el, key) {
|
||||
let hasAttrs = false
|
||||
let hasProps = false
|
||||
let hasEvents = false
|
||||
|
||||
// parent elements my need to add props to children
|
||||
if (el.props) {
|
||||
hasProps = true
|
||||
props += el.props + ','
|
||||
}
|
||||
|
||||
for (let i = 0, l = el.attrs.length; i < l; i++) {
|
||||
let attr = el.attrs[i]
|
||||
let name = attr.name
|
||||
@ -89,9 +96,8 @@ function genData (el, key) {
|
||||
name = name.replace(onRE, '')
|
||||
addHandler(events, name, value)
|
||||
} else if (name === 'v-model') {
|
||||
// TODO: handle other input types
|
||||
hasProps = hasEvents = true
|
||||
props += genModel(el, events, value)
|
||||
props += genModel(el, events, value) + ','
|
||||
} else if (dirRE.test(name)) {
|
||||
// TODO: normal directives
|
||||
} else {
|
||||
|
@ -1,31 +1,60 @@
|
||||
import { addHandler } from './events'
|
||||
|
||||
export function genModel (el, events, value) {
|
||||
switch (el.attrsMap.type) {
|
||||
case 'checkbox':
|
||||
return genCheckboxModel(events, value)
|
||||
case 'radio':
|
||||
return genRadioModel(events, value)
|
||||
case 'select':
|
||||
return genSelectModel(events, value)
|
||||
default:
|
||||
return genTextModel(events, value)
|
||||
if (el.tag === 'select') {
|
||||
if (el.attrsMap.multiple != null) {
|
||||
return genMultiSelect(events, value, el)
|
||||
} else {
|
||||
return genSelect(events, value)
|
||||
}
|
||||
} else {
|
||||
switch (el.attrsMap.type) {
|
||||
case 'checkbox':
|
||||
return genCheckboxModel(events, value)
|
||||
case 'radio':
|
||||
return genRadioModel(events, value, el)
|
||||
default:
|
||||
return genDefaultModel(events, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function genCheckboxModel (events, value) {
|
||||
// TODO
|
||||
addHandler(events, 'change', `${value}=$event.target.checked`)
|
||||
return `checked:!!(${value})`
|
||||
}
|
||||
|
||||
function genRadioModel (events, value) {
|
||||
// TODO
|
||||
function genRadioModel (events, value, el) {
|
||||
addHandler(events, 'change', `${value}=$event.target.value`)
|
||||
return `checked:(${value}==${getInputValue(el)})`
|
||||
}
|
||||
|
||||
function genSelectModel (events, value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
function genTextModel (events, value) {
|
||||
function genDefaultModel (events, value) {
|
||||
addHandler(events, 'input', `${value}=$event.target.value`)
|
||||
return `value:${value},`
|
||||
return `value:(${value})`
|
||||
}
|
||||
|
||||
function genSelect (events, value) {
|
||||
addHandler(events, 'change', `${value}=$event.target.value`)
|
||||
return `value:(${value})`
|
||||
}
|
||||
|
||||
function genMultiSelect (events, value, el) {
|
||||
addHandler(events, 'change', `${value}=Array.prototype.filter
|
||||
.call($event.target.options,function(o){return o.selected})
|
||||
.map(function(o){return o.value})`)
|
||||
// patch child options
|
||||
for (let i = 0; i < el.children.length; i++) {
|
||||
let c = el.children[i]
|
||||
if (c.tag === 'option') {
|
||||
c.props = `selected:(${value}).indexOf(${getInputValue(c)})>-1`
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function getInputValue (el) {
|
||||
return el.attrsMap.value
|
||||
? JSON.stringify(el.attrsMap.value)
|
||||
: el.attrsMap['v-bind:value'] || el.attrsMap[':value']
|
||||
}
|
||||
|
@ -14,13 +14,6 @@ export default {
|
||||
|
||||
silent: false,
|
||||
|
||||
/**
|
||||
* Whether to warn against errors caught when evaluating
|
||||
* expressions.
|
||||
*/
|
||||
|
||||
warnExpressionErrors: true,
|
||||
|
||||
/**
|
||||
* List of asset types that a component can own.
|
||||
*
|
||||
|
@ -49,13 +49,11 @@ export default function Watcher (vm, expOrFn, cb, options) {
|
||||
this.newDeps = []
|
||||
this.depIds = new Set()
|
||||
this.newDepIds = new Set()
|
||||
this.prevError = null // for async error stacks
|
||||
// parse expression for getter/setter
|
||||
// parse expression for getter
|
||||
if (isFn) {
|
||||
this.getter = expOrFn
|
||||
this.setter = undefined
|
||||
} else {
|
||||
warn('vue-lite only supports watching functions.')
|
||||
this.getter = new Function(`with(this){return ${expOrFn}}`)
|
||||
}
|
||||
this.value = this.lazy
|
||||
? undefined
|
||||
@ -71,68 +69,16 @@ export default function Watcher (vm, expOrFn, cb, options) {
|
||||
|
||||
Watcher.prototype.get = function () {
|
||||
this.beforeGet()
|
||||
var scope = this.scope || this.vm
|
||||
var value
|
||||
try {
|
||||
value = this.getter.call(scope, scope)
|
||||
} catch (e) {
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
config.warnExpressionErrors
|
||||
) {
|
||||
warn(
|
||||
'Error when evaluating expression ' +
|
||||
'"' + this.expression + '": ' + e.toString(),
|
||||
this.vm
|
||||
)
|
||||
}
|
||||
}
|
||||
const value = this.getter.call(this.vm, this.vm)
|
||||
// "touch" every property so they are all tracked as
|
||||
// dependencies for deep watching
|
||||
if (this.deep) {
|
||||
traverse(value)
|
||||
}
|
||||
if (this.preProcess) {
|
||||
value = this.preProcess(value)
|
||||
}
|
||||
if (this.filters) {
|
||||
value = scope._applyFilters(value, null, this.filters, false)
|
||||
}
|
||||
if (this.postProcess) {
|
||||
value = this.postProcess(value)
|
||||
}
|
||||
this.afterGet()
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the corresponding value with the setter.
|
||||
*
|
||||
* @param {*} value
|
||||
*/
|
||||
|
||||
Watcher.prototype.set = function (value) {
|
||||
var scope = this.scope || this.vm
|
||||
if (this.filters) {
|
||||
value = scope._applyFilters(
|
||||
value, this.value, this.filters, true)
|
||||
}
|
||||
try {
|
||||
this.setter.call(scope, scope, value)
|
||||
} catch (e) {
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
config.warnExpressionErrors
|
||||
) {
|
||||
warn(
|
||||
'Error when evaluating setter ' +
|
||||
'"' + this.expression + '": ' + e.toString(),
|
||||
this.vm
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for dependency collection.
|
||||
*/
|
||||
@ -230,25 +176,7 @@ Watcher.prototype.run = function () {
|
||||
// set new value
|
||||
var oldValue = this.value
|
||||
this.value = value
|
||||
// in debug + async mode, when a watcher callbacks
|
||||
// throws, we also throw the saved before-push error
|
||||
// so the full cross-tick stack trace is available.
|
||||
var prevError = this.prevError
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production' &&
|
||||
config.debug && prevError) {
|
||||
this.prevError = null
|
||||
try {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
} catch (e) {
|
||||
nextTick(function () {
|
||||
throw prevError
|
||||
}, 0)
|
||||
throw e
|
||||
}
|
||||
} else {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
}
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
}
|
||||
this.queued = this.shallow = false
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ function updateAttrs (oldVnode, vnode) {
|
||||
old = oldAttrs[key]
|
||||
if (old !== cur) {
|
||||
// TODO: add support to namespaced attributes (setAttributeNS)
|
||||
if(!cur && booleanAttrsDict[key])
|
||||
if(booleanAttrsDict[key] && cur == null)
|
||||
elm.removeAttribute(key)
|
||||
else
|
||||
elm.setAttribute(key, cur)
|
||||
|
Loading…
Reference in New Issue
Block a user