La version bêta publique du mini-programme WeChat a déclenché une vague d'apprentissage sur le développement du mini-programme. Il est multiplateforme, prêt à l'emploi, comparable à l'expérience native, avec une documentation complète et un cadre de développement efficace qui en a apporté de nombreuses. surprises pour les développeurs. A travers cet article, nous analyserons la structure du mini programme et partagerons notre expérience de développement avec tout le monde.
Caractéristiques du mini programme :
Architecture du mini programme
Le cadre du mini programme WeChat se compose de deux parties : la couche d'affichage et l'application. Couche logique de service, la couche View est utilisée pour restituer la structure de la page et la couche AppService est utilisée pour le traitement logique, les demandes de données et les appels d'interface. Elles s'exécutent dans deux threads.
La couche de vue est rendue à l'aide de WebView et la couche logique est exécutée à l'aide de JSCore.
La couche de vue et la couche logique communiquent via le JSBridage de la couche système. La couche logique notifie la couche de vue des modifications de données et déclenche les mises à jour de page dans la couche de vue. couche logique pour le traitement métier.
Lorsque le mini programme sera démarré, le package complet du mini programme sera téléchargé à partir du CDN
Vue (page vue)
La couche de vue est écrite par WXML et WXSS et est affichée par composants.
Reflétez les données de la couche logique dans la vue et envoyez en même temps les événements de la couche de vue à la couche logique.
1. Vue - WXML
WXML (WeiXin Markup Language)
Prend en charge la liaison de données
Prend en charge l'arithmétique et les opérations logiques
Prend en charge modèles et références
Prend en charge l'ajout d'événements (bindtap)
Compilateur wxml : wcc Convertir le fichier wxml en js Méthode d'exécution : wcc index.wxml
Vue - WXSS
WXSS (feuilles de style WeiXin)
Prend en charge la plupart des fonctionnalités CSS
Ajouter une unité de taille rpx, qui peut être adaptée en fonction de la largeur de l'écran
Utiliser les instructions @import peut être importé dans des feuilles de style externes
Ne prend pas en charge les sélecteurs multi-niveaux - pour éviter d'être détruit par la structure interne du composant
compilateur wxss : wcsc Convertir les fichiers wxss Pour la méthode d'exécution js : wcsc index.wxss
3. Vue – Sélecteurs WXSS
WXSS prend actuellement en charge les sélecteurs suivants :
4 , Vue - Composant
L'applet fournit une série de composants permettant de développer des fonctions métiers. La comparaison avec les balises HTML5 selon les fonctions est la suivante :
Mini programme Le composant est basé sur le standard Web Component
Utilisez le framework Polymer pour implémenter le composant Web
5. Composant
Le composant actuellement implémenté par Native Il y a Couche WebView
App Service (couche logique)
La couche logique traite les données et les envoie à la couche de vue, et en même temps accepte les événements commentaires de la couche de vue
1. Entrée de l'applet App ( ) ; Entrée de la page Page( )
3. Fournir des API riches, telles que les données utilisateur WeChat, l'analyse, le paiement et autres WeChat. -capacités spécifiques.
4. Chaque page a une portée indépendante et offre des fonctionnalités modulaires.
5. Liaison de données, distribution d'événements, gestion du cycle de vie, gestion du routage
Environnement d'exécution
IOS - JSCore
Android - Analyseur X5 JS
DevTool - nwjs Chrome Kernel
1.
La liaison de données utilise la syntaxe Moustache (doubles accolades) pour envelopper les variables. Les données dynamiques proviennent des données de la page correspondante. Les données peuvent être modifiées via la méthode setData.
La liaison d'événement est écrite de la même manière que les attributs de composant, sous la forme d'une clé et d'une valeur. La clé commence par bind ou catch, suivi du type d'événement, tel que bindtap, catchtouchstart et. value est une chaîne, une fonction du même nom doit être définie dans la page correspondante.
2. Service d'application - Cycle de vie
3. - API
API communique avec Native via JSBridge
4. App Service - Routeur
navigateTo(OBJECT)
Conservez la page actuelle, accédez à une page de l'application et utilisez naviguerBack pour revenir à la page d'origine. Le chemin de la page ne peut comporter que cinq niveaux
redirectTo(OBJECT)
Fermez la page actuelle et accédez à une page de l'application.
navigateBack(OBJECT)
Fermez la page actuelle et revenez à la page précédente ou à la page multi-niveaux. Vous pouvez obtenir la pile de pages actuelle via getCurrentPages()) et décider du nombre de niveaux à renvoyer.
5. Expérience de développement de mini-programmes
1. Problèmes avec les mini-programmes
Les mini-programmes utilisent toujours WebView pour le rendu, pas le rendu natif
Nécessite un développement indépendant. , ne peut pas être exécuté dans des environnements non-WeChat.
Les développeurs ne peuvent pas étendre de nouveaux composants.
L'en-tête renvoyé par l'interface du serveur ne peut pas être exécuté, tel que : Set-Cookie.
Les bibliothèques JS qui s'appuient sur l'environnement du navigateur ne peuvent pas être utilisées car elles sont exécutées par JSCore et n'ont pas d'objets fenêtre ou document.
Les locaux (images, polices, etc.) ne peuvent pas être utilisés dans WXSS.
WXSS est converti en js au lieu de css pour la compatibilité avec rpx.
WXSS ne prend pas en charge les sélecteurs en cascade.
L'applet ne peut pas ouvrir la page et ne peut pas lancer l'APP.
Le mini programme ne peut pas avoir le même nom que le compte officiel, donc le nom du mini programme est devenu : Optionnel Stocks, Didi Chuxing DiDi.
2. Avantages dont les petits programmes peuvent tirer des leçons
Créez une nouvelle WebView à l'avance et préparez-vous au nouveau rendu de page.
La couche Vue et la couche logique sont séparées, pilotées par les données et n'exploitent pas directement le DOM.
Utilisez Virtual DOM pour les mises à jour locales.
Tous utilisent https pour assurer la sécurité lors de la transmission.
Utilisez les fonctionnalités hors ligne.
Développement de composants front-end.
Ajoutez une unité rpx pour isoler la taille de l'appareil et faciliter le développement.
3. "Mini programme" qui se démarque de WeChat : PWA Progressive Applications
Le nom complet de PWA est Progressive Web Apps. Lorsqu'il est traduit en chinois, il s'agit de Progressive Web Apps. par Google le 15 juin 2015. concept présenté.
Les Progressive Web Apps sont une expérience qui combine les meilleures fonctionnalités du Web et des applications natives. Il est très avantageux pour les nouveaux utilisateurs, qui peuvent y accéder directement dans le navigateur sans installer d'application. Au fil du temps, à mesure que les utilisateurs développent une connexion avec l’application, celle-ci deviendra de plus en plus puissante. Il se charge rapidement, peut envoyer des messages pertinents même dans des environnements réseau faibles et peut être ajouté à l'écran d'accueil comme une application native, offrant ainsi une expérience de navigation en plein écran.
PWA présente les caractéristiques suivantes :
Amélioration progressive - Les navigateurs qui prennent en charge les nouvelles fonctionnalités bénéficient d'une meilleure expérience et les navigateurs qui ne les prennent pas en charge conservent l'original. expérience.
Accès hors ligne : les techniciens de service peuvent travailler hors ligne ou dans des environnements avec des vitesses de réseau faibles.
Application de type natif - Utilisez le modèle de shell d'application pour obtenir une expérience de type application native.
Installable - Permet aux utilisateurs de conserver les applications qui leur sont utiles sur leur écran d'accueil sans passer par l'App Store.
Facile à partager : les applications peuvent être facilement partagées via une URL.
Mises à jour continues - Grâce au processus de mise à jour du service worker, l'application peut toujours rester à jour.
Sécurité - Fournissez des services via HTTPS pour empêcher la surveillance du réseau et garantir que le contenu n'est pas falsifié.
Recherchable - Rend les applications Web détectables par les moteurs de recherche grâce aux métadonnées des manifestes du W3C et à l'enregistrement des techniciens de service.
Revisiter : permettez aux utilisateurs de revenir facilement grâce à des fonctionnalités telles que l'envoi de messages.
Web App Manifest rend le Web plus natif (configuration par défaut, paramètres plein écran, etc.).
Les Service Workers améliorent les fonctionnalités Web
Mise en cache et mise à jour hors ligne des ressources via Service Works
App Shell améliore l'efficacité de l'affichage
App Shell (shell d'application) est le HTML, CSS et JavaScript le plus basique requis pour l'interface utilisateur de l'application, immédiatement après le premier chargement Il est mis en cache et n'a pas besoin d'être téléchargé à chaque fois qu'il est utilisé. Au lieu de cela, seules les données requises sont chargées de manière asynchrone pour conserver l'interface utilisateur localisée.
Une application todos développée sur la base du mini-cadre de programme
Ce qui suit est une introduction aux points clés du développement de cette application :
1. La structure des répertoires et la configuration de cette application ne seront pas présentées en détail. Elles sont décrites en détail dans la section Document-Framework. Il n'y a pas de HTML et de CSS dans cette plateforme, remplacés par wxml et wxss. Il n'y a presque aucune différence entre wxss et css. L'inconvénient est qu'il n'est pas aussi puissant que css et prend en charge des sélecteurs limités. Mais l’avantage est que puisqu’il n’existe qu’une seule plateforme, WeChat, il n’y a quasiment aucun problème de compatibilité et vous pouvez utiliser la technologie CSS standard et mise à jour. Seules les balises des composants fournis par la plateforme peuvent être utilisées dans wxml. Des exemples d'utilisation de chaque composant dans wxml peuvent être trouvés dans la section Document - Composants. Donc en fait, il n’y a aucun problème pour écrire wxml et wxss.
2. wxml prend en charge les fonctionnalités suivantes :
À l'exception des modèles et des références, tous les autres sont utilisés dans l'application todo, mais les détails de chaque fonctionnalité ne sont pas utilisés, sélectionnez uniquement les fonctions appropriées. selon les besoins de l'application. J'ai vu un article il y a quelques jours disant que l'applet WeChat pouvait être implémentée sur la base du framework vue, j'ai donc jeté un œil à la documentation de vue. Pour la liaison de données, le rendu conditionnel, le rendu de liste et les événements, nous avons examiné en détail l'utilisation de vue. En comparaison, les fonctionnalités fournies par wxml sont assez similaires aux fonctionnalités associées de vue, mais il n'y a pas tellement de fonctions, il n'est donc pas facile d'utiliser directement les fonctionnalités du framework vue dans de petits programmes. La meilleure pratique reste basée sur les instructions fournies dans les documents officiels. Si les fonctions ne sont pas mentionnées dans les documents officiels, cela ne fonctionnera certainement pas si vous les utilisez en devinant. J'ai vérifié les prototypes de certains objets par impression, et je n'ai pas trouvé plus de méthodes d'instance que dans les documents officiels, ce qui montre que la fonction framework du mini programme est effectivement limitée.
3. Wxss peut en fait être écrit en less ou en sass, tant que le sélecteur répond aux exigences du framework. En raison de contraintes de temps, je ne l'ai pas essayé dans cette application.
4. Pas de liaison bidirectionnelle. Dans Vue, une instance Vue est un modèle de vue ; les mises à jour des données dans la couche de vue seront renvoyées au modèle en temps réel ; les mises à jour du modèle seront également renvoyées à la vue en temps réel. Dans le mini-programme, il n'y a pas de liaison bidirectionnelle et la mise à jour de la vue ne sera pas directement synchronisée avec le modèle ; vous devez obtenir les données directement de la couche de vue dans le rappel d'événement correspondant, puis mettre à jour le modèle ; via setData. Le mini programme utilisera setData en interne, puis restituera la page. Par exemple, pour un seul élément de tâche, l'opération de bascule est :
toggleTodo: function( e ) { var id = this.getTodoId( e, 'todo-item-chk-' ); var value = e.detail.value[ 0 ]; var complete = !!value; var todo = this.getTodo( id ); todo.complete = complete; this.updateData( true ); this.updateStorage(); },
Dans le code ci-dessus, la valeur de la case à cocher dans un seul élément de tâche est obtenue via e.detail.value[0], et le statut complet de la tâche est jugé à travers cette valeur. Enfin, dans updateData, le contenu du modèle est actualisé via la méthode setData. Ce n'est qu'ainsi que les statistiques en bas de l'application seront mises à jour après l'opération de basculement.
5. Lors de la liaison d'un événement, les paramètres ne peuvent pas être transmis, un seul événement peut être transmis. Par exemple, dans l'opération de bascule ci-dessus, je voulais en fait transmettre l'ID de la tâche actuelle dans le rappel, mais je n'ai pas pu le faire de toutes les manières possibles. En fin de compte, je n'ai pu le gérer que via la méthode ID : le lier. dans wxml. Sur le composant de l'événement, ajoutez un identifiant. Cet identifiant ne peut pas être répété dans toute la page, l'identifiant doit donc être préfixé, puis ajoutez la valeur todo id à la fin de l'identifiant ; , il peut être obtenu via e.currentTarget.id Pour l'identifiant du composant, supprimez le préfixe id correspondant et vous obtiendrez la valeur id de la tâche. C'est une méthode actuellement utilisée, je pense qu'elle n'est pas très élégante, j'espère trouver une meilleure façon de la mettre en œuvre plus tard.
6. L'effet de chargement est pris en compte dans l'application, qui doit être obtenu en utilisant l'attribut de chargement du composant bouton. Mais le chargement n'est qu'un contrôle de style, il ne contrôle pas si le bouton peut être cliqué à plusieurs reprises. Par conséquent, nous devons également utiliser l’attribut désactivé du bouton pour éviter les clics répétés.
Les détails d'implémentation restants se trouvent dans le code source des deux fichiers suivants. Vous êtes invités à signaler les problèmes.
Code source de index.wxml :
<!--list.wxml--> <view class="container"> <view class="app-hd"> <view class="fx1"> <input class="new-todo-input" value="{{newTodoText}}" auto-focus bindinput="newTodoTextInput"/> </view> <button type="primary" size="mini" bindtap="addOne" loading="{{addOneLoading}}" disabled="{{addOneLoading}}"> + Add </button> </view> <view class="todos-list" > <view class="todo-item {{index == 0 ? '' : 'todo-item-not-first'}} {{todo.complete ? 'todo-item-complete' : ''}}" wx:for="{{todos}}" wx:for-item="todo"> <view wx-if="{{!todo.editing}}"> <checkbox-group id="todo-item-chk-{{todo.id}}" bindchange="toggleTodo"> <label class="checkbox"> <checkbox value="1" checked="{{todo.complete}}"/> </label> </checkbox-group> </view> <view id="todo-item-txt-{{todo.id}}" class="todo-text" wx-if="{{!todo.editing}}" bindlongtap="startEdit"> <text>{{todo.text}}</text> </view> <view wx-if="{{!todo.editing}}"> <button id="btn-del-item-{{todo.id}}" bindtap="clearSingle" type="warn" size="mini" loading="{{todo.loading}}" disabled="{{todo.loading}}"> Clear </button> </view> <input id="todo-item-edit-{{todo.id}}" class="todo-text-input" value="{{todo.text}}" auto-focus bindblur="endEditTodo" wx-if="{{todo.editing}}"/> </view> </view> <view class="app-ft" wx:if="{{todos.length > 0}}"> <view class="fx1"> <checkbox-group bindchange="toggleAll"> <label class="checkbox"> <checkbox value="1" checked="{{todosOfUncomplted.length == 0}}"/> </label> </checkbox-group> <text>{{todosOfUncomplted.length}} left.</text> </view> <view wx:if="{{todosOfComplted.length > 0}}"> <button type="warn" size="mini" bindtap="clearAll" loading="{{clearAllLoading}}" disabled="{{clearAllLoading}}"> Clear {{todosOfComplted.length}} of done. </button> </view> </view> <loading hidden="{{loadingHidden}}" bindchange="loadingChange"> {{loadingText}} </loading> <toast hidden="{{toastHidden}}" bindchange="toastChange"> {{toastText}} </toast> </view>
Code source de index.js :
var app = getApp(); Page( { data: { todos: [], todosOfUncomplted: [], todosOfComplted: [], newTodoText: '', addOneLoading: false, loadingHidden: true, loadingText: '', toastHidden: true, toastText: '', clearAllLoading: false }, updateData: function( resetTodos ) { var data = {}; if( resetTodos ) { data.todos = this.data.todos; } data.todosOfUncomplted = this.data.todos.filter( function( t ) { return !t.complete; }); data.todosOfComplted = this.data.todos.filter( function( t ) { return t.complete; }); this.setData( data ); }, updateStorage: function() { var storage = []; this.data.todos.forEach( function( t ) { storage.push( { id: t.id, text: t.text, complete: t.complete }) }); wx.setStorageSync( 'todos', storage ); }, onLoad: function() { this.setData( { todos: wx.getStorageSync( 'todos' ) || [] }); this.updateData( false ); }, getTodo: function( id ) { return this.data.todos.filter( function( t ) { return id == t.id; })[ 0 ]; }, getTodoId: function( e, prefix ) { return e.currentTarget.id.substring( prefix.length ); }, toggleTodo: function( e ) { var id = this.getTodoId( e, 'todo-item-chk-' ); var value = e.detail.value[ 0 ]; var complete = !!value; var todo = this.getTodo( id ); todo.complete = complete; this.updateData( true ); this.updateStorage(); }, toggleAll: function( e ) { var value = e.detail.value[ 0 ]; var complete = !!value; this.data.todos.forEach( function( t ) { t.complete = complete; }); this.updateData( true ); this.updateStorage(); }, clearTodo: function( id ) { var targetIndex; this.data.todos.forEach( function( t, i ) { if( targetIndex !== undefined ) return; if( t.id == id ) { targetIndex = i; } }); this.data.todos.splice( targetIndex, 1 ); }, clearSingle: function( e ) { var id = this.getTodoId( e, 'btn-del-item-' ); var todo = this.getTodo( id ); todo.loading = true; this.updateData( true ); var that = this; setTimeout( function() { that.clearTodo( id ); that.updateData( true ); that.updateStorage(); }, 500 ); }, clearAll: function() { this.setData( { clearAllLoading: true }); var that = this; setTimeout( function() { that.data.todosOfComplted.forEach( function( t ) { that.clearTodo( t.id ); }); that.setData( { clearAllLoading: false }); that.updateData( true ); that.updateStorage(); that.setData( { toastHidden: false, toastText: 'Success' }); }, 500 ); }, startEdit: function( e ) { var id = this.getTodoId( e, 'todo-item-txt-' ); var todo = this.getTodo( id ); todo.editing = true; this.updateData( true ); this.updateStorage(); }, newTodoTextInput: function( e ) { this.setData( { newTodoText: e.detail.value }); }, endEditTodo: function( e ) { var id = this.getTodoId( e, 'todo-item-edit-' ); var todo = this.getTodo( id ); todo.editing = false; todo.text = e.detail.value; this.updateData( true ); this.updateStorage(); }, addOne: function( e ) { if( !this.data.newTodoText ) return; this.setData( { addOneLoading: true }); //open loading this.setData( { loadingHidden: false, loadingText: 'Waiting...' }); var that = this; setTimeout( function() { //close loading and toggle button loading status that.setData( { loadingHidden: true, addOneLoading: false, loadingText: '' }); that.data.todos.push( { id: app.getId(), text: that.data.newTodoText, compelte: false }); that.setData( { newTodoText: '' }); that.updateData( true ); that.updateStorage(); }, 500 ); }, loadingChange: function() { this.setData( { loadingHidden: true, loadingText: '' }); }, toastChange: function() { this.setData( { toastHidden: true, toastText: '' }); } });
最后需要补充的是,这个app在有限的时间内依据微信的官方文档进行开发,所以这里面的实现方式到底是不是合理的,我也不清楚。我也仅仅是通过这个app来了解小程序这个平台的用法。希望微信官方能够推出一些更全面、最好是项目性的demo,在代码层面,给我们这些开发者提供一个最佳实践规范。欢迎有其它的开发思路的朋友,帮我指出我以上实现中的问题。