Referências do Modelo de Marcação
Embora o modelo de interpretação declarativa da Vue abstraia a maior parte das operações diretas do DOM por ti, ainda existe casos onde precisamos de acesso direto aos elementos do DOM subjacentes. Para conseguir isto, podemos utilizar o atributo especial ref
:
template
<input ref="input">
O ref
é um atributo especial, similar ao atributo key
discutido no capitulo v-for
. Ele permite-nos obter uma referência direta para um elemento de DOM especifico ou instância de componente depois de ser montada. Isto pode ser útil quando quiseres, por exemplo, focar programaticamente uma entrada (input
) na montagem do componente, ou inicializar uma biblioteca de terceiro sobre um elemento.
Acessando as Referências
Para obter a referência com a API de Composição, precisamos declarar uma ref
com o mesmo nome:
vue
<script setup>
import { ref, onMounted } from 'vue'
// declara uma `ref` para segurar a referência de elemento
// o nome deve corresponder ao valor de `ref` do modelo de marcação
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="input" />
</template>
Se não estiveres utilizando a <script setup>
, certifica-te de também retornar a referência a partir de setup()
:
js
export default {
setup() {
const input = ref(null)
// ...
return {
input
}
}
}
Nota que só podes acessar a referência depois do componente ser montado. Se tentares acessar input
em uma expressão de modelo de marcação, será null
na primeira interpretação. Isto porque o elemento não existe até depois da primeira interpretação!
Se estiveres tentando observar as mudanças de uma referência de modelo de marcação, certifica-te de representar o caso onde a referência tem o valor null
:
js
watchEffect(() => {
if (input.value) {
input.value.focus()
} else {
// ainda não está montado, ou o elemento foi desmontado (por exemplo, pelo v-if)
}
})
Consulte também: Atribuindo Tipos às Referências do Modelo de Marcação
Referências dentro de v-for
Exige a versão 3.2.25 em diante
Quando o ref
é utilizado dentro de v-for
, a referência correspondente deve conter uma valor de arranjo, que será povoada com os elementos depois de montar:
vue
<script setup>
import { ref, onMounted } from 'vue'
const list = ref([
/* ... */
])
const itemRefs = ref([])
onMounted(() => console.log(itemRefs.value))
</script>
<template>
<ul>
<li v-for="item in list" ref="itemRefs">
{{ item }}
</li>
</ul>
</template>
Deve ser notado que o arranjo de referência não garante a mesma ordem conforme o arranjo de origem.
Referências de Função
No lugar de uma chave de sequência de caracteres, o atributo key
também pode ser atado a uma função, que será chamada em cada atualização do componente e dar-te-á completa flexibilidade sobre onde guardar a referência do elemento. A função recebe a referência do elemento como primeiro argumento:
template
<input :ref="(el) => { /* atribui `el` a uma propriedade ou referência */ }">
Nota que estamos utilizando uma vinculação de :ref
dinâmica assim podemos passar nela uma função no lugar de uma sequência de caracteres de nome de referência. Quando o elemento é desmontado, o argumento será null
. Tu podes, claro, utilizar um método no lugar de uma função em linha.
Referência no Componente
Esta seção presume conhecimento de Componentes. Esteja a vontade para saltá-la e voltar mais tarde.
O ref
também pode ser utilizado sobre um componente filho. Neste caso a referência será aquela de uma instância de componente:
vue
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
const child = ref(null)
onMounted(() => {
// child.value segurará uma instância de <Child />
})
</script>
<template>
<Child ref="child" />
</template>
Se o componente filho estiver utilizando a API de Opções ou não utilizando <script setup>
, a instância referenciada será idêntica ao this
do componente filho, o que significa que o componente pai terá total acesso as todas propriedades e métodos do componente filho. Isto torna-o fácil de criar detalhes de implementação atrelados firmemente entre o pai e o filho, assim as referências do componente só deve ser utilizadas quando forem absolutamente necessários - na maioria dos casos, deves tentar implementar interações entre o pai e o filho utilizando as interfaces de propriedades e emissão padrão primeiro.
Uma exceção é que componentes utilizando <script setup>
são privados por padrão: um componente pai referenciando um componente filho utilizando <script setup>
não será capaz de acessar nada a menos que o componente filho escolha expor uma interface publica utilizando a macro defineExpose
:
vue
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
// Macros do compilador, tais como `defineExpose`, não precisam ser importados.
defineExpose({
a,
b
})
</script>
Quando um pai recebe uma instância deste componente através de referências de modelo de marcação, a instância recuperada será da forma { a: number, b: number }
(referências são desembrulhadas automaticamente como instâncias normais).
Consulte também: Atribuindo Tipos às Referências do Modelo de Marcação do Componente