Visión general
v-md-editor es un componente de edición Markdown para Vue que funciona tanto en Vue 2 como en Vue 3. Para incorporar la subida de imágenes es necesario implementar un endpoint en el servidor y manejar el evento upload-image desde el cliente.
Endpoint en el servidor
El siguiente controlador de Spring Boot recibe el archivo, lo almacena en disco y devuelve la URL pública resultante:
@RestController
@RequestMapping("/recursos")
public class RecursoController {
@PostMapping("/imagen")
public Resultado<String> guardarImagen(
@RequestParam("archivo") MultipartFile archivo,
@RequestParam(value = "ruta", required = false) String ruta) {
String urlPublica = almacenarArchivo(archivo, ruta);
return Resultado.ok(urlPublica, "Imagen guardada correctamente");
}
}
Ejemplo de respuesta exitosa:
{
"codigo": 200,
"mensaje": "Imagen guardada correctamente",
"datos": "http://127.0.0.1:9005/recursos/ae83c411083848a69efccf7094183348.png"
}
Componente Vue
En el template se habilita el menú de subida local pasando un array vacío a disabled-menus y se escucha el evento upload-image:
<template>
<div class="editor-markdown">
<v-md-editor
v-model="texto"
mode="edit"
height="400px"
:disabled-menus="[]"
@upload-image="procesarImagen"
/>
<v-md-editor v-model="texto" mode="preview" />
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { subirImagen } from "@/services/imagenService";
const texto = ref("Introduce el contenido aquí");
const procesarImagen = (evento: any, insertarImagen: any, archivos: File[]) => {
if (!archivos || archivos.length === 0) return;
const payload = new FormData();
payload.append("archivo", archivos[0]);
subirImagen(payload)
.then((respuesta) => {
if (respuesta.codigo === 200 && respuesta.datos) {
insertarImagen({ url: respuesta.datos });
} else {
ElMessage.warning(respuesta.mensaje || "No se pudo subir la imagen");
}
})
.catch(() => ElMessage.error("Fallo la subida de la imagen"));
};
</script>
El servicio que envía el FormData mediante Axios puede verse así:
import axios from "@/utils/peticion";
export function subirImagen(formData: FormData) {
return axios.post("/recursos/imagen", formData, {
headers: { "Content-Type": "multipart/form-data" }
});
}
El objeto FormData permite empaquetar el archivo como multipart/form-data, de modo que el backend pueda recibirlo con MultipartFile. Una vez obtenida la URL, se invoca insertarImagen para renderizar la imagan en el editor.
Propiedades más útiles
text: cadena Markdown que se quiere previsualizar.v-model: enlace bidirectional con el contenido.mode: modo de visualización. Valores:edit,editable,preview.default-fullscreen: indica si se activa pantalla completa por defecto.disabled-menus: menús deshabilitados. Dejar vacío para permitir la subida local de imágenes.