Jelajahi Sumber

do not defer cleanup when unbinding component (fix #1006)

Evan You 11 tahun lalu
induk
melakukan
4a8581f3ed
2 mengubah file dengan 39 tambahan dan 10 penghapusan
  1. 7 4
      src/directives/component.js
  2. 32 6
      test/unit/specs/misc_spec.js

+ 7 - 4
src/directives/component.js

@@ -101,12 +101,12 @@ module.exports = {
     this.invalidatePending()
     if (!value) {
       // just remove current
-      this.unbuild()
+      this.unbuild(true)
       this.remove(this.childVM, afterTransition)
       this.unsetCurrent()
     } else {
       this.resolveCtor(value, _.bind(function () {
-        this.unbuild()
+        this.unbuild(true)
         var newComponent = this.build(data)
         /* istanbul ignore if */
         if (afterBuild) afterBuild(newComponent)
@@ -190,9 +190,11 @@ module.exports = {
   /**
    * Teardown the current child, but defers cleanup so
    * that we can separate the destroy and removal steps.
+   *
+   * @param {Boolean} defer
    */
 
-  unbuild: function () {
+  unbuild: function (defer) {
     var child = this.childVM
     if (!child || this.keepAlive) {
       return
@@ -200,7 +202,7 @@ module.exports = {
     // the sole purpose of `deferCleanup` is so that we can
     // "deactivate" the vm right now and perform DOM removal
     // later.
-    child.$destroy(false, true)
+    child.$destroy(false, defer)
   },
 
   /**
@@ -285,6 +287,7 @@ module.exports = {
 
   unbind: function () {
     this.invalidatePending()
+    // Do not defer cleanup when unbinding
     this.unbuild()
     this.unsetCurrent()
     // destroy all keep-alive cached instances

+ 32 - 6
test/unit/specs/misc_spec.js

@@ -81,7 +81,7 @@ describe('Misc', function () {
   })
 
   // #1005
-  it('call attach/ready/detach hook for child components', function () {
+  it('call lifecycle hooks for child components', function () {
     Vue.options.replace = true
     var el = document.createElement('div')
     var logs = []
@@ -96,22 +96,48 @@ describe('Misc', function () {
       attached: log(0),
       ready: log(1),
       detached: log(2),
+      beforeDestroy: log(3),
+      destroyed: log(4),
       template: '<div><test></test><test></test></div>',
       components: {
         test: {
           template: '<span>hi</span>',
-          attached: log(3),
-          ready: log(4),
-          detached: log(5)
+          attached: log(5),
+          ready: log(6),
+          detached: log(7),
+          beforeDestroy: log(8),
+          destroyed: log(9)
         }
       }
     })
     expect(vm.$el.innerHTML).toBe('<span>hi</span><span>hi</span>')
-    expect(logs.join()).toBe('0,3,4,3,4,1')
+    expect(logs.join()).toBe('0,5,6,5,6,1')
     logs = []
     vm.$destroy(true)
-    expect(logs.join()).toBe('2,5,5')
+    expect(logs.join()).toBe('3,8,9,8,9,2,7,7,4')
     Vue.options.replace = false
   })
 
+  // #1006
+  it('destroyed hook for components inside v-if', function (done) {
+    var spy = jasmine.createSpy('v-if destroyed hook')
+    var vm = new Vue({
+      el: document.createElement('div'),
+      template: '<template v-if="ok"><test></test></template>',
+      data: {
+        ok: true
+      },
+      components: {
+        test: {
+          destroyed: spy
+        }
+      }
+    })
+    vm.ok = false
+    Vue.nextTick(function () {
+      expect(spy).toHaveBeenCalled()
+      done()
+    })
+  })
+
 })