An Introduction To Vue $refs
The $refs
property in Vue is used to reference DOM elements in the Vue instance's templates.
A common use case for $refs
is focusing on a DOM element when a certain event happens. The autofocus
property works on page loads. But what if you want to give focus back to the username
input if login failed?
If you give the username
input a ref
attribute in your template, you can then access
the username
input using this.$refs.username
as shown below. You can then call
the built-in Element#focus()
function to give focus to the username
input.
const app = new Vue({
data: () => ({ username: '', password: '', failed: false }),
methods: {
login: async function() {
// Simulate that login always fails, just for this example
this.failed = true;
// Give focus back to `username` input. If you change the
// 'ref' attribute in the template to 'usernameRef', you
// would do `this.$refs.usernameRef` here.
this.$refs.username.focus();
}
},
template: `
<div>
<input type="text" v-model="username" ref="username" id="username">
<input type="password" v-model="password">
<button v-on:click="login()">Login</button>
<div v-if="failed" id="failed">
Login Failed!
</div>
</div>
`
});
With v-for
When you use ref
with the v-for
directive,
Vue gives you a native JavaScript array of elements, not just a single element.
For example, suppose you have a list of <input>
tags, and you want users
to be able to navigate between inputs using the up and down arrow keys.
You can access the individual <input>
elements using $refs
and call
focus()
whenever the user presses up or down:
const app = new Vue({
data: () => ({ cells: ['foo', 'bar', 'baz'].map(val => ({ val })) }),
mounted: function() {
let cur = 0;
this.$refs.inputs[0].focus();
document.addEventListener('keyup', ev => {
console.log('Got event', ev)
cur = this.$refs.inputs.findIndex(el => document.activeElement === el);
if (cur === -1) {
cur = 0;
}
const numEls = this.cells.length;
if (ev.keyCode === 38) { // Up arrow
cur = (numEls + cur - 1) % numEls;
this.$refs.inputs[cur].focus();
} else if (ev.keyCode === 40) { // Down arrow
cur = (cur + 1) % numEls;
this.$refs.inputs[cur].focus();
}
});
},
template: `
<div>
<div v-for="cell in cells">
<input v-model="cell.val" ref="inputs">
</div>
</div>
`
});