首頁 >web前端 >uni-app >uni-app中怎麼開發一個全域彈層元件(程式碼範例)

uni-app中怎麼開發一個全域彈層元件(程式碼範例)

青灯夜游
青灯夜游轉載
2022-03-07 19:59:585561瀏覽

uni-app中怎麼開發一個全域彈層元件?以下這篇文章給大家透過範例介紹uni-app中實作一個全域彈層組件的方法,希望對大家有幫助!

uni-app中怎麼開發一個全域彈層元件(程式碼範例)

公司有一個採用uni-app框架寫的app應用,裡面的彈層基本上是使用官方的uni.showModal之類的api實現彈層,在裝置上表現就是原生的彈層,在客戶的要求下,需要更換成設計的樣式,所以就開始實現這樣一個元件。

根據彈層經常使用的方法和方式可以大致列出他需要的屬性和方法:

  • 類型: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: {})

    config
  •  (default: 
  • {}

    )定義標籤名稱和內容的鍵值對

    label
  • (default: 
  • []

    )需要全域引入的標籤,打包後會在所有頁面引入此標籤

    rootEle

    (default: "div")根元素的標籤類型,預設值為div,支援正規,例如符合任意標籤".*" 

     
  • label
 和 

rootEle

# 支援在單獨頁面的style裡配置,優先權高於全域配置

到這,元件就可以全域使用了,不需要在每個頁面上寫標籤使用,只需要呼叫api就可以。

後面可以再根據使用情況進行最佳化處理。程度有限,歡迎各位大佬指點。 ######推薦:《###uniapp教學###》###

以上是uni-app中怎麼開發一個全域彈層元件(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除