Ce guide présente une méthode pour générer des images à partir de descriptions WXML dans le cadre d'une application Uni-app destinée aux mini-programmes. L'objectif est de permettre la sauvegarde de contenu de page sous forme d'image pour une éventuelle téléversement.
Une première tenttaive avec html-to-canvas s'est heurtée à la restriction des mini-programmes : l'impossibilité de manipuler directement le DOM ou d'y accéder sans passer par des méthodes spécifiques comme wx.createSelectorQuery().
La soluiton native des mini-programmes WeChat, wxml-to-canvas, bien que conçue pour générer des images à partir de Canvas WXML, présente une configuration spécifique aux mini-programmes natifs, ce qui pose des problèmes d'intégration avec Uni-app.
Intégration de wxml-to-canvas dans Uni-app
-
Téléchargez l'exemple de code fourni par le mini-programme WeChat officiel.
-
Dans le répertoire racine de votre projet Uni-app, créez un dossier
wxcomponents. Copiez-y les dossierswidget-uietwxml-to-canvasprovenant de la sectionminiprogram_npmde l'exemple. -
Modifiez le fichier
/wxcomponents/wxml-to-canvas/index.jscomme suit :// Ligne originale : // module.exports = require("widget-ui"); // Ligne modifiée : module.exports = require("../widget-ui/index.js"); -
Configurez votre fichier
pages.jsonpour que Uni-app inclue correctement le dosierwxcomponentslors du packaging :{ "pages": [ { "path": "pages/share", "style": { "usingComponents": { "wxml-to-canvas": "/wxcomponents/wxml-to-canvas/index" } } } // ... autres pages ] } -
Créez ou modifiez votre page principale, par exemple
pages/share.vue:<template> <view class="share-page"> <view class="share-page-box" id="box" v-if="isCanvasVisible" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"> <wxml-to-canvas class="widget-renderer" :width="canvasWidth" :height="canvasHeight"></wxml-to-canvas> </view> <view class="share-page-btn" @tap="saveAsImage"> <button class="btn-big" :style="getButtonStyle">Enregistrer l'image</button> </view> </view> </template> <script> import { generateWxmlContent, generateStyleSheet } from './contentGenerator.js'; export default { data() { return { isCanvasVisible: false, canvasWidth: 320, canvasHeight: 480, deviceScreenWidth: null, deviceScreenHeight: null, titleText: '', imageUrl: '', chapterList: [], canvasComponent: null, }; }, onLoad(options) { console.log('Options reçues :', options); this.titleText = 'Génération Canvas via WXML (Exemple)'; this.imageUrl = 'https://via.placeholder.com/150'; // Remplacez par une URL d'image valide this.chapterList = ['Chapitre 1', 'Chapitre 2', 'Chapitre 3']; // Liste d'exemples // Récupérer les informations système wx.getSystemInfo({ success: (res) => { console.log("Informations système :", res); this.deviceScreenWidth = res.screenWidth; // Il est recommandé de calculer ou de fixer la hauteur pour éviter les problèmes de dépassement de texte. this.deviceScreenHeight = 1000; this.canvasWidth = this.deviceScreenWidth; this.canvasHeight = this.deviceScreenHeight; this.isCanvasVisible = true; // Ajustement de la largeur du conteneur pour le rendu dynamique setTimeout(() => { wx.showLoading({ title: 'Génération de l\'image...' }); // Sélection du composant wxml-to-canvas this.canvasComponent = this.selectComponent('.widget-renderer'); this.renderContentToCanvas(); }, 1000); } }); }, methods: { // Rendu WXML vers Canvas renderContentToCanvas() { console.log('Composant Canvas :', this.canvasComponent); const dynamicWxml = generateWxmlContent(this.titleText, this.imageUrl, this.chapterList); const dynamicStyle = generateStyleSheet(this.deviceScreenWidth, this.canvasWidth, this.canvasHeight); const renderPromise = this.canvasComponent.renderToCanvas({ wxml: dynamicWxml, style: dynamicStyle, }); renderPromise.then((res) => { console.log('Rendu Canvas réussi'); wx.hideLoading(); }).catch((err) => { console.error('Erreur lors du rendu Canvas :', err); wx.hideLoading(); }); }, // Enregistrement de l'image saveAsImage() { const capturePromise = this.canvasComponent.canvasToTempFilePath(); capturePromise.then(result => { const imagePath = result.tempFilePath; console.log('Chemin temporaire de l\'image :', imagePath); // Ici, vous pouvez utiliser imagePath pour le téléversement ou d'autres actions. }).catch(err => { console.error('Erreur lors de la capture du Canvas :', err); }); }, } }; </script> -
Créez un nouveau fichier, par exemple
pages/contentGenerator.js, pour définir le contenu WXML et le style :/** * Génère le contenu WXML sous forme de chaîne de caractères. * @param {string} title Le titre à afficher. * @param {string} imgSrc L'URL de l'image. * @param {string[]} chapterData Les éléments de chapitre. * @returns {string} La chaîne WXML générée. */ const generateWxmlContent = (title, imgSrc, chapterData) => ` <view class="container"> <image src="${imgSrc}" class="profile-pic"/> <text class="title-text">${title}</text> ${chapterData.map((chapter, index) => ` <text class="chapter-content">${chapter}</text> `).join('')} </view> `; /** * Génère les styles pour le Canvas. * @param {number} screenWidth La largeur de l'écran du périphérique. * @param {number} canvasWidth La largeur du Canvas. * @param {number} canvasHeight La hauteur du Canvas. * @returns {object} L'objet de styles. */ const generateStyleSheet = (screenWidth, canvasWidth, canvasHeight) => { return { "container": { width: canvasWidth, height: canvasHeight, position: 'relative', overflow: 'hidden', backgroundColor: '#f0f0f0', // Couleur de fond légère }, "title-text": { fontSize: 24, // Taille de police plus grande pour le titre color: '#1a1a1a', // Couleur de texte plus foncée marginTop: canvasWidth * 0.1, marginBottom: canvasWidth * 0.05, width: canvasWidth * 0.8, textAlign: 'center', fontWeight: 'bold', // Ajout de gras pour le titre }, "chapter-content": { fontSize: 16, // Taille de police pour le contenu color: '#4d4d4d', // Couleur de texte un peu plus claire width: canvasWidth * 0.8, marginBottom: screenWidth * 0.03, // Espacement ajusté marginLeft: canvasWidth * 0.1, lineHeight: 24, // Hauteur de ligne pour une meilleure lisibilité }, "profile-pic": { width: canvasWidth * 0.4, height: screenWidth * 0.3, // Hauteur proportionnelle à la largeur marginTop: canvasWidth * 0.1, marginLeft: canvasWidth * 0.3, marginBottom: canvasWidth * 0.08, borderRadius: screenWidth * 0.05, // Coin légèrement arrondi overflow: 'hidden', border: '2px solid #cccccc', // Bordure légère }, }; }; module.exports = { generateWxmlContent, generateStyleSheet };Il est important de noter que le WXML retourné par
generateWxmlContentest une chaîne de caractères représentant le rendu final. Les directives commewx:ifouwx:forne sont pas directement supportées. Pour implémenter des logiques conditionnelles ou des boucles, vous devez les gérer en JavaScript dans la fonction de génération de chaîne WXML. -
Rendu final et considérations :
wxml-to-canvasprend en charge uniquement les élémentsview,textetimage.- Il est impératif de définir les propriétés
widthetheightpour chaque élément rendu. - Par défaut, la disposition des éléments est gérée via Flexbox. Vous pouvez modifier l'orientation avec la propriété
flexDirection: "column".