Skip to content

Commit 154e17a

Browse files
committed
support binding DOM properties with .prop modifier and :: shorthand
1 parent 472b897 commit 154e17a

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

src/compiler/directives/bind.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
import { addHook } from '../helpers'
44

55
export default function bind (el: ASTElement, dir: ASTDirective) {
6-
addHook(el, 'construct', `_b(n1,${dir.value})`)
6+
addHook(el, 'construct', `_b(n1,${dir.value}${
7+
dir.modifiers && dir.modifiers.prop ? ',true' : ''
8+
})`)
79
}

src/compiler/parser/index.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { decodeHTML } from 'entities'
44
import { parseHTML } from './html-parser'
55
import { parseText } from './text-parser'
6-
import { cached, no } from 'shared/util'
6+
import { cached, no, camelize } from 'shared/util'
77
import {
88
pluckModuleFunction,
99
getAndRemoveAttr,
@@ -324,7 +324,7 @@ function processComponent (el) {
324324

325325
function processAttrs (el) {
326326
const list = el.attrsList
327-
let i, l, name, value, arg, modifiers
327+
let i, l, name, value, arg, modifiers, isProp
328328
for (i = 0, l = list.length; i < l; i++) {
329329
name = list[i].name
330330
value = list[i].value
@@ -336,7 +336,12 @@ function processAttrs (el) {
336336
}
337337
if (bindRE.test(name)) { // v-bind
338338
name = name.replace(bindRE, '')
339-
if (platformMustUseProp(name)) {
339+
if (name.charAt(0) === ':' || (modifiers && modifiers.prop)) {
340+
isProp = true
341+
name = camelize(name.replace(bindRE, ''))
342+
if (name === 'innerHtml') name = 'innerHTML'
343+
}
344+
if (isProp || platformMustUseProp(name)) {
340345
addProp(el, name, value)
341346
} else {
342347
addAttr(el, name, value)

src/core/instance/render.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ export function renderMixin (Vue: Class<Component>) {
148148
}
149149

150150
// apply v-bind object
151-
Vue.prototype._b = function bindProps (vnode: VNodeWithData, value: any) {
151+
Vue.prototype._b = function bindProps (
152+
vnode: VNodeWithData,
153+
value: any,
154+
asProp?: boolean) {
152155
if (value) {
153156
if (!isObject(value)) {
154157
process.env.NODE_ENV !== 'production' && warn(
@@ -161,7 +164,7 @@ export function renderMixin (Vue: Class<Component>) {
161164
}
162165
const data = vnode.data
163166
for (const key in value) {
164-
const hash = config.mustUseProp(key)
167+
const hash = asProp || config.mustUseProp(key)
165168
? data.domProps || (data.domProps = {})
166169
: data.attrs || (data.attrs = {})
167170
hash[key] = value[key]

test/unit/features/directives/bind.spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ describe('Directive v-bind', () => {
109109
}).then(done)
110110
})
111111

112+
it('bind as prop', () => {
113+
const vm = new Vue({
114+
template: '<div><span v-bind:text-content.prop="foo"></span><span ::inner-html="bar"></span></div>',
115+
data: {
116+
foo: 'hello',
117+
bar: '<span>qux</span>'
118+
}
119+
}).$mount()
120+
expect(vm.$el.children[0].textContent).toBe('hello')
121+
expect(vm.$el.children[1].innerHTML).toBe('<span>qux</span>')
122+
})
123+
112124
it('bind object', done => {
113125
const vm = new Vue({
114126
template: '<input v-bind="test">',
@@ -132,6 +144,30 @@ describe('Directive v-bind', () => {
132144
}).then(done)
133145
})
134146

147+
it('bind object as prop', done => {
148+
const vm = new Vue({
149+
template: '<input v-bind.prop="test">',
150+
data: {
151+
test: {
152+
id: 'test',
153+
className: 'ok',
154+
value: 'hello'
155+
}
156+
}
157+
}).$mount()
158+
expect(vm.$el.id).toBe('test')
159+
expect(vm.$el.className).toBe('ok')
160+
expect(vm.$el.value).toBe('hello')
161+
vm.test.id = 'hi'
162+
vm.test.className = 'okay'
163+
vm.test.value = 'bye'
164+
waitForUpdate(() => {
165+
expect(vm.$el.id).toBe('hi')
166+
expect(vm.$el.className).toBe('okay')
167+
expect(vm.$el.value).toBe('bye')
168+
}).then(done)
169+
})
170+
135171
it('bind array', done => {
136172
const vm = new Vue({
137173
template: '<input v-bind="test">',

0 commit comments

Comments
 (0)