Keywords: Vue.js | DOM elements | component instances | refs | reactive programming
Abstract: This article provides an in-depth exploration of methods to find corresponding Vue component instances from DOM elements in Vue.js. Focusing on Vue 2's refs system, it explains how to use the ref attribute to mark elements or components in templates and access them via this.$refs in JavaScript. The article compares different approaches including this.$el for accessing the component's root element, the __vue__ property for direct instance access, and VNode properties for advanced scenarios. Practical code examples demonstrate refs usage with various component types, helping developers understand the relationship between Vue's reactive system and the DOM.
Introduction
In Vue.js application development, developers often need to access specific DOM elements or component instances from JavaScript code. Unlike jQuery's $(element) approach, Vue provides more integrated and reactive methods for this purpose. This article focuses on Vue 2's recommended refs system while comparing alternative approaches.
The Refs System in Vue 2
Vue 2 unified the referencing mechanism for both elements and components, replacing Vue 1's v-el and v-ref directives with the ref attribute. This is the officially recommended standard approach.
In templates, you can add reference identifiers using the ref attribute:
<template>
<div>
<input ref="myInput">
<my-component ref="myComponent"></my-component>
</div>
</template>In JavaScript code, access these references through the this.$refs object:
export default {
mounted() {
// Access DOM element
const inputElement = this.$refs.myInput;
console.log('Input element:', inputElement);
// Access component instance
const componentInstance = this.$refs.myComponent;
console.log('Component instance:', componentInstance);
// Call component method
if (componentInstance && componentInstance.someMethod) {
componentInstance.someMethod();
}
}
}How Refs Work and Their Characteristics
this.$refs is an object containing all registered refs, with keys corresponding to the ref attribute values in templates. Important considerations include:
- Refs are not reactive and should not be used in templates or computed properties
- Refs are only populated after component rendering, accessing them before the
mountedlifecycle hook may returnundefined - When used with
v-for, ref becomes an array containing the corresponding elements
Example: Using refs with lists
<template>
<ul>
<li v-for="item in items" :key="item.id" ref="listItems">
{{ item.text }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' },
{ id: 3, text: 'Item 3' }
]
};
},
mounted() {
// this.$refs.listItems is an array containing 3 li elements
console.log('List items:', this.$refs.listItems);
}
};
</script>Comparison of Alternative Approaches
1. this.$el
Inside Vue components, this.$el returns the DOM reference of the component's root element. This method is limited to accessing the current component's own root element.
export default {
mounted() {
const rootElement = this.$el;
console.log('Component root element:', rootElement);
}
}2. __vue__ Property
Vue adds a __vue__ property to DOM elements in development mode, pointing to the corresponding Vue instance. While direct, this approach has limitations:
- Primarily intended for debugging purposes
- May not be available in production builds
- Breaks encapsulation and is not recommended for production code
// Get Vue instance from DOM element
const element = document.getElementById('app');
const vueInstance = element.__vue__;
console.log('Vue instance:', vueInstance);3. VNode-Related Properties
In advanced scenarios like custom directives or render functions, you can access related elements and components through VNode:
Vue.directive('custom-directive', {
bind(el, binding, vnode) {
// vnode.elm - DOM element the directive is bound to
console.log('Bound element:', vnode.elm);
// vnode.componentInstance - Component instance (if applicable)
console.log('Component instance:', vnode.componentInstance);
// vnode.context - Component context (usually parent component)
console.log('Context:', vnode.context);
}
});Method Selection Recommendations
Based on different use cases, the following approaches are recommended:
- Standard intra-component access: Use
refandthis.$refs, which aligns best with Vue's design philosophy - Accessing current component root element: Use
this.$el - Debugging purposes: The
__vue__property can be used, but don't rely on it in production code - Custom directives or advanced rendering: Use VNode-related properties
Practical Application Example
The following complete example demonstrates refs in a real-world scenario:
<template>
<div>
<form @submit.prevent="handleSubmit">
<input
type="text"
v-model="username"
ref="usernameInput"
placeholder="Enter username"
>
<button type="submit">Submit</button>
</form>
<user-profile ref="profileComponent" :username="username"></user-profile>
</div>
</template>
<script>
import UserProfile from './UserProfile.vue';
export default {
components: {
UserProfile
},
data() {
return {
username: ''
};
},
methods: {
handleSubmit() {
// Focus on input field
this.$refs.usernameInput.focus();
// Call child component method
if (this.$refs.profileComponent) {
this.$refs.profileComponent.refreshProfile();
}
}
},
mounted() {
// Auto-focus input field after component mounts
this.$refs.usernameInput.focus();
}
};
</script>Conclusion
Vue.js provides multiple approaches to establish connections between DOM elements and component instances. The ref system, as Vue 2's standard method, offers the clearest and most maintainable solution. By properly using the ref attribute, developers can easily create references between templates and JavaScript code while maintaining reactive and component-based characteristics. Although alternatives like __vue__ exist, the refs system should be prioritized in production environments to ensure code stability and maintainability.