only treat binding as domProps on specific elements (fix #4233)

This commit is contained in:
Evan You 2016-11-18 11:36:05 -05:00
parent f4df893828
commit 9a742cb423
7 changed files with 22 additions and 12 deletions

View File

@ -7,7 +7,7 @@ declare type CompilerOptions = {
directives?: { [key: string]: Function }; // platform specific directives
isUnaryTag?: (tag: string) => ?boolean; // check if a tag is unary for the platform
isReservedTag?: (tag: string) => ?boolean; // check if a tag is a native for the platform
mustUseProp?: (attr: string) => ?boolean; // check if an attribute should be bound as a property
mustUseProp?: (tag: string, attr: string) => ?boolean; // check if an attribute should be bound as a property
isPreTag?: (attr: string) => ?boolean; // check if a tag needs to preserve whitespace
getTagNamespace?: (tag: string) => ?string; // check the namespace for a tag
transforms?: Array<Function>; // a list of transforms on parsed AST before codegen

View File

@ -2,11 +2,7 @@
export default function bind (el: ASTElement, dir: ASTDirective) {
el.wrapData = (code: string) => {
return `_b(${
code
},${
dir.value
}${
return `_b(${code},'${el.tag}',${dir.value}${
dir.modifiers && dir.modifiers.prop ? ',true' : ''
})`
}

View File

@ -379,7 +379,7 @@ function processAttrs (el) {
name = camelize(name)
if (name === 'innerHtml') name = 'innerHTML'
}
if (isProp || platformMustUseProp(name)) {
if (isProp || platformMustUseProp(el.tag, name)) {
addProp(el, name, value)
} else {
addAttr(el, name, value)

View File

@ -14,7 +14,7 @@ export type Config = {
isReservedTag: (x?: string) => boolean;
isUnknownElement: (x?: string) => boolean;
getTagNamespace: (x?: string) => string | void;
mustUseProp: (x?: string) => boolean;
mustUseProp: (tag?: string, x?: string) => boolean;
// internal
_assetTypes: Array<string>;
_lifecycleHooks: Array<string>;

View File

@ -201,6 +201,7 @@ export function renderMixin (Vue: Class<Component>) {
// apply v-bind object
Vue.prototype._b = function bindProps (
data: any,
tag: string,
value: any,
asProp?: boolean
): VNodeData {
@ -218,7 +219,7 @@ export function renderMixin (Vue: Class<Component>) {
if (key === 'class' || key === 'style') {
data[key] = value[key]
} else {
const hash = asProp || config.mustUseProp(key)
const hash = asProp || config.mustUseProp(tag, key)
? data.domProps || (data.domProps = {})
: data.attrs || (data.attrs = {})
hash[key] = value[key]

View File

@ -3,7 +3,14 @@
import { makeMap } from 'shared/util'
// attributes that should be using props for binding
export const mustUseProp = makeMap('value,selected,checked,muted')
export const mustUseProp = (tag: string, attr: string): boolean => {
return (
(attr === 'value' && (tag === 'input' || tag === 'textarea' || tag === 'option')) ||
(attr === 'selected' && tag === 'option') ||
(attr === 'checked' && tag === 'input') ||
(attr === 'muted' && tag === 'video')
)
}
export const isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck')

View File

@ -84,7 +84,7 @@ describe('codegen', () => {
it('generate v-bind directive', () => {
assertCodegen(
'<p v-bind="test"></p>',
`with(this){return _h('p',_b({},test))}`
`with(this){return _h('p',_b({},'p',test))}`
)
})
@ -151,9 +151,15 @@ describe('codegen', () => {
})
it('generate DOM props with v-bind directive', () => {
// input + value
assertCodegen(
'<input :value="msg">',
`with(this){return _h('input',{domProps:{"value":msg}})}`
)
// non input
assertCodegen(
'<p :value="msg">',
`with(this){return _h('p',{domProps:{"value":msg}})}`
`with(this){return _h('p',{attrs:{"value":msg}})}`
)
})