Maison  >  Article  >  interface Web  >  Comment développer un composant de couche élastique globale dans uni-app (exemple de code)

Comment développer un composant de couche élastique globale dans uni-app (exemple de code)

青灯夜游
青灯夜游avant
2022-03-07 19:59:585484parcourir

Comment développer un composant de couche élastique globale dans uni-app ? L'article suivant vous présentera, à travers des exemples, comment implémenter un composant de couche élastique globale dans uni-app. J'espère qu'il vous sera utile !

Comment développer un composant de couche élastique globale dans uni-app (exemple de code)

La société dispose d'une application écrite à l'aide du framework uni-app. La couche élastique à l'intérieur utilise essentiellement l'uni.showModal officiel et d'autres API pour implémenter la couche élastique. Elle se comporte comme une couche élastique native sur l'appareil. À la demande du client, il a fallu le modifier selon le style conçu, nous avons donc commencé à mettre en œuvre un tel composant.

Selon les méthodes et méthodes fréquemment utilisées par la couche élastique, les attributs et méthodes dont elle a besoin peuvent être grossièrement listés :

  • Type : alerte/confirmation, etc. alert/confirm
  • 展示图标 icon
  • 展示内容 content
  • 可以api调用
  • 支持promise,可以使用$api.xx().then

前几项就很好做,就在data中定义好字段,外层直接拿官方的轮子uni-popup,这样少写一些控制弹出的逻辑(懒的),这样大致结构就写好了

// template部分
<uni-popup ref="popup" :maskClick="maskClick">
		<view class="st-layer" :style="{ width: width }">
			<view class="st-layer__content">
				<!-- #ifndef APP-NVUE -->
				<text class="st-layer__icon" :class="option.iconClass || getIconClass()"
					v-if="option.type !== &#39;none&#39; && option.showIcon"></text>
				<!-- #endif -->
				<view class="st-layer__msg" v-if="option.msg">
					<text>{{ option.msg }}</text>
				</view>
			</view>
			<view class="st-layer__footer" :class="{&#39;is-reverse-cofirmcancel&#39; : isReverseConfirmCancel}" v-if="option.showConfirmButton || option.showCancelButton">
				<view class="st-layer__footer__btn st-layer__footer__btn--confirm" @tap.stop="confirmClick"
					v-if="option.showConfirmButton"><text>确认</text></view>
				<view class="st-layer__footer__btn st-layer__footer__btn--cancel" @tap.stop="cancelClick"
					v-if="option.showCancelButton"><text>取消</text></view>
			</view>
		</view>
	</uni-popup>

然后js部分先简单实现了一些open和close方法

data() {
    return {
            option: {}
    }
},
methods: {
    open(option) {
        let defaultOption = {
                showCancelButton: false, // 是否显示取消按钮
                cancelButtonText: &#39;取消&#39;, // 取消按钮文字
                showConfirmButton: true, // 是否显示确认按钮
                confirmButtonText: &#39;取消&#39;, // 确认按钮文字
                showIcon: true, // 是否显示图标
                iconClass: null, // 图标class自定义
                type: &#39;none&#39;, // 类型
                confirm: null, // 点击确认后的逻辑
                cancel: null, // 点击取消后的逻辑
                msg: &#39;&#39;
        }
        this.option = Object.assign({}, defaultOption, option)
        this.$refs.popup.open()
    },
    close() {
            this.$refs.popup.close()
    },
    confirmClick() {
            const confirmHandler = this.option.confirm
            if (confirmHandler && typeof confirmHandler === &#39;function&#39;) {
                    confirmHandler()
            }
            this.close()
            this.$emit(&#39;confirm&#39;)
    },
    cancelClick() {
            const cancelHandler = this.option.cancel
            if (cancelHandler && typeof cancelHandler === &#39;function&#39;) {
                    cancelHandler()
            }
            this.close()
            this.$emit(&#39;cancel&#39;)
    }
}

目前在其他页面已经可以使用

// test.vue  可以使用uni-app的 [easycom组件规范](https://uniapp.dcloud.io/component/README?id=easycom%e7%bb%84%e4%bb%b6%e8%a7%84%e8%8c%83),不用写import语句
<st-layer ref="stLayer"></st-layer>

// js部分
this.$refs.stLayer.open({
    msg: &#39;测试&#39;,
    confirm: () => {
        console.log(&#39;点击了确认&#39;)
    },
    cancel: () => {
        console.log(&#39;点击了取消&#39;)
    }
})

现在基本功能已经实现,但是有人要说了,这样调用不方便,我想这样调用

open(msg).then(() => {
    console.log(&#39;点击了确认&#39;)
}).catch(() => {
     console.log(&#39;点击了取消&#39;)
})

那如何实现promise化呢?最简单的方法就是让open方法返回一个promise。如何点击确认或取消的时候进入then方法呢,看下面的写法

...
open() {
     return new promise((reoslve, reject) => {
        ...
        this.option.confirm = this.option.confirm || function confirmResolve () {
            resolve()
        }
         this.option.cancel = this.option.cancel || function cancelReject () {
            reject()
        }
     })
 }
...

如果要封装其他单独的方法,比如confirm之类,可以在open基础上扩展:

confirm(msg, option = {}) {
        if (typeof msg === &#39;object&#39;) {
                option = msg
        } else {
                option.msg = msg
        }
        return this.open({
                ...option,
                showCancelButton: true,
                type: &#39;confirm&#39;
        })
}
// 调用方式
this.$refs.stLayer.confirm(&#39;是否确认?&#39;).then().catch()

这样基本的弹层组件已经实现。下面也就是最后一步全局使用原有vue项目写的layer组件要全局使用通常是采用下面的方法注入到页面中

import main from &#39;./main.vue&#39;

const LayerConstructor = vue.extend(main)

const initInstance = () => {
  instance = new LayerConstructor({
    el: document.createElement(&#39;div&#39;)
  })

  instance.callback = defaultCallback
  document.getElementById(&#39;app&#39;).appendChild(instance.$el)
}

直接拉过来用,结果报错,提示error: document is undefined,才想起uni-app跟普通vue项目的有一个很大的区别,在它的运行原理中有介绍:

uni-app 逻辑层和视图层分离,在非H5端运行时,从架构上分为逻辑层和视图层两个部分。逻辑层负责执行业务逻辑,也就是运行js代码,视图层负责页面渲染。虽然开发者在一个vue页面里写js和css,但其实,编译时就已经将它们拆分了。逻辑层是运行在一个独立的jscore里的,它不依赖于本机的webview,所以一方面它没有浏览器兼容问题,可以在Android4.4上跑es6代码,另一方面,它无法运行window、document、navigator、localstorage等浏览器专用的js API。

所以这种注册全局的方法已经不可用。那该如何在uni-app中实现呢? 翻看官方论坛,找到了一个实现loadervue-inset-loader,实现原理就是获取sfc模板内容,在指定位置插入自定义内容(也就是需要全局的组件),使用方式如下:

// 第一步
npm install vue-inset-loader --save-dev 
// 第二步 在vue.config.js(hbuilderx创建的项目没有的话新建一个)中注入loader
module.export = {
    chainWebpack: config => {
            // 超级全局组件
            config.module
                    .rule(&#39;vue&#39;)
                    .test(/\.vue$/)
                    .use()
                    .loader(path.resolve(__dirname, "./node_modules/vue-inset-loader"))
                    .end()
	} 
}
// 支持自定义pages.json文件路径  
// options: {  
//     pagesPath: path.resolve(__dirname,&#39;./src/pages.json&#39;)  
// } 
// 第三步 pages.json配置文件中添加insetLoader
"insetLoader": {  
    "config":{  
        "confirm": "<BaseConfirm ref=&#39;confirm&#39;></BaseConfirm>",  
        "abc": "<BaseAbc ref=&#39;BaseAbc&#39;></BaseAbc>"  
    },  
    // 全局配置  
    "label":["confirm"],  
    "rootEle":"div"  
}

配置说明

  • config (default: {})
    定义标签名称和内容的键值对

  • label(default: [])
    需要全局引入的标签,打包后会在所有页面引入此标签

  • rootEle(default: "div")
    根元素的标签类型,缺省值为div,支持正则,比如匹配任意标签 ".*" 

     label 和 rootEle

    Afficher l'icône icône
Afficher le contenu

Peut être appelé par api

Prend en charge la promesse, vous pouvez utiliser $api.xx().then

Les premiers éléments sont faciles à faire, juste dans data Définissez les champs dans et utilisez directement la roue officielle uni-popup dans la couche externe. Cela vous évitera d'écrire une logique de contrôle pop-up. (paresseux), et la structure générale sera écrite

rrreee🎜 Ensuite, la partie js a d'abord simplement implémenté quelques méthodes d'ouverture et de fermeture🎜rrreee🎜Elle peut maintenant être utilisée sur d'autres pages🎜rrreee🎜Maintenant, les fonctions de base ont été implémentées, mais quelqu'un J'ai dit que ce n'était pas pratique de l'appeler comme ça. Je veux l'appeler comme ça🎜rrreee🎜Cela Comment implémenter la promesse ? Le moyen le plus simple est de laisser la méthode open renvoyer une promesse. Comment saisir la méthode then en cliquant sur confirmer ou annuler ? Voir la méthode d'écriture ci-dessous🎜rrreee🎜Si vous souhaitez encapsuler d'autres méthodes distinctes, telles que confirmer, vous pouvez ouvrir l'extension supérieure de base : 🎜rrreee🎜 Un tel composant de couche élastique de base a été implémenté. Voici la dernière étape utilisation globale Si le composant de couche écrit dans le projet vue d'origine doit être utilisé globalement, il est généralement injecté dans la page en utilisant la méthode suivante 🎜rrreee🎜 Extrayez-le directement et utilisez-le, et le résultat est une erreur, provoquant une erreur  : le document n'est pas défini, puis je me suis souvenu que uni-app est très différent du projet vue ordinaire, qui est introduit dans son principe de fonctionnement : 🎜🎜🎜uni -app La couche logique et la couche vue sont séparées Lorsqu'elle est exécutée du côté non-H5, elle est divisée en deux parties : la couche logique et la vue. couche. La couche logique est responsable de l'exécution de la logique métier, c'est-à-dire de l'exécution du code js, et la couche vue est responsable du rendu des pages. Bien que les développeurs écrivent js et css dans une page vue, ils sont en fait divisés lors de la compilation. La couche logique s'exécute dans un jscore indépendant. Elle ne dépend pas de la vue Web locale, donc d'une part elle n'a aucun problème de compatibilité avec le navigateur et peut exécuter du code es6 sur Android 4.4. D'autre part, elle ne peut pas exécuter Windows, Browser-. API js spécifiques telles que document, navigateur et stockage local. 🎜🎜🎜Cette méthode d'inscription globale n'est donc plus disponible. Alors, comment l'implémenter dans uni-app ? En parcourant le forum officiel, j'ai trouvé une implémentation de loadervue-inset-loader🎜, principe de mise en œuvre Il s'agit d'obtenir le contenu du modèle sfc et d'insérer du contenu personnalisé (c'est-à-dire des composants globaux) à l'emplacement spécifié. La méthode d'utilisation est la suivante : 🎜rrreee

Instructions de configuration<.>🎜🎜🎜config (par défaut : {})
Paires clé-valeur qui définissent le nom et le contenu de l'étiquette🎜🎜🎜🎜label (par défaut : [])
Une balise qui doit être introduite globalement. Cette balise sera introduite dans toutes les pages après l'emballage🎜🎜🎜🎜rootElecode>(par défaut : "div" code>)
Le type d'étiquette de l'élément racine, la valeur par défaut est div, prend en charge les règles régulières, telles que la correspondance avec n'importe quelle étiquette ".*" 🎜🎜 label
et rootEle Configuré dans le style d'une page séparée, la priorité est supérieure à la configuration globale 🎜🎜🎜🎜 À ce stade, le composant peut être utilisé globalement. pas besoin d'écrire des balises sur chaque page pour l'utiliser. Il suffit d'appeler l'API. 🎜🎜Vous pouvez l'optimiser plus tard en fonction de l'utilisation. Le niveau est limité, les conseils de chacun sont les bienvenus. 🎜🎜Recommandé : "🎜Tutoriel uniapp🎜"🎜

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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer