-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Activated hook for directives #2349
Comments
This would be very helpful my v-shared-element library as well. I hope this gets implemented! |
My use case is v-keep-scroll directive. |
Note: at least for Browser environments, you should be able to use |
Yep, but I need event, not just property. |
Same thing here. I'm using the activated hook to tell when I need to record the position of the elements and animate from their previous state. Simply haven't a property would not work for my case. |
I rethinked my issue and created abstract component instead of directive. Maybe it will help somebody Code is here // MIT License
import { withDirectives, onActivated } from 'vue';
const onScroll = ({ target }) => {
target.dataset.scrollPos = target.scrollLeft + '-' + target.scrollTop;
};
const onScrollOptions = { passive: true };
export default {
setup(props, { slots }) {
let els = [];
const saveScroll = {
created(el) {
el.addEventListener('scroll', onScroll, onScrollOptions);
els.push(el);
},
unmounted(el) {
el.removeEventListener('scroll', onScroll, onScrollOptions);
els = els.filter(e => e !== el);
}
};
onActivated(() => {
els.forEach(el => {
const { scrollPos } = el.dataset;
if (scrollPos) {
const pos = scrollPos.split('-');
el.scrollLeft = pos[0];
el.scrollTop = pos[1];
}
});
});
return () => slots.default().map(vnode => withDirectives(vnode, [[ saveScroll ]]));
}
} It is even more appropriate as before (using Vue 2) I used Component.vue
|
Hi, |
+100 for this |
yes please, add this |
I was able to do this
|
Something like this can work too (works well when you have multiple instances, unlike the one above)
|
The issue with this solution is that beforeUpdate doesn't fire in all cases when the component is deactivated. so the isActive property doesn't reflect the actual state and can trigger autofocus when it's not desired. Our team went with the composable route instead. Our issue was with the autofocus directive not able to fire when the component gets activated
|
I reworked this today using a component from vueuse
|
Hooks activated and deactivated still not supported for plugins after almost 4 years :( It really complicates plugins for custom directives v-custom-directive="...". |
In 2024, I found a solution. The binding parameter contains the instance of the component, and So a possible implementation of a directive that saves the scroll position is as follows: export default <Directive<HTMLElement, never, never, ScrollBehavior>>{
mounted(el, binding) {
let { scrollTop, scrollLeft } = el
const instance = binding.instance?.$
onActivated(() => {
el.scrollTo({
top: scrollTop,
left: scrollLeft,
behavior: binding.arg,
})
}, instance)
onDeactivated(() => {
scrollTop = el.scrollTop
scrollLeft = el.scrollLeft
}, instance)
},
} Works well with |
The onActivated and onDeactivated hooks will never be removed before the instance is destroyed. If the element is mounted multiple times due to v-if control, this code will lead to a memory leak. I made some improvements.
|
Your improvements still cannot prevent memory leaks. // SomePage.vue
<div class="app">
<button @click="flag = !flag">switch component</button>
<keep-alive>
<component :is="flag ? Comp1 : Comp2" />
</keep-alive>
</div>
// Comp1.vue
<div class="comp-1">
<p>comp 1</p>
<button @click="flag = !flag">switch v-if</button>
<template v-if="flag">
<Counter />
</template>
<template v-else>
<div v-for="i of 1000" :key="i" v-keep-scroll></div>
</template>
</div> Comp1 will not be unmounted no matter you switch v-if or switch component, so onUpdated(() => {
instance[keepScrollElements]
.values()
.filter((el: HTMLElement) => !el.isConnected)
.forEach((el: HTMLElement) => instance[keepScrollElements].delete(el))
}, instance) |
Perhaps you have misunderstood due to an incorrect statement in the official documentation. The
|
<script setup>
import { ref } from 'vue'
import vUnmount from './unmount';
const flag1 = ref(true), flag2 = ref(true);
</script>
<template>
<div class="app">
<button @click="flag1 = !flag1">switch flag 1</button>
<button @click="flag2 = !flag2">switch flag 2</button>
<template v-if="flag1">
<p v-unmount>no v-for</p>
</template>
<template v-if="flag2">
<p v-for="i of 1" v-unmount>with v-for</p>
</template>
</div>
</template>
<style scoped>
.app {
display: flex;
flex-direction: column;
}
.app>* {
margin: 1em 1em;
}
</style> The |
What problem does this feature solve?
component's keep-alive activated and deactivated hooks should also be available in directives.
For example, suppose you have a directive that adds a class based on the size of an element. When the component to which the directive is added is in a keep-alive, the directive's mounted hook will be called, even if it is not actually mounted in the DOM, and the size of the element will be zero. If we can detect that a component with a directive bound to it is now active, we can get the correct size.
Thank you!
What does the proposed API look like?
The text was updated successfully, but these errors were encountered: