Implementación de Edición por Doble Clic en el-table sin Condiciones v-if/v-else Mediante Herencia con Vue.extend

Planteamiento del Problema

Se requiere habilitar la edición directa en una tabla al hacer doble clic sobre una celda. La solución común implica duplicar elementos en el DOM, usando v-if y v-else para alternar entre un span de visualización y un el-input de edición. Sin embargo, esto genera código repetitivo para cada columna. Una alternativa más eficeinte es crear dinámicamente componentes de entrada y eliminarlos al finalizar la edición.

Enfoque de la Solución

Se aprovecha la capacidda de Vue para heredar componentes mediante Vue.extend(). Al hacer doble clic en una celda, se instancia un componente el-input que reemplaza temporalmente el contenido visual. Al perder el foco, se revierte al estado original.

Pasos Clave

  • Capturar el evento de doble clic en la tabla para identificar la fila, columna y DOM objetivo.
  • Crear una clase constructora a partir de un componente el-input personalizado.
  • Montar dinámicamente la instancia del componente en el DOM de la celda.
  • Al deetctar la pérdida de foco, desmontar el componente y restaurar el contenido estático.

Resolución de Desafíos Técnicos

Generación Dinámica del Componente de Entrada

No es posible crear el-input directamente con métodos del DOM. En su lugar, se define un componente Vue que encapsula el input y se hereda con Vue.extend().

<!-- EditorInput.vue -->
<template>
  <div class="celda-entrada">
    <el-input
      ref="campoEntrada"
      size="mini"
      v-model.trim="valorCelda"
      @blur="manejarDesenfoque"
    />
  </div>
</template>

<script>
export default {
  props: {
    valorCelda: {
      type: [String, Number],
      default: ''
    },
    alDesenfocar: Function,
    domCelda: HTMLElement,
    datosFila: Object,
    clavePropiedad: String
  },
  mounted() {
    this.$refs.campoEntrada.focus();
  },
  methods: {
    manejarDesenfoque() {
      this.alDesenfocar({
        valorCelda: this.valorCelda,
        domCelda: this.domCelda,
        datosFila: this.datosFila,
        clavePropiedad: this.clavePropiedad
      });
    }
  }
};
</script>

<style scoped>
.celda-entrada {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  padding: 0 8px;
  box-sizing: border-box;
}
</style>

Para simplificar la restauración, también se hereda un componente span.

<!-- VisualizadorCelda.vue -->
<template>
  <span class="celda-visualizacion">{{ valorCelda }}</span>
</template>

<script>
export default {
  props: {
    valorCelda: {
      type: [String, Number],
      default: ''
    }
  }
};
</script>

Herencia y Exportación de Clases

Se utiliza Vue.extend() para convertir los componentes en funciones constructoras.

// fabricaComponentes.js
import Vue from 'vue';
import EditorInput from './EditorInput.vue';
import VisualizadorCelda from './VisualizadorCelda.vue';

export const ConstructorInput = Vue.extend(EditorInput);
export const ConstructorSpan = Vue.extend(VisualizadorCelda);

Manejo del Doble Clic y Restauración

En el componente principal, se vincula el evento cell-dblclick y se gestiona la lógica de reemplazo.

<template>
  <el-table
    @cell-dblclick="manejarDobleClic"
    :data="registrosTabla"
    border
  >
    <el-table-column align="center" label="Nombre" prop="nombre" />
    <el-table-column align="center" label="Edad" prop="edad" />
  </el-table>
</template>

<script>
import { ConstructorInput, ConstructorSpan } from './fabricaComponentes';

export default {
  data() {
    return {
      registrosTabla: [
        { nombre: 'Ana', edad: 28 },
        { nombre: 'Luis', edad: 35 }
      ],
      valorPrevio: null
    };
  },
  methods: {
    manejarDobleClic(fila, columna, celda) {
      this.valorPrevio = fila[columna.property];
      const instanciaInput = new ConstructorInput({
        propsData: {
          valorCelda: fila[columna.property],
          alDesenfocar: this.guardarCambios,
          domCelda: celda,
          datosFila: fila,
          clavePropiedad: columna.property
        }
      });
      instanciaInput.$mount(celda.children[0]);
    },
    guardarCambios({ valorCelda, domCelda, datosFila, clavePropiedad }) {
      if (valorCelda !== this.valorPrevio) {
        datosFila[clavePropiedad] = valorCelda;
        // Aquí se podría enviar una petición al servidor
      }
      const instanciaSpan = new ConstructorSpan({
        propsData: { valorCelda }
      });
      instanciaSpan.$mount(domCelda.children[0]);
    }
  }
};
</script>

Este método evita el uso de banderas y directivas condicionales, centralizando la lógica de edición de manera dinámica y reutilizable. La herencia de componentes permite extender el enfoque a otros controles como el-select.

Etiquetas: vue.js Element UI el-table Vue.extend herencia de componentes

Publicado el 6-6 22:13