如何判断Vue组件是否处于活动状态

15

我有一个Vue组件,它被包裹在<keep-alive>标签中以防止重新渲染。

在组件内部,我希望通过触发方法来对全局数据的某些更改做出反应。但是,我只想在组件当前处于活动状态时才触发该方法。

目前,我正在执行类似以下的操作:

export default {
  data() {
    return { 
      globalVar: this.$store.state.var,
      isComponentActive: false,
    };
  },
  methods: {
    foo() { console.log('foo') };
  },
  watch: {
    globalVar() {
      if (this.isComponentActive) {
        this.foo();
      }
    },
  },
  activated() {
    this.isComponentActive = true;
  },
  deactivated() {
    this.isComponentActive = false;
  },
}
  

但我希望组件实例中已经有一个属性可供引用。就像这样:

export default {
  data() {
    return { globalVar: this.$store.state.var };
  },
  methods: {
    foo() { console.log('foo') };
  },
  watch: {
    globalVar() {
      if (this.$isComponentActive) {
        this.foo();
      }
    },
  },
}

保持活性标签<keep-alive>的文档中,并没有找到类似的东西。并且,根据Vue实例,它似乎没有这个属性。但是,有没有人知道我能否获取Vue实例的“activated”状态,而不必通过钩子函数自己维护?


可能使用directive=ref指令是一个解决方案。在你的组件中加入ref="test"<keep-alive>,然后通过this.$refs.test ? true : false检查其活动状态。 - Sphinx
这不可行,即使组件被停用,该组件的$refs数组仍将维护。除非你指的是父级作用域,但这对我没有帮助,因为我需要防止触发的方法在已停用的组件内,而不在父级中。 - thanksd
5个回答

15

你可以使用_inactive(基于vue/src/core/instance/lifecycle.js的源代码)来检查组件是否已被激活。

Vue.config.productionTip = false
Vue.component('child', {
  template: '<div>{{item}}</div>',
  props: ['item'],
  activated: function(){
    console.log('activated', this._inactive, this.item)
  },
  deactivated: function(){
    console.log('deactivated', this._inactive, this.item)
  },
  mounted: function(){
    console.log('mounted', this._inactive, this.item)
  },
  destroyed: function () {
    console.log('destroyed', this._inactive, this.item)
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      testArray: ['a', 'b', 'c']
    }
  },
  methods:{
    pushItem: function() {
      this.testArray.push('z')
    },
    popItem: function() {
      this.testArray.pop()
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <button v-on:click="pushItem()">Push Item</button>
  <button v-on:click="popItem()">Pop Item</button>
  <div v-for="(item, key) in testArray">
    <keep-alive>
      <child :key="key" :item="item"></child>
    </keep-alive>
  </div>
</div>


是的,完美的,可能我错过了那个。谢谢! - thanksd
5
你没错过什么,这不是公共API,可能随时会更改。我想在实例上拥有这样的属性,而不必手动创建它... - Maksim Nesterenko

1

源代码来看,似乎没有任何状态在组件实例中被改变。相反,该元素只是被添加或从缓存中移除。因此,我认为除了生命周期钩子之外,没有其他选项。


1

1
我知道我来晚了,但这个问题仍然是一个好问题。通常情况下,您可以通过props从父级设置子元素的可见性。但有些情况下,您希望子元素自己知道它是否可见,而不涉及父级。

这个建议有点像黑客技巧,但对于vue 2 + 3都有效。我使用updated钩子,在那里检查元素是否具有宽度(作为布尔值),以及一个观察器来对更改做出反应。

然而-如果您需要在孙子级中触发更新,则需要通过其父级绑定一个变量,例如:key='someVar',然后在可见性更改时更改该值,如someVar ++。否则,孙子级中的更新将不会被触发。

感谢@Sphinx提供的代码片段,我已经适应了我的目的。

Vue.config.productionTip = false
Vue.component('child', {
  template: '<div id="childisch"><slot></slot></div>',
   data() {
    return {
      isActive: false
    }
  },
    watch: {
        isActive(val) {
          if (val) {
            console.log('I know I am visible')
          } else {
            console.log('I am hidden')
          }
        }
    },
  updated(){
    const el = document.querySelector('#childisch')
    this.isActive = el.offsetWidth > 0
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      showChild: false
    }
  },
  methods:{
    toggleItem() {
      this.showChild = !this.showChild
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <button v-on:click="toggleItem()">Toggle Child Visibility</button>
  <div v-show="showChild">
      <child>CHILD COMPONENT</child>
  </div>
</div>


0

使用 Composition API 时,您可以这样做:

<script setup>
const vm = getCurrentInstance()

onDeactivated(() => {
    console.log(vm?.isDeactivated) // true
})

onActivated(() => {
    console.log(vm?.isDeactivated) // false
})
</script>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接