Skip to content

Refs de la Plantilla

Aunque el modelo de renderizado declarativo de Vue abstrae la mayor parte de las operaciones directas del DOM, puede haber casos en los que necesitemos acceso directo a los elementos subyacentes del DOM. Para ello, podemos utilizar el atributo especial ref:

template
<input ref="input">

ref es un atributo especial, similar al atributo key comentado en el capítulo v-for. Nos permite obtener una referencia directa a un elemento DOM específico o a una instancia de componente hijo después de que se haya montado. Esto puede ser útil cuando se quiere, por ejemplo, enfocar programáticamente una entrada al montar un componente, o inicializar una biblioteca de terceros en un elemento.

Acceso a las Refs

Para obtener la referencia con la Composition API, necesitamos declarar una ref con el mismo nombre:

vue
<script setup>
import { ref, onMounted } from 'vue'

// declarar una ref para mantener la referencia del elemento
// el nombre debe coincidir con el valor de ref de la plantilla
const input = ref(null)

onMounted(() => {
  input.value.focus()
})
</script>

<template>
  <input ref="input" />
</template>

Si no utilizas <script setup>, asegúrate de devolver también la ref de setup():

js
export default {
  setup() {
    const input = ref(null)
    // ...
    return {
      input
    }
  }
}

La ref resultante se expone en this.$refs:

vue
<script>
export default {
  mounted() {
    this.$refs.input.focus()
  }
}
</script>

<template>
  <input ref="input" />
</template>

Ten en cuenta que sólo puedes acceder a la ref después de que el componente esté montado. Si intentas acceder a refs.inputinput en la declaración de la plantilla, resultará undefinednull en la primera renderización. Esto se debe a que el elemento no existe hasta después del primer renderizado.

Si estás intentando vigilar los cambios de una ref de plantillas, asegúrate de tener en cuenta el caso de que la ref tenga un valor nulo:

js
watchEffect(() => {
  if (input.value) {
    input.value.focus()
  } else {
    // no está montado todavía, o el elemento fue
    // desmontado (por ejemplo, por v-if)
  }
})

Véase también: Escritura de Refs de la Plantilla

Refs dentro de v-for

Requiere v3.2.25 o superior

Cuando se utiliza ref dentro de v-for, la ref correspondiente debe contener un valor de Array, que se completará con los elementos después del montaje:

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>

Pruébalo en la Zona de Práctica

Cuando se utiliza ref dentro de v-for, el valor de ref resultante será un array que contiene los elementos correspondientes:

vue
<script>
export default {
  data() {
    return {
      list: [
        /* ... */
      ]
    }
  },
  mounted() {
    console.log(this.$refs.items)
  }
}
</script>

<template>
  <ul>
    <li v-for="item in list" ref="items">
      {{ item }}
    </li>
  </ul>
</template>

Pruébalo en la Zona de Práctica

Hay que tener en cuenta que el array de la ref no garantiza el mismo orden que el array de origen.

Refs de una Función

En lugar de una clave de cadena, el atributo ref también puede vincularse a una función, que será llamada en cada actualización del componente y te ofrece total flexibilidad sobre dónde almacenar la referencia del elemento. La función recibe la referencia del elemento como primer argumento:

template
<input :ref="(el) => { /* asigna el a una propiedad o ref */ }">

Observa que estamos utilizando un enlace dinámico :ref para poder pasarle una función en lugar de una cadena de nombre ref. Cuando el elemento es desmontado, el argumento será null. Por supuesto, puedes utilizar un método en lugar de una función inline.

Ref en un Componente

Esta sección supone el conocimiento de Componentes. Siéntete libre de saltarla y volver más tarde.

ref también puede utilizarse en un componente hijo. En este caso la referencia será la de una instancia del componente:

vue
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

const child = ref(null)

onMounted(() => {
  // child.value contendrá una instancia de <Child />
})
</script>

<template>
  <Child ref="child" />
</template>
vue
<script>
import Child from './Child.vue'

export default {
  components: {
    Child
  },
  mounted() {
    // this.$refs.child contendrá una instancia de <Child />
  }
}
</script>

<template>
  <Child ref="child" />
</template>

Si el componente hijo utiliza la Options API o no utiliza <script setup>, laLa instancia referenciada será idéntica a la del componente hijo this, lo que significa que el componente padre tendrá acceso completo a cada propiedad y método del componente hijo. Esto facilita la creación de detalles de implementación estrechamente acoplados entre el padre y el hijo, por lo que las referencias a los componentes sólo deben utilizarse cuando sea absolutamente necesario. En la mayoría de los casos, debes tratar de implementar las interacciones padre / hijo utilizando primero las interfaces estándar props y emit.

Una excepción aquí es que los componentes que utilizan <script setup> son privados por defecto: un componente padre que hace referencia a un componente hijo que utiliza <script setup> no podrá acceder a nada a menos que el componente hijo elija exponer una interfaz pública utilizando la macro defineExpose:

vue
<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

Cuando un padre obtiene una instancia de este componente a través de las referencias de la plantilla, la instancia recuperada tendrá la forma { a: número, b: número } (las referencias se desempaquetan automáticamente como en las instancias normales).

Véase también: Escritura de Refs de la Plantilla del Componentes

La opción expose se puede utilizar para limitar el acceso a una instancia hija:

js
export default {
  expose: ['publicData', 'publicMethod'],
  data() {
    return {
      publicData: 'foo',
      privateData: 'bar'
    }
  },
  methods: {
    publicMethod() {
      /* ... */
    },
    privateMethod() {
      /* ... */
    }
  }
}

En el ejemplo anterior, un padre referenciando este componente a través de la ref de plantilla sólo podrá acceder a publicData y publicMethod.

Refs de la Plantilla has loaded