فهرست منبع

hoist refs at compile time so that they are properly reactive (fix #1671)

Evan You 10 سال پیش
والد
کامیت
296ed695d8
4فایلهای تغییر یافته به همراه22 افزوده شده و 20 حذف شده
  1. 12 0
      src/compiler/compile.js
  2. 1 7
      src/directives/internal/component.js
  3. 4 11
      src/directives/public/for.js
  4. 5 2
      test/unit/specs/directives/public/ref_spec.js

+ 12 - 0
src/compiler/compile.js

@@ -493,8 +493,10 @@ function checkElementDirectives (el, options) {
 function checkComponent (el, options) {
   var component = _.checkComponent(el, options)
   if (component) {
+    var ref = _.findRef(el)
     var descriptor = {
       name: 'component',
+      ref: ref,
       expression: component.id,
       def: internalDirectives.component,
       modifiers: {
@@ -502,6 +504,9 @@ function checkComponent (el, options) {
       }
     }
     var componentLinkFn = function (vm, el, host, scope, frag) {
+      if (ref) {
+        _.defineReactive((scope || vm).$refs, ref, null)
+      }
       vm._bindDir(descriptor, el, host, scope, frag)
     }
     componentLinkFn.terminal = true
@@ -568,7 +573,14 @@ function makeTerminalNodeLinkFn (el, dirName, value, options, def) {
     // either an element directive, or if/for
     def: def || publicDirectives[dirName]
   }
+  // check ref for v-for
+  if (dirName === 'for') {
+    descriptor.ref = _.findRef(el)
+  }
   var fn = function terminalNodeLinkFn (vm, el, host, scope, frag) {
+    if (descriptor.ref) {
+      _.defineReactive((scope || vm).$refs, descriptor.ref, null)
+    }
     vm._bindDir(descriptor, el, host, scope, frag)
   }
   fn.terminal = true

+ 1 - 7
src/directives/internal/component.js

@@ -23,12 +23,6 @@ module.exports = {
 
   bind: function () {
     if (!this.el.__vue__) {
-      // check ref
-      this.ref = _.findRef(this.el)
-      var refs = (this._scope || this.vm).$refs
-      if (this.ref && !refs.hasOwnProperty(this.ref)) {
-        _.defineReactive(refs, this.ref, null)
-      }
       // keep-alive cache
       this.keepAlive = this.params.keepAlive
       if (this.keepAlive) {
@@ -182,7 +176,7 @@ module.exports = {
         // if no inline-template, then the compiled
         // linker can be cached for better performance.
         _linkerCachable: !this.inlineTemplate,
-        _ref: this.ref,
+        _ref: this.descriptor.ref,
         _asComponent: true,
         _isRouterView: this._isRouterView,
         // if this is a transcluded component, context

+ 4 - 11
src/directives/public/for.js

@@ -55,9 +55,6 @@ module.exports = {
     _.replace(this.el, this.end)
     _.before(this.start, this.end)
 
-    // check ref
-    this.ref = _.findRef(this.el)
-
     // cache
     this.cache = Object.create(null)
 
@@ -231,7 +228,7 @@ module.exports = {
    */
 
   updateRef: function () {
-    var ref = this.ref
+    var ref = this.descriptor.ref
     if (!ref) return
     var hash = (this._scope || this.vm).$refs
     var refs
@@ -243,11 +240,7 @@ module.exports = {
         refs[frag.scope.$key] = findVmFromFrag(frag)
       })
     }
-    if (!hash.hasOwnProperty(ref)) {
-      _.defineReactive(hash, ref, refs)
-    } else {
-      hash[ref] = refs
-    }
+    hash[ref] = refs
   },
 
   /**
@@ -513,8 +506,8 @@ module.exports = {
   },
 
   unbind: function () {
-    if (this.ref) {
-      (this._scope || this.vm).$refs[this.ref] = null
+    if (this.descriptor.ref) {
+      (this._scope || this.vm).$refs[this.descriptor.ref] = null
     }
     if (this.frags) {
       var i = this.frags.length

+ 5 - 2
test/unit/specs/directives/public/ref_spec.js

@@ -57,7 +57,10 @@ if (_.inBrowser) {
       var vm = new Vue({
         el: el,
         data: { view: 'one' },
-        template: '{{$refs.test.value}}<component :is="view" v-ref:test></component>',
+        template:
+          '{{$refs.test.value}}' +
+          '<component :is="view" v-ref:test></component>' +
+          '<div v-if="$refs.test.value > 1">ok</div>',
         components: {
           one: {
             id: 'one',
@@ -80,7 +83,7 @@ if (_.inBrowser) {
       vm.view = 'two'
       _.nextTick(function () {
         expect(vm.$refs.test.$options.id).toBe('two')
-        expect(el.textContent).toBe('2')
+        expect(el.textContent).toBe('2ok')
         vm.view = ''
         _.nextTick(function () {
           expect(vm.$refs.test).toBeNull()