Selección y recorte de imágenes en mini-programas con carga al servidor

Descripción general

En los mini-programas de WeChat, una funcionalidad común es permitir a los usuarios seleccinoar una imagen de su galería o cámara, recortarla en un formato específico (generalmente cuadrado para fotos de perfil) y enviarla al servidor. Este artículo detalla la implementación utilizando la librería WeCropper.

Configuración del componente de recorte

El primer paso es configurar las opciones del recortador de imágenes en el archivo de lógica de la página. Se obtienen las dimensiones del dispositivo para crear un área de trabajo proporcional.

// Obtención de información del dispositivo
const infoDispositivo = wx.getSystemInfoSync();
const anchoCanvas = infoDispositivo.windowWidth;
const altoCanvas = infoDispositivo.windowHeight - 150;

// Configuración de opciones del recortador
data: {
    fotoPerfil: "",
    opcionesRecortador: {
        id: 'lienzoRecorte',
        idDestino: 'lienzoDestino',
        pixelRatio: infoDispositivo.pixelRatio,
        width: anchoCanvas,
        height: altoCanvas,
        imagenOrigen: '',
        escalaMaxima: 2.5,
        factorZoom: 8,
        areaRecorte: {
            x: (anchoCanvas - 140) / 2,
            y: (anchoCanvas - 140) / 2,
            ancho: 140,
            alto: 140
        }
    }
}

Inicialización del recortador

En el evento onLoad, se inicializa el componente WeCropper y se configura la imagen inicial si existe previamente.

onLoad: function(opciones) {
    const { opcionesRecortador } = this.data;
    
    // Cargar imagen previa si existe
    if (app.datosGlobales.fotoPerfil) {
        opcionesRecortador.imagenOrigen = app.datosGlobales.fotoPerfil;
    } else {
        opcionesRecortador.imagenOrigen = 'imagen_predeterminada';
    }

    if (opcionesRecortador.imagenOrigen) {
        this.recortador = new WeCropper(opcionesRecortador)
            .on('ready', (contexto) => {
                console.log('Recortador inicializado correctamente');
            })
            .on('antesCarga', (contexto) => {
                wx.showToast({
                    titulo: 'Cargando imagen',
                    icono: 'loading',
                    duracion: 3000
                });
            })
            .on('imagenCargada', (contexto) => {
                wx.hideToast();
            });
    }
}

Manejo de eventos táctiles

El插件 recibe eventos táctiles para permitir al usuario manipular la imagen dentro del área de recorte mediante gestos de arrastre y zoom.

// Eventos táctiles para el recortador
iniciarTocar(evento) {
    this.recortador.iniciarTocar(evento);
},
moverTocar(evento) {
    this.recortador.moverTocar(evento);
},
finalizarTocar(evento) {
    this.recortador.finalizarTocar(evento);
}

Selección de imagen

Esta función permite al usuario elegir una nueva imagen desde la galería o la cámara del dispositivo.

seleccionarImagen() {
    const referencia = this;
    wx.elegirImagen({
        cantidad: 1,
        tipoTamano: ['comprimido'],
        origen: ['album', 'camara'],
        exito(resultado) {
            const rutaOrigen = resultado.tempFilePaths[0];
            referencia.recortador.insertarOrigen(rutaOrigen);
            
            setTimeout(() => {
                referencia.generarImagenRecortada();
            }, 2000);
        }
    });
}

Generación y envío de imagen

Una vez que el usuario ha ajustado el recorte, se genera la imagen procesada y se envía al servidor mediante uploadFile.

generarImagenRecortada() {
    var aqui = this;
    this.recortador.obtenerImagenRecortada((rutaTemporal) => {
        if (rutaTemporal) {
            console.log('Imagen procesada:', rutaTemporal);
            
            wx.showToast({
                titulo: 'Enviando...',
                icono: 'loading',
                mascara: true,
                duracion: 10000
            });
            
            let token = wx.obtenerStorageSync("cookie");
            
            wx.subirArchivo({
                url: app.datosGlobales.host + '/api/cliente/info/recopilar/subirFoto',
                rutaArchivo: rutaTemporal,
                nombre: 'archivo',
                header: {
                    "Content-type": "multipart/form-data",
                    "cookie": token
                },
                exito: function(respuesta) {
                    if (respuesta.statusCode == 200) {
                        console.log(JSON.parse(respuesta.data).data);
                    }
                    aqui.setData({
                        fotoPerfil: JSON.parse(respuesta.data).data
                    });
                    app.datosGlobales.fotoPerfil = JSON.parse(respuesta.data).data;
                    aqui.guardarDatos(3);
                },
                fallo: function(respuesta) {
                    wx.hideToast();
                    wx.showModal({
                        titulo: 'Error',
                        contenido: 'Error al subir la imagen',
                        mostrarCancelar: false
                    });
                }
            });
        } else {
            console.log('Error al obtener la imagen procesada');
        }
    });
}

Guardado de información

Finalmente, se guardan los datos del perfil del usuario, incluyendo la URL de la imagen procesada.

async guardarDatos(tipo) {
    let parametros = {};
    
    if (tipo == '3') {
        parametros.fotoPerfil = this.data.fotoPerfil;
        app.datosGlobales.fotoPerfil = this.data.fotoPerfil;
    }
    
    let respuesta = await Util.peticion('/endpoint/actualizar', parametros, true);
    if (respuesta) {
        wx.showToast({
            titulo: 'Guardado exitosamente',
            mascara: true
        });
        setTimeout(() => {
            this.obtenerInfoUsuario();
        }, 1500);
    }
}

Estructura WXML

La plantilla WXML integra el componente del recortador y el área de visualización de la foto de perfil.

<import src="./we/we-cropper.wxml"/>
<view class="contenedor-recortador">
    <template is="we-cropper" data="{{...opcionesRecortador}}"/>
</view>

<view class="seccion-perfil">
    <view class="contenedor-foto" bindtap='seleccionarImagen'>
        <view class="cuadro-foto">
            <view class="imagen-foto">
                <image src="{{fotoPerfil}}" class="imagen-deslizable" mode="widthFix" />
            </view>
            <view class="icono-camara">
                <image src="https://ejemplo.com/icono-camara.png" class="imagen-deslizable" mode="widthFix" />
            </view>
        </view>
    </view>
</view>

Plantilla del componente

El archivo WXML del插件 define dos elementos canvas: uno para la interación del usuario y otro para generar la imagen resultado.

<template name="we-cropper">
    <canvas
        class="recortador"
        disable-scroll="true"
        bindtouchstart="iniciarTocar"
        bindtouchmove="moverTocar"
        bindtouchend="finalizarTocar"
        style="width:{{ancho}}px;height:{{alto}}px;background-color: rgba(0, 0, 0, 0.8)"
        canvas-id="{{id}}">
    </canvas>
    <canvas
        class="recortador"
        disable-scroll="true"
        style="position: fixed; top: -{{ancho * pixelRatio}}px; left: -{{alto * pixelRatio}}px; width:{{ancho * pixelRatio}}px;height:{{alto * pixelRatio}}px;"
        canvas-id="{{idDestino}}">
    </canvas>
</template>

Consideraciones importantes

  • El插件 requiere la inclusión de los archivos JavaScript y WXML en el proyecto
  • Es necesario ajustar las dimensiones del área de recorte según los requisitos de la aplicación
  • El tiempo de espera de 2 segundos después de seleccionar la imagen garantiza que el recortador esté listo antes de generar el resultado
  • La imagen se envía como multipart/form-data al endpoint correspondiente del servidor

Etiquetas: WeChat mini-program imagen-recorte carga-archivos JavaScript

Publicado el 6-25 03:04