support binding DOM properties with .prop modifier and :: shorthand

This commit is contained in:
Evan You 2016-07-21 01:53:30 -04:00
parent 472b8975ed
commit 154e17abae
4 changed files with 52 additions and 6 deletions

View File

@ -3,5 +3,7 @@
import { addHook } from '../helpers'
export default function bind (el: ASTElement, dir: ASTDirective) {
addHook(el, 'construct', `_b(n1,${dir.value})`)
addHook(el, 'construct', `_b(n1,${dir.value}${
dir.modifiers && dir.modifiers.prop ? ',true' : ''
})`)
}

View File

@ -3,7 +3,7 @@
import { decodeHTML } from 'entities'
import { parseHTML } from './html-parser'
import { parseText } from './text-parser'
import { cached, no } from 'shared/util'
import { cached, no, camelize } from 'shared/util'
import {
pluckModuleFunction,
getAndRemoveAttr,
@ -324,7 +324,7 @@ function processComponent (el) {
function processAttrs (el) {
const list = el.attrsList
let i, l, name, value, arg, modifiers
let i, l, name, value, arg, modifiers, isProp
for (i = 0, l = list.length; i < l; i++) {
name = list[i].name
value = list[i].value
@ -336,7 +336,12 @@ function processAttrs (el) {
}
if (bindRE.test(name)) { // v-bind
name = name.replace(bindRE, '')
if (platformMustUseProp(name)) {
if (name.charAt(0) === ':' || (modifiers && modifiers.prop)) {
isProp = true
name = camelize(name.replace(bindRE, ''))
if (name === 'innerHtml') name = 'innerHTML'
}
if (isProp || platformMustUseProp(name)) {
addProp(el, name, value)
} else {
addAttr(el, name, value)

View File

@ -148,7 +148,10 @@ export function renderMixin (Vue: Class<Component>) {
}
// apply v-bind object
Vue.prototype._b = function bindProps (vnode: VNodeWithData, value: any) {
Vue.prototype._b = function bindProps (
vnode: VNodeWithData,
value: any,
asProp?: boolean) {
if (value) {
if (!isObject(value)) {
process.env.NODE_ENV !== 'production' && warn(
@ -161,7 +164,7 @@ export function renderMixin (Vue: Class<Component>) {
}
const data = vnode.data
for (const key in value) {
const hash = config.mustUseProp(key)
const hash = asProp || config.mustUseProp(key)
? data.domProps || (data.domProps = {})
: data.attrs || (data.attrs = {})
hash[key] = value[key]

View File

@ -109,6 +109,18 @@ describe('Directive v-bind', () => {
}).then(done)
})
it('bind as prop', () => {
const vm = new Vue({
template: '<div><span v-bind:text-content.prop="foo"></span><span ::inner-html="bar"></span></div>',
data: {
foo: 'hello',
bar: '<span>qux</span>'
}
}).$mount()
expect(vm.$el.children[0].textContent).toBe('hello')
expect(vm.$el.children[1].innerHTML).toBe('<span>qux</span>')
})
it('bind object', done => {
const vm = new Vue({
template: '<input v-bind="test">',
@ -132,6 +144,30 @@ describe('Directive v-bind', () => {
}).then(done)
})
it('bind object as prop', done => {
const vm = new Vue({
template: '<input v-bind.prop="test">',
data: {
test: {
id: 'test',
className: 'ok',
value: 'hello'
}
}
}).$mount()
expect(vm.$el.id).toBe('test')
expect(vm.$el.className).toBe('ok')
expect(vm.$el.value).toBe('hello')
vm.test.id = 'hi'
vm.test.className = 'okay'
vm.test.value = 'bye'
waitForUpdate(() => {
expect(vm.$el.id).toBe('hi')
expect(vm.$el.className).toBe('okay')
expect(vm.$el.value).toBe('bye')
}).then(done)
})
it('bind array', done => {
const vm = new Vue({
template: '<input v-bind="test">',