Table des matières
4. Middleware d'authentification Laravel" >4. Middleware d'authentification Laravel
6. Actualisation indolore de l'idée access_token" >6. Actualisation indolore de l'idée access_token
Maison interface Web uni-app applet uni-app série d'authentification d'autorité Laravel + jwt

applet uni-app série d'authentification d'autorité Laravel + jwt

Nov 27, 2020 pm 05:15 PM
uni-app 小程序 权限认证

La colonne

tutoriel de développement uni-app présente une série de méthodes d'authentification des autorisations.

applet uni-app série d'authentification d'autorité Laravel + jwt

Recommandé : Tutoriel de développement d'uni-app

Description de l'environnement

uni-app
laravel 5.7 + jwt-auth 1.0.0

Description générale de l'authentification d'autorité

  1. Structure de la table de conception
  2. Classe de requête frontale
  3. Le package JS lié à l'authentification d'autorité comprend un jeton d'actualisation non conscient
  4. laravel auth Le middleware contient un jeton d'actualisation non perceptuel
  5. Obtenez le numéro de téléphone mobile pour vous connecter
  6. Actualisation indolore access_token Idées
  7. Comment le mini programme détermine la connexion statut

La structure de la table de conception

n'est pas différente de la table de conception générale S'il s'agit d'une applet multiplateforme, la table commune. est associé via account_id.

CREATE TABLE `users` (
  `u_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '账号id',
  `u_username` varchar(15) NOT NULL DEFAULT '' COMMENT '手机号隐藏 ',
  `u_nickname` varchar(15) NOT NULL COMMENT '分配用户名',
  `u_headimg` varchar(200) DEFAULT NULL COMMENT '头像',
  `u_province` varchar(50) DEFAULT NULL,
  `u_city` varchar(50) DEFAULT NULL,
  `u_platform` varchar(30) NOT NULL COMMENT '平台:小程序wx,bd等',
  `u_mobile` char(11) NOT NULL COMMENT '手机号必须授权',
  `u_openid` varchar(100) DEFAULT NULL COMMENT 'openid',
  `u_regtime` timestamp NULL DEFAULT NULL COMMENT '注册时间',
  `u_login_time` timestamp NULL DEFAULT NULL COMMENT '最后登陆时间',
  `u_status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0禁用1正常',
  `account_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '平台联合id',
  PRIMARY KEY (`u_id`),
  KEY `platform` (`u_platform`,`u_mobile`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
Copier après la connexion

2. Classe de requête frontale

Une meilleure classe de requêteluch-request qui prend en charge la modification dynamique des configurations et des intercepteurs, dans le plug uni-app. -dans les marchés peuvent être trouvés.
applet uni-app série dauthentification dautorité Laravel + jwt
Le request.js n'a pas besoin d'être modifié. La logique personnalisée se trouve dans index.js.
index.js

import Request from './request';import jwt from '@/utils/auth/jwt.js'; // jwt 管理 见下文const http = new Request();const baseUrl = 'http://xxx'; // api 地址var platform = ''; // 登陆时需知道来自哪个平台的小程序用户// #ifdef MP-BAIDUplatform = 'MP-BAIDU';// #endif/* 设置全局配置 */http.setConfig((config) => { 
  config.baseUrl = baseUrl; //设置 api 地址
  config.header = {
    ...config.header  }
  return config})/* 请求之前拦截器 */http.interceptor.request((config, cancel) => {
    if (!platform) {cancel('缺少平台参数');}
    config.header = {
        ...config.header,
        platform:platform    } 
  if (config.custom.auth) {
      // 需要权限认证的路由 需携带自定义参数 {custom: {auth: true}}
    config.header.Authorization = jwt.getAccessToken();
  }
  return config})http.interceptor.response(async (response) => { /* 请求之后拦截器 */
    console.log(response);
    // 如果是需要权限认证的路由
    if(response.config.custom.auth){

            if(response.data.code == 4011){
                // 刷新 token
                jwt.setAccessToken(response.data.data.access_token);
                // 携带新 token 重新请求
                let repeatRes = await http.request(response.config);
                if ( repeatRes ) {
                    response = repeatRes;
                }
            }

    }
    return response}, (response) => { // 请求错误做点什么
    if(response.statusCode == 401){
        getApp().globalData.isLogin = false;
        uni.showToast({icon:'none',duration:2000,title: "请登录"})
    }else if(response.statusCode == 403){
        uni.showToast({
            title: "您没有权限进行此项操作,请联系客服。",
            icon: "none"
        });
    }
  return response})export {
  http}
Copier après la connexion

Montage global

import Vue from 'vue'import App from './App'import { http } from '@/utils/luch/index.js' //这里Vue.prototype.$http = http

Vue.config.productionTip = falseApp.mpType = 'app'const app = new Vue({
    ...App})app.$mount()
Copier après la connexion

3. >

authorize.js

Pour des raisons d'espace, le code complet n'est pas publié et les autres ne sont pas utilisés. Par exemple, uni.checkSession(), étant donné que jwt est utilisé pour reprendre l'état de connexion de l'applet, cette méthode n'est pas utilisée actuellement.

// #ifndef H5const loginCode = provider => {
    return new Promise((resolve, reject) => {
        uni.login({
            provider: provider,
            success: function(loginRes) {
                if (loginRes && loginRes.code) { resolve(loginRes.code) } else { reject("获取code失败") }
            },
            fail:function(){ reject("获取code失败")}
        });
    })}// #endifexport {
    loginCode //登录获取code}
Copier après la connexion

jwt.js

Gère spécialement access_token, pas beaucoup de code, et y met également la gestion des informations utilisateur.

const tokenKey = 'accessToken';//键值const userKey    = 'user'; // 用户信息// tokenconst getAccessToken = function(){
    let token='';
    try {token = 'Bearer '+ uni.getStorageSync(tokenKey);} catch (e) {}
    return token;}const setAccessToken = (access_token) => {
    try {uni.setStorageSync(tokenKey, access_token);return true;} catch (e) {return false;}}const clearAccessToken = function(){
    try {uni.removeStorageSync(tokenKey);} catch (e) {}}// userinfoconst setUser = (user)=>{
    try {uni.setStorageSync(userKey, user);return true;} catch (e) {return false;}}const getUser = function(){
    try {return uni.getStorageSync(userKey)} catch (e) {return false;}}const clearUser = function(){
    try {uni.removeStorageSync(userKey)} catch (e) {}}export default {
  getAccessToken,setAccessToken,clearAccessToken,getUser,setUser,clearUser}
Copier après la connexion

auth.js

Gère uniquement la connexion, pourquoi le mettre dans un fichier séparé, rien d'autre, car il est utilisé partout

import {loginCode} from '@/utils/auth/authorize.js';import jwt from '@/utils/auth/jwt.js';import {http} from '@/utils/luch/index.js';const login=function(detail){
    return new Promise((resolve, reject) => {
        loginCode().then(code=>{
            detail.code = code;
            return http.post('/v1/auth/login',detail);
        })
        .then(res=>{
            jwt.setAccessToken(res.data.data.access_token);
            jwt.setUser(res.data.data.user);
            getApp().globalData.isLogin = true;
            resolve(res.data.data.user);
        })
        .catch(err=>{
            reject('登陆失败')
        })
    })}export default {login}
Copier après la connexion
Voici un peu sur jwt-auth. 1. Lorsqu'un jeton expire et que le jeton est actualisé, le jeton d'origine sera répertorié dans la « liste noire » et deviendra invalide. En fait, jwt-auth gère également un fichier pour stocker la liste noire, et les jetons invalides ne seront effacés que lorsque le délai d'actualisation sera atteint. Par exemple, le délai d'expiration est de 10 minutes et la limite d'actualisation est d'un mois. Pendant cette période, un grand nombre de listes noires seront générées, ce qui affectera les performances, alors essayez d'ajuster autant que possible, par exemple, l'expiration. le temps est de 60 minutes, la limite d'actualisation est de deux semaines ou le délai d'expiration est d'une semaine et la limite d'actualisation est Aucun problème pendant un mois. 2. Concernant la solution d'actualisation indolore, lorsque le jeton expire, le frontal que j'utilise fait deux requêtes pour terminer l'actualisation, dont l'utilisateur n'est pas au courant. Il existe une solution sur Internet qui demande directement l'actualisation et la connexion automatiques, mais je. Je ne l'ai pas utilisé. Quant à pourquoi, je ne sais pas, je ne comprends rien d'autre. Cependant, j'ai compilé diverses exceptions jwt et les étudiants peuvent les personnaliser si nécessaire. TokenExpiredException expire, TokenInvalidException ne peut pas analyser le jeton, UnauthorizedHttpException ne transporte pas le jeton, JWTException le jeton expire ou atteint la limite d'actualisation ou une erreur interne jwt.

<?phpnamespace  App\Http\Middleware;use App\Library\Y;use Closure;use Exception;use Tymon\JWTAuth\Exceptions\JWTException;use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;use Tymon\JWTAuth\Exceptions\TokenExpiredException;class ApiAuth extends BaseMiddleware{

    public function handle($request, Closure $next, $guard = &#39;api&#39;)
    {
        // 在排除名单中 比如登录
        if($request->is(...$this->except)){
            return $next($request);
        }

        try {
            $this->checkForToken($request);// 是否携带令牌
            if ( $this->auth->parseToken()->authenticate() ) {
                return $next($request); //验证通过
            }
        }catch(Exception $e){
            // 如果token 过期
            if ($e instanceof TokenExpiredException) {
                try{
                    // 尝试刷新 如果成功 返给前端 关于前端如何处理的 看前边 index.js
                    $token = $this->auth->refresh();
                    return Y::json(4011, $e->getMessage(),['access_token'=>$token]);
                }catch(JWTException $e){
                    // 达到刷新时间上限
                    return Y::json(401, $e->getMessage());
                }
            }else{
                // 其他各种 直接返回 401 状态码 不再细分
                return Y::json(401, $e->getMessage());
            }
        }
    }

    protected $except = [
        'v1/auth/login',
    ];}
Copier après la connexion
L'auteur pense que ce type de rafraîchissement est très difficile à maintenir. Il est préférable d'utiliser directement un jeton unique. Il est préférable de se reconnecter après son expiration. Cela dépend si le mini-programme ou le site Web nécessite une sécurité renforcée. Généralement, une sécurité élevée n'est pas requise. Il est préférable d'utiliser un jeton unique pour la requête https. Le middleware ici n'a besoin que de auth()->check(), true. signifie l'état de connexion, false signifie non connecté.

5. Obtenez un numéro de téléphone portable pour vous connecter
<template>
    <view>
        <button>获取手机号</button>
        <button>获取用户数据</button>
        <button>清除用户数据</button>
    </view></template><script>
    import auth from &#39;@/utils/auth/auth.js&#39;;
    import jwt from &#39;@/utils/auth/jwt.js&#39;;
    var _self;
    export default{
        data() {return {}},
        onLoad(option) {},
        onShow(){},
        methods: {
            decryptPhoneNumber: function(e){
                // console.log(e.detail);
                if( e.detail.errMsg == "getPhoneNumber:ok" ){ //成功
                    auth.login(e.detail);
                }
            },
            me: function(){
                this.$http.get(&#39;/v1/auth/me&#39;,{custom: {auth: true}}).then(res=>{
                    console.log(res,&#39;success&#39;)
                }).catch(err=>{
                    console.log(err,&#39;error60&#39;)
                })
            },
            clear: function(){
                jwt.clearAccessToken();
                jwt.clearUser();
                uni.showToast({
                    icon: &#39;success&#39;,
                    title: &#39;清除成功&#39;,
                    duration:2000,
                });
            }
        },
        components: {}
    }</script><style></style>
Copier après la connexion

Backend

// 登陆
    public function login(Request $request)
    {
        $platform = $request->header('platform');
        if(!$platform || !in_array($platform,User::$platforms)){
            return Y::json(1001, '不支持的平台类型');
        }
        $post = $request->only(['encryptedData', 'iv', 'code']);
        $validator = Validator::make($post, [
            'encryptedData' => 'required',
            'iv'            => 'required',
            'code'          => 'required'
        ]);
        if ($validator->fails()) {return Y::json(1002,'非法请求');}
        switch ($platform) {
            case 'MP-BAIDU':
                $decryption = (new BdDataDecrypt())->decrypt($post['encryptedData'],$post['iv'],$post['code']);
                break;
            default:
                $decryption = false;
                break;
        }
        // var_dump($decryption);
        if($decryption !== false){
            $user = User::where('u_platform',$platform)->where('u_mobile',$decryption['mobile'])->first();
            if($user){
                $user->u_login_time = date('Y-m-d H:i:s',time());
                $user->save();
            }else{
                $user = User::create([
                    'u_username'=> substr_replace($decryption['mobile'],'******',3,6),
                    'u_nickname'=> User::crateNickName(),
                    'u_platform'=> $platform,
                    'u_mobile'   => $decryption['mobile'],
                    'u_openid'  => $decryption['openid'],
                    'u_regtime' => date('Y-m-d H:i:s',time())
                ]);
            }

            $token = auth()->login($user);
            return Y::json(
                array_merge(
                    $this->respondWithToken($token),
                    ['user'=>['nickName'=>$user->u_nickname]]
                )
            );
        }
        return Y::json(1003,'登录失败'); 
    }
    // 返回 token
    protected function respondWithToken($token)
    {
        return ['access_token' => $token];
    }
Copier après la connexion

Téléphone portable décryptage du numéro

<?phpnamespace  App\Library;use App\Library\Y;class BdDataDecrypt{

    private $_appid;
    private $_app_key;
    private $_secret;
    private $_session_key;

    public function __construct()
    {
        $this->_appid       = env('BD_APPID');
        $this->_app_key     = env('BAIDU_KEY');
        $this->_secret      = env('BD_SECRET');
    }

    public function decrypt($encryptedData, $iv, $code){
        $res = $this->getSessionKey($code);
        if($res === false){return false;}
        $data['openid'] = $res['openid'];
        $res = $this->handle($encryptedData,$iv,$this->_app_key,$res['session_key']);
        if($res === false){return false;}
        $res = json_decode($res,true);
        $data['mobile'] = $res['mobile'];
        return $data;

    }

    public function getSessionKey($code)
    {
        $params['code']         = $code;
        $params['client_id']     = $this->_app_key;
        $params['sk']             = $this->_secret;
        $res = Y::curl("https://spapi.baidu.com/oauth/jscode2sessionkey",$params,0,1);
        // var_dump($res);
        /**
         * 错误返回
         * array(3) {
            ["errno"]=>
            int(1104)
            ["error"]=>
            string(33) "invalid code , expired or revoked"
            ["error_description"]=>
            string(33) "invalid code , expired or revoked"
            }
            成功返回:
            array(2) {
                ["openid"]=>
                string(26) "z45QjEfvkUJFwYlVcpjwST5G8w"
                ["session_key"]=>
                string(32) "51b9297ababbcf43c1a099256bf82d75"
            }
         */
        if( isset($res['error']) ){
            return false;
        }
        return $res;
    }

    /**
     * 官方 demo
     * return string(24) "{"mobile":"18288881111"}" or false
     */
    private function handle($ciphertext, $iv, $app_key, $session_key)
    {
        $session_key = base64_decode($session_key);
        $iv = base64_decode($iv);
        $ciphertext = base64_decode($ciphertext);

        $plaintext = false;
        if (function_exists("openssl_decrypt")) {
            $plaintext = openssl_decrypt($ciphertext, "AES-192-CBC", $session_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
        } else {
            $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, null, MCRYPT_MODE_CBC, null);
            mcrypt_generic_init($td, $session_key, $iv);
            $plaintext = mdecrypt_generic($td, $ciphertext);
            mcrypt_generic_deinit($td);
            mcrypt_module_close($td);
        }
        if ($plaintext == false) {
            return false;
        }
        // trim pkcs#7 padding
        $pad = ord(substr($plaintext, -1));
        $pad = ($pad  32) ? 0 : $pad;
        $plaintext = substr($plaintext, 0, strlen($plaintext) - $pad);
        $plaintext = substr($plaintext, 16);
        $unpack = unpack("Nlen/", substr($plaintext, 0, 4));
        $content = substr($plaintext, 4, $unpack['len']);
        $app_key_decode = substr($plaintext, $unpack['len'] + 4);
        return $app_key == $app_key_decode ? $content : false;
    }}
Copier après la connexion
Tout d'abord, la méthode que j'utilise est qu'une fois que le backend a déterminé que le jeton a expiré, il essaie automatiquement d'actualiser et l'actualisation est renvoyée avec succès. Pour le nouveau jeton, le frontal capture le code convenu de la réponse back-end dans l'intercepteur de réponse, stocke le nouveau jeton, puis effectue une deuxième demande dans le. fin, elle est perçue comme une demande normale.

Une autre façon de penser est qu'une fois que le backend tente de s'actualiser avec succès, il se connectera automatiquement pour l'utilisateur actuel et renverra le nouveau jeton dans l'en-tête. Le frontend est uniquement responsable du stockage.

7. 小程序如何判断登陆状态

其实思路也很简单,非前后端分离怎么做的,前后端分离就怎么做,原理一样。非前后端分离,在每次请求时都会读取 session ,那么前后端分离,更好一些,有些公开请求不走中间件,也就无需判断登陆态,只有在需要权限认证的页面,在页面初始化时发出一次请求走中间件,以此判断登陆状态。
定义全局登陆检查函数

import jwt from '@/utils/auth/jwt.js';Vue.prototype.checkLogin = function(){
    var TOKEN  = jwt.getAccessToken();
    return new Promise((resolve, reject) => {
        if(TOKEN){
            http.get('/v1/auth/check',{custom: {auth: true}}).then(res=>{
                // 通过中间件 一定是登陆态
                resolve(true);
            }).catch(err=>{
                resolve(false);
                console.log(err) // 这里是401 403 后端500错误或者网络不好
            })
        }else{
            resolve(false) //没有token 一定是未登陆
        }
    })}
Copier après la connexion

笔者最终放弃上面的这种检查登录的方式,直接检验storage中有user和token即视为登录状态。以被动的验证代替主动去验证,就是说用户执行一个请求,返回401,那么就改变登录状态。以后再补充。

前端

<script>
    export default {
        data() {
            return {
                isLogin:null
            }
        },
        onLoad() {
            this.checkLogin().then(loginStatus=>{
                this.isLogin = loginStatus;
            });
        },
        methods: {
        },
        components: {}
    }</script>
Copier après la connexion

                                                       

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Développer l'applet WeChat en utilisant Python Développer l'applet WeChat en utilisant Python Jun 17, 2023 pm 06:34 PM

Avec la popularité de la technologie Internet mobile et des smartphones, WeChat est devenu une application indispensable dans la vie des gens. Les mini-programmes WeChat permettent aux gens d'utiliser directement des mini-programmes pour résoudre certains besoins simples sans télécharger ni installer d'applications. Cet article explique comment utiliser Python pour développer l'applet WeChat. 1. Préparation Avant d'utiliser Python pour développer l'applet WeChat, vous devez installer la bibliothèque Python appropriée. Il est recommandé d'utiliser ici les deux bibliothèques wxpy et itchat. wxpy est une machine WeChat

Les petits programmes peuvent-ils réagir ? Les petits programmes peuvent-ils réagir ? Dec 29, 2022 am 11:06 AM

Les mini-programmes peuvent utiliser React. Comment l'utiliser : 1. Implémentez un moteur de rendu basé sur "react-reconciler" et générez un DSL ; 2. Créez un mini composant de programme pour analyser et restituer le DSL 3. Installez npm et exécutez le développeur Build ; npm dans l'outil ; 4. Introduisez le package dans votre propre page, puis utilisez l'API pour terminer le développement.

Comment développer uni-app en VSCode ? (Partage du tutoriel) Comment développer uni-app en VSCode ? (Partage du tutoriel) May 13, 2022 pm 08:11 PM

Comment développer uni-app en VSCode ? L'article suivant partagera avec vous un didacticiel sur le développement d'uni-app dans VSCode. Il s'agit peut-être du didacticiel le meilleur et le plus détaillé. Venez jeter un oeil !

Implémenter des effets de retournement de cartes dans les mini-programmes WeChat Implémenter des effets de retournement de cartes dans les mini-programmes WeChat Nov 21, 2023 am 10:55 AM

Implémentation d'effets de retournement de cartes dans les mini-programmes WeChat Dans les mini-programmes WeChat, la mise en œuvre d'effets de retournement de cartes est un effet d'animation courant qui peut améliorer l'expérience utilisateur et l'attractivité des interactions d'interface. Ce qui suit présentera en détail comment implémenter l'effet de retournement de carte dans l'applet WeChat et fournira des exemples de code pertinents. Tout d'abord, vous devez définir deux éléments de carte dans le fichier de mise en page du mini-programme, un pour afficher le contenu avant et un pour afficher le contenu arrière. L'exemple de code spécifique est le suivant : &lt;!--index.wxml-. -&gt;&l

Alipay a lancé le mini-programme « Chinese Character Picking-Rare Characters » pour collecter et compléter la bibliothèque de personnages rares. Alipay a lancé le mini-programme « Chinese Character Picking-Rare Characters » pour collecter et compléter la bibliothèque de personnages rares. Oct 31, 2023 pm 09:25 PM

Selon les informations de ce site du 31 octobre, le 27 mai de cette année, Ant Group a annoncé le lancement du « Projet de sélection de caractères chinois » et a récemment inauguré de nouveaux progrès : Alipay a lancé le mini-programme « Sélection de caractères chinois-Caractères rares ». pour collecter des collections de la société Les personnages rares complètent la bibliothèque de personnages rares et offrent différentes expériences de saisie pour les personnages rares afin d'aider à améliorer la méthode de saisie des caractères rares dans Alipay. Actuellement, les utilisateurs peuvent accéder à l'applet « Caractères peu communs » en recherchant des mots-clés tels que « capture de caractères chinois » et « caractères rares ». Dans le mini-programme, les utilisateurs peuvent soumettre des images de caractères rares qui n'ont pas été reconnus et saisis par le système. Après confirmation, les ingénieurs d'Alipay effectueront des entrées supplémentaires dans la bibliothèque de polices. Ce site Web a remarqué que les utilisateurs peuvent également découvrir la dernière méthode de saisie par fractionnement de mots dans le mini-programme. Cette méthode de saisie est conçue pour les mots rares dont la prononciation n'est pas claire. Démantèlement utilisateur

Utilisez uniapp pour développer une navigation cartographique simple Utilisez uniapp pour développer une navigation cartographique simple Jun 09, 2022 pm 07:46 PM

Comment utiliser Uniapp pour développer une navigation cartographique simple ? Cet article vous donnera une idée pour créer une carte simple. J'espère qu'il vous sera utile !

Comment Uniapp réalise une conversion rapide entre les mini-programmes et H5 Comment Uniapp réalise une conversion rapide entre les mini-programmes et H5 Oct 20, 2023 pm 02:12 PM

La manière dont Uniapp peut réaliser une conversion rapide entre les mini-programmes et le H5 nécessite des exemples de code spécifiques. Ces dernières années, avec le développement de l'Internet mobile et la popularité des smartphones, les mini-programmes et le H5 sont devenus des formulaires de candidature indispensables. En tant que cadre de développement multiplateforme, uniapp peut réaliser rapidement la conversion entre les petits programmes et H5 sur la base d'un ensemble de codes, améliorant considérablement l'efficacité du développement. Cet article présentera comment Uniapp peut réaliser une conversion rapide entre les mini-programmes et H5, et donnera des exemples de code spécifiques. 1. Introduction à uniapp unia

Parlons de la façon d'utiliser Uniapp pour développer un jeu de serpent ! Parlons de la façon d'utiliser Uniapp pour développer un jeu de serpent ! May 20, 2022 pm 07:56 PM

Comment utiliser Uniapp pour développer un jeu de serpent ? L'article suivant vous guidera étape par étape dans la mise en œuvre du jeu Snake dans uniapp. J'espère qu'il vous sera utile !

See all articles