Acceso Directo al DOM y Instancias con ref en Vue.js

En el desarrollo con Vue.js, aunque el enlace de datos reactivo es la práctica recomendada, existen escenarios donde es necesario interactuar directamente con el DOM o acceder a la instancia de un componente hijo. Para ello, el framework proporciona el atributo ref en las planitllas y la propiedad $refs en la lógica del componente.

Uso de referencias en elementos DOM nativos

El objeto $refs almacena referencias a los elementos del DOM registrados con el atributo ref. Es fundamental tener en cuenta que estas referencias solo están disponibles después de que el componente haya sido montado. Por lo tanto, cualquier operación que dependa de $refs debe ejecutarse dentro del hook mounted.

A continuación, se muestra un ejemplo básico donde se registra un elemento div y se accede a su contenido y atributos una vez inicializada la aplicación.

<div id="contenedor-principal"></div>
<script type="module">
  const { createApp } = Vue;
  
  createApp({
    mounted() {
      // Acceso al nodo DOM registrado como 'bloqueSuperior'
      const nodo = this.$refs.bloqueSuperior;
      console.log('Elemento DOM:', nodo);
      console.log('Contenido interno:', nodo.innerHTML);
      console.log('Atributo data-id:', nodo.attributes['data-id'].value);
    },
    template: `
      <div>
        <div ref="bloqueSuperior" data-id="100">Contenido de prueba</div>
      </div>
    `
  }).mount('#contenedor-principal');
</script>

En este contexto, this.$refs.bloqueSuperior devuelve el elemento HTML real. Esto permite leer propiedades como innerHTML o acceder a la lista de atributos nativos del navegador.

Uso de referencias en componentes hijos

Cuando el atributo ref se utiliza sobre un componente personalizado, la referencia almacenada en $refs apunta a la instancia del componente hijo. Esto habliita la comunicación padre-hijo imperativa, permitiendo invocar métodos públicos o leer estados internos definidos en data.

El siguiente ejemplo define un componente global llamado WidgetContador y demuestra cómo el componente padre puede interactuar con él.

<div id="app-raiz"></div>
<script type="module">
  const { createApp } = Vue;
  const app = createApp({
    mounted() {
      const hijo = this.$refs.widgetHijo;
      
      // Acceso a la instancia del componente
      console.log('Instancia:', hijo);
      
      // Ejecución de método definido en el hijo
      hijo.ejecutarTarea();
      
      // Lectura de propiedad reactiva
      console.log('Estado interno:', hijo.titulo);
      
      // Acceso al elemento raíz del componente hijo
      console.log('Raíz DOM:', hijo.$el);
      console.log('HTML Raíz:', hijo.$el.innerHTML);
      
      // Acceso a opciones de configuración
      console.log('Opciones:', hijo.$options);
    },
    template: `
      <div>
        <widget-contador ref="widgetHijo" />
      </div>
    `
  });

  // Definición del componente hijo
  app.component('widget-contador', {
    data() {
      return {
        titulo: 'Datos del Widget',
        contador: 0
      };
    },
    methods: {
      ejecutarTarea() {
        console.log('Método del hijo ejecutado');
        this.contador++;
      }
    },
    template: `<div class="widget-clase">{{ titulo }}</div>`
  });

  app.mount('#app-raiz');
</script>

Al utilizar this.$refs.widgetHijo, se obtiene acceso completo a la instancia Vue del componente hijo. Propiedades como $el permiten llegar al nodo DOM raíz del componente, mientras que $data y $options exponen el estado interno y la configuración de opciones respectivamente. Es importante recordar que este acoplamiento directo debe usarse con precaución para no violar el flujo de datos unidireccional típico de Vue.

Para acceder a los atributos específicos del template renderizado por el componente hijo, se combina la referencia con la propiedad $el, ya que $refs apunta a la instancia lógica y no directamente al nodo DOM cuando se trata de componentes.

Etiquetas: vuejs refs dom-manipulation component-lifecycle

Publicado el 8-6 13:44