最新公告
  • 欢迎您光临站长资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • uni-app中怎么开发一个全局弹层组件(代码示例)

    uni-app中怎么开发一个全局弹层组件?下面本篇文章给大家通过例子介绍一下uni-app中实现一个全局弹层组件的方法,希望对大家有所帮助!

    uni-app中怎么开发一个全局弹层组件(代码示例)

    公司有一个采用uni-app框架写的app应用,里面的弹层基本是使用官方的uni.showModal之类的api实现弹层,在设备上表现就是原生的弹层,在客户的要求下,需要更换成设计的样式,所以就开始实现这样一个组件。

    根据弹层经常使用的方法和方式可以大致列出他需要的属性和方法:

    类型:alert/confirm

    展示图标 icon

    展示内容 content

    可以api调用

    支持promise,可以使用$api.xx().then

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

    1. // template部分
    2. <uni-popup ref="popup" :maskClick="maskClick">
    3.     <view class="st-layer" :style="{ width: width }">
    4.         <view class="st-layer__content">
    5.             <!-- #ifndef APP-NVUE -->
    6.             <text class="st-layer__icon" :class="option.iconClass || getIconClass()"
    7.                 v-if="option.type !== 'none' && option.showIcon"></text>
    8.             <!-- #endif -->
    9.             <view class="st-layer__msg" v-if="option.msg">
    10.                 <text>{{ option.msg }}</text>
    11.             </view>
    12.         </view>
    13.         <view class="st-layer__footer" :class="{'is-reverse-cofirmcancel' : isReverseConfirmCancel}" v-if="option.showConfirmButton || option.showCancelButton">
    14.             <view class="st-layer__footer__btn st-layer__footer__btn--confirm" @tap.stop="confirmClick"
    15.                 v-if="option.showConfirmButton"><text>确认</text></view>
    16.             <view class="st-layer__footer__btn st-layer__footer__btn--cancel" @tap.stop="cancelClick"
    17.                 v-if="option.showCancelButton"><text>取消</text></view>
    18.         </view>
    19.     </view>
    20. </uni-popup>

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

    1. data() {
    2.     return {
    3.             option: {}
    4.     }
    5. },
    6. methods: {
    7.     open(option) {
    8.         let defaultOption = {
    9.                 showCancelButton: false, // 是否显示取消按钮
    10.                 cancelButtonText: '取消', // 取消按钮文字
    11.                 showConfirmButton: true, // 是否显示确认按钮
    12.                 confirmButtonText: '取消', // 确认按钮文字
    13.                 showIcon: true, // 是否显示图标
    14.                 iconClass: null, // 图标class自定义
    15.                 type: 'none', // 类型
    16.                 confirm: null, // 点击确认后的逻辑
    17.                 cancel: null, // 点击取消后的逻辑
    18.                 msg: ''
    19.         }
    20.         this.option = Object.assign({}, defaultOption, option)
    21.         this.$refs.popup.open()
    22.     },
    23.     close() {
    24.             this.$refs.popup.close()
    25.     },
    26.     confirmClick() {
    27.             const confirmHandler = this.option.confirm
    28.             if (confirmHandler && typeof confirmHandler === 'function') {
    29.                     confirmHandler()
    30.             }
    31.             this.close()
    32.             this.$emit('confirm')
    33.     },
    34.     cancelClick() {
    35.             const cancelHandler = this.option.cancel
    36.             if (cancelHandler && typeof cancelHandler === 'function') {
    37.                     cancelHandler()
    38.             }
    39.             this.close()
    40.             this.$emit('cancel')
    41.     }
    42. }

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

    1. // 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语句
    2. <st-layer ref="stLayer"></st-layer>
    1. // js部分
    2. this.$refs.stLayer.open({
    3.     msg: '测试',
    4.     confirm: () => {
    5.         console.log('点击了确认')
    6.     },
    7.     cancel: () => {
    8.         console.log('点击了取消')
    9.     }
    10. })
    现在基本功能已经实现,但是有人要说了,这样调用不方便,我想这样调用
    1. open(msg).then(() => {
    2.     console.log('点击了确认')
    3. }).catch(() => {
    4.      console.log('点击了取消')
    5. })

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

    1. ...
    2. open() {
    3.      return new promise((reoslve, reject) => {
    4.         ...
    5.         this.option.confirm = this.option.confirm || function confirmResolve () {
    6.             resolve()
    7.         }
    8.          this.option.cancel = this.option.cancel || function cancelReject () {
    9.             reject()
    10.         }
    11.      })
    12.  }
    13. ...

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

    1. confirm(msg, option = {}) {
    2.         if (typeof msg === 'object') {
    3.                 option = msg
    4.         } else {
    5.                 option.msg = msg
    6.         }
    7.         return this.open({
    8.                 ...option,
    9.                 showCancelButton: true,
    10.                 type: 'confirm'
    11.         })
    12. }
    13. // 调用方式
    14. this.$refs.stLayer.confirm('是否确认?').then().catch()

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

    1. import main from './main.vue'
    2.  
    3. const LayerConstructor = vue.extend(main)
    4.  
    5. const initInstance = () => {
    6.   instance = new LayerConstructor({
    7.     el: document.createElement('div')
    8.   })
    9.  
    10.   instance.callback = defaultCallback
    11.   document.getElementById('app').appendChild(instance.$el)
    12. }

    直接拉过来用,结果报错,提示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模板内容,在指定位置插入自定义内容(也就是需要全局的组件),使用方式如下:

    1. // 第一步
    2. npm install vue-inset-loader --save-dev 
    3. // 第二步 在vue.config.js(hbuilderx创建的项目没有的话新建一个)中注入loader
    4. module.export = {
    5.     chainWebpack: config => {
    6.             // 超级全局组件
    7.             config.module
    8.                     .rule('vue')
    9.                     .test(/\.vue$/)
    10.                     .use()
    11.                     .loader(path.resolve(__dirname, "./node_modules/vue-inset-loader"))
    12.                     .end()
    13.     } 
    14. }
    15. // 支持自定义pages.json文件路径  
    16. // options: {  
    17. //     pagesPath: path.resolve(__dirname,'./src/pages.json')  
    18. // } 
    19. // 第三步 pages.json配置文件中添加insetLoader
    20. "insetLoader": {  
    21.     "config":{  
    22.         "confirm": "<BaseConfirm ref='confirm'></BaseConfirm>",  
    23.         "abc": "<BaseAbc ref='BaseAbc'></BaseAbc>" 
    24.     },  
    25.     // 全局配置  
    26.     "label":["confirm"],  
    27.     "rootEle":"div" 
    28. }

    配置说明

    config (default: {})

    定义标签名称和内容的键值对

    label(default: [])

    需要全局引入的标签,打包后会在所有页面引入此标签

    rootEle(default: "div")

    根元素的标签类型,缺省值为div,支持正则,比如匹配任意标签 “.*”

    label 和 rootEle 支持在单独页面的style里配置,优先级高于全局配置

    到这,该组件就可以全局使用了,不需要在每个页面写标签使用,只需要调用api就可以。

    后面可以再根据使用情况进行优化处理。水平有限,欢迎各位大佬指点。

    RIPRO主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
    云站网络 » uni-app中怎么开发一个全局弹层组件(代码示例)
    • 8会员总数(位)
    • 5资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 1711稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情