uni-app中怎麼開發一個全域彈層元件?以下這篇文章給大家透過範例介紹uni-app中實作一個全域彈層組件的方法,希望對大家有幫助!
公司有一個採用uni-app框架寫的app應用,裡面的彈層基本上是使用官方的uni.showModal之類的api實現彈層,在裝置上表現就是原生的彈層,在客戶的要求下,需要更換成設計的樣式,所以就開始實現這樣一個元件。
根據彈層經常使用的方法和方式可以大致列出他需要的屬性和方法:
alert/confirm
等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 !== 'none' && 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="{'is-reverse-cofirmcancel' : 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: '取消', // 取消按钮文字 showConfirmButton: true, // 是否显示确认按钮 confirmButtonText: '取消', // 确认按钮文字 showIcon: true, // 是否显示图标 iconClass: null, // 图标class自定义 type: 'none', // 类型 confirm: null, // 点击确认后的逻辑 cancel: null, // 点击取消后的逻辑 msg: '' } 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 === 'function') { confirmHandler() } this.close() this.$emit('confirm') }, cancelClick() { const cancelHandler = this.option.cancel if (cancelHandler && typeof cancelHandler === 'function') { cancelHandler() } this.close() this.$emit('cancel') } }
目前在其他頁面已經可以使用
// 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: '测试', confirm: () => { console.log('点击了确认') }, cancel: () => { console.log('点击了取消') } })
現在基本功能已經實現,但是有人要說了,這樣調用不方便,我想這樣調用
open(msg).then(() => { console.log('点击了确认') }).catch(() => { console.log('点击了取消') })
那如何實現 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 === 'object') { option = msg } else { option.msg = msg } return this.open({ ...option, showCancelButton: true, type: 'confirm' }) } // 调用方式 this.$refs.stLayer.confirm('是否确认?').then().catch()
這樣基本的彈層元件已經實現。下面也就是最後一步全域使用
原有vue專案寫的layer元件要全域使用通常是採用下面的方法注入到頁面中
import main from './main.vue' const LayerConstructor = vue.extend(main) const initInstance = () => { instance = new LayerConstructor({ el: document.createElement('div') }) instance.callback = defaultCallback document.getElementById('app').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('vue') .test(/\.vue$/) .use() .loader(path.resolve(__dirname, "./node_modules/vue-inset-loader")) .end() } } // 支持自定义pages.json文件路径 // options: { // pagesPath: path.resolve(__dirname,'./src/pages.json') // } // 第三步 pages.json配置文件中添加insetLoader "insetLoader": { "config":{ "confirm": "<BaseConfirm ref='confirm'></BaseConfirm>", "abc": "<BaseAbc ref='BaseAbc'></BaseAbc>" }, // 全局配置 "label":["confirm"], "rootEle":"div" }
#config
(default: {}
)
)定義標籤名稱和內容的鍵值對
)需要全域引入的標籤,打包後會在所有頁面引入此標籤
(default: "div"
)根元素的標籤類型,預設值為div,支援正規,例如符合任意標籤".*"
rootEle
# 支援在單獨頁面的style裡配置,優先權高於全域配置到這,元件就可以全域使用了,不需要在每個頁面上寫標籤使用,只需要呼叫api就可以。
後面可以再根據使用情況進行最佳化處理。程度有限,歡迎各位大佬指點。 ######推薦:《###uniapp教學###》###以上是uni-app中怎麼開發一個全域彈層元件(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!