Reputation: 536
How can I call a method in VueJS when some html elements are mounted?
For example:
...
data: [
{
items: [
{text:'item1'},
{text:'item2'}
]
}
]
methods: function() {
myMethod: function(a) {
console.warn(a)
}
}
template: '<div
v-for="item in items"
:key="item.text"
@hook:mounted="myMethod(item.text + \" mounted\")"
>{{ item.text }}</div>'
...
I need to get HTML like this:
<div>item1</div>
<div>item2</div>
And I need to get 2 warn messages in console:
item1 mounted
item2 mounted
Or I can do it with another way?
Upvotes: 2
Views: 14045
Reputation: 29092
As others have noted, the hook:mounted
event is only available for components and won't fire for HTML elements.
You can do something similar for elements using a custom directive. While an element can't be 'mounted' we can nevertheless have a directive that is called when the element is available.
new Vue({
el: '#app',
directives: {
myMountedDirective (el, { value }) {
console.warn(value + ' mounted')
}
},
data () {
return {
items: [
{text: 'item1'},
{text: 'item2'}
]
}
}
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<div
v-for="item in items"
:key="item.text"
v-my-mounted-directive="item.text"
>
{{ item.text }}
</div>
</div>
However, all of this is very DOM-driven. Custom directives exist so that tweaks can be made to the DOM nodes after they exist. Generally that isn't the correct way to solve the underlying problem.
Usually it is better to make decisions based on the data rather than the DOM. So rather than watching for changes to the DOM we can watch for changes in items
.
If you really do need access to the DOM nodes (e.g. to measure sizes) then you might be better off using refs. You can add a ref
attribute to each <div>
and they will then be accessible as an array via $refs
. The mounted
and updated
hooks of the surrounding component are generally the appropriate places to react to changes in the $refs
as they all called immediately after rendering.
Upvotes: 2
Reputation: 2313
The only way to simulate a component mounting on div
s is to actually create a component that is a div:
V-Div.vue
<template>
<div><slot></slot></div>
</template>
You need a <slot>
so that you can pass content into the <v-div>
Include V-Div in your component (the component you created, not V-Div.vue)
import VDiv from './components/V-Div.vue';
// ...
{
data() { return { /* data */} },
computed: {},
// other options....
components: {VDiv}
}
Use the VDiv
in your component template:
<v-div @hook:mounted="myMethod(item.text + \" mounted\")">{{item.text}}</v-div>
EDIT: I would not recommend doing this, turning a plain HTML Element into a Vue component just to subscribe to life-cycles is a waste of resources.
Upvotes: 2
Reputation: 2313
Well, the @hook:mounted
syntax adds a life-cycle hook to a Vue Component.
<div></div>
is a plain HTML element.. you need to add a mounted()
method to your component options. The reason @click
works and @hook
doesn't is because HTML elements have click events; they don't have Vue component lifecycle hooks.
EDIT: To demonstrate, go ahead and visit this Codesandbox, navigate to App.vue
and try to move the @hook:mounted
directive from the Child
component to the div
that contains it, you'll notice the hook is never called because div
has no life-cycle hooks
EDIT: Also your Vue component needs to look like this:
mounted: function(a) {
this.myMethod("Hello, I am mounted!");
},
methods: {
myMethod(a) { console.warn(a); }
},
template: '<div></div>'
Upvotes: 6