make ref a runtime module

This commit is contained in:
Evan You 2016-06-01 19:52:42 -04:00
parent 8f274a3324
commit 060fab9ec1
9 changed files with 77 additions and 51 deletions

View File

@ -63,6 +63,9 @@ declare type ASTElement = {
slotName?: ?string,
slotTarget?: ?string,
ref?: string,
refInFor?: boolean,
render?: true,
renderMethod?: ?string,
renderArgs?: ?string,

View File

@ -100,13 +100,6 @@ declare interface Component {
val: any,
render: Function
) => ?Array<VNode>;
// registerRef
_r: (
key: string,
ref: Component | Element,
vFor: boolean,
isRemoval: boolean
) => void;
// apply v-bind object
_b: (vnode: VNodeWithData, value: any) => void;

View File

@ -112,6 +112,13 @@ function genData (el: ASTElement): string | void {
if (el.key) {
data += `key:${el.key},`
}
// ref
if (el.ref) {
data += `ref:"${el.ref}",`
}
if (el.refInFor) {
data += `refInFor:true,`
}
// slot target
if (el.slotTarget) {
data += `slot:${el.slotTarget},`

View File

@ -1,19 +1,15 @@
/* @flow */
import { addHook } from '../helpers'
export default function ref (el: ASTElement, dir: ASTDirective) {
// go up and check if this node is inside a v-for
let isFor = false
let parent = el
while (parent) {
if (parent.for !== undefined) {
isFor = true
if (dir.arg) {
el.ref = dir.arg
// go up and check if this node is inside a v-for
let parent = el
while (parent) {
if (parent.for !== undefined) {
el.refInFor = true
}
parent = parent.parent
}
parent = parent.parent
}
// registerRef: _r(name, ref, vFor?, remove?)
const code = `_r("${dir.arg}",n1.child||n1.elm,${isFor ? 'true' : 'false'}`
addHook(el, 'insert', `${code},false)`)
addHook(el, 'destroy', `${code},true)`)
}

View File

@ -4,7 +4,7 @@ import config from '../config'
import VNode, { emptyVNode } from '../vdom/vnode'
import { normalizeChildren } from '../vdom/helpers'
import {
warn, bind, remove, isObject, toObject,
warn, bind, isObject, toObject,
nextTick, resolveAsset, renderString
} from '../util/index'
@ -120,34 +120,6 @@ export function renderMixin (Vue: Class<Component>) {
return ret
}
// register ref
Vue.prototype._r = function (
key: string,
ref: Vue | Element,
vFor: boolean,
isRemoval: boolean
) {
const vm: Component = this
const refs = vm.$refs
if (isRemoval) {
if (Array.isArray(refs[key])) {
remove(refs[key], ref)
} else {
refs[key] = undefined
}
} else {
if (vFor) {
if (Array.isArray(refs[key])) {
refs[key].push(ref)
} else {
refs[key] = [ref]
}
} else {
refs[key] = ref
}
}
}
// apply v-bind object
Vue.prototype._b = function (vnode: VNodeWithData, value: any) {
if (value) {

View File

@ -1,5 +1,7 @@
import directives from './directives'
import ref from './ref'
export default [
ref,
directives
]

View File

@ -0,0 +1,38 @@
/* flow */
import { remove } from 'shared/util'
export default {
create (_, vnode) {
registerRef(vnode, false)
},
destroy (vnode) {
registerRef(vnode, true)
}
}
function registerRef (vnode: VNodeWithData, isRemoval: boolean) {
const key = vnode.data.ref
if (!key) return
const vm = vnode.context
const ref = vnode.child || vnode.elm
const refs = vm.$refs
if (isRemoval) {
if (Array.isArray(refs[key])) {
remove(refs[key], ref)
} else if (refs[key] === ref) {
refs[key] = undefined
}
} else {
if (vnode.data.refInFor) {
if (Array.isArray(refs[key])) {
refs[key].push(ref)
} else {
refs[key] = [ref]
}
} else {
refs[key] = ref
}
}
}

View File

@ -25,6 +25,21 @@ describe('Directive v-ref', () => {
expect(vm.$refs['test-hyphen'].$options.id).toBe('test2')
})
it('should work as a hyperscript prop', () => {
const vm = new Vue({
components,
render () {
const h = this.$createElement
return h('div', null, [
h('test', { ref: 'test' })
])
}
})
vm.$mount()
expect(vm.$refs.test).toBeTruthy()
expect(vm.$refs.test.$options.id).toBe('test')
})
it('should accept camelCase refs', () => {
const vm = new Vue({
template:

View File

@ -62,14 +62,14 @@ describe('codegen', () => {
it('generate v-ref directive', () => {
assertCodegen(
'<p v-ref:component1></p>',
`with(this){return _h(_e('p',{hook:{"insert":function(n1,n2){_r("component1",n1.child||n1.elm,false,false)},"destroy":function(n1,n2){_r("component1",n1.child||n1.elm,false,true)}}}))}`
`with(this){return _h(_e('p',{ref:"component1"}))}`
)
})
it('generate v-ref directive on v-for', () => {
assertCodegen(
'<ul><li v-for="item in items" v-ref:component1></li></ul>',
`with(this){return _h(_e('ul'),[(items)&&_l((items),function(item,$index,$key){return _h(_e('li',{hook:{"insert":function(n1,n2){_r("component1",n1.child||n1.elm,true,false)},"destroy":function(n1,n2){_r("component1",n1.child||n1.elm,true,true)}}}))})])}`
`with(this){return _h(_e('ul'),[(items)&&_l((items),function(item,$index,$key){return _h(_e('li',{ref:"component1",refInFor:true}))})])}`
)
})