自己弹窗一个封装(vue,uniapp)

本文介绍了一个基于Vue的弹窗组件实现,包括组件的配置、使用方法及全局挂载技巧。该组件支持自定义样式、回调函数等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、效果图:

二、项目中使用效果

1、弹窗一展示

this.popUpCallback是在你调用弹窗的页面写的方法,点击确定的回调

2、弹窗二展示

三、代码相关

1、popup.js

import Popup from './popup.vue'

export default {
  install(Vue) {
    const Profile = Vue.extend(Popup)

    // 弹出弹窗
    Vue.prototype.$openPopUp = function(params) {
      const instance = new Profile()
      for (const key in params) {
        if (Object.hasOwnProperty.call(params, key)) {
          const value = params[key]
          instance[key] = value
        }
      }
      instance.vm = instance.$mount()
      const popUpEle = document.body.lastElementChild
      if (popUpEle.className === 'popup-box') return
      setTimeout(() => document.body.appendChild(instance.vm.$el))
      return instance
    }

    // 关闭弹窗
    Vue.prototype.$closePopUp = function() {
      const instance = new Profile()
      instance.vm = instance.$mount()
      const popUpEle = document.body.lastElementChild
      if (popUpEle.className !== 'popup-box') return
      document.body.removeChild(popUpEle)
      return instance
    }
  }
}

2、main.js 直接挂载安装到全局

// 导入弹窗
import popup from './components/popup/popup.js'
// 安装插件
Vue.use(popup)

3、popup.vue

<template>
  <div class="popup-box">
    <view class="center-box" :style="[popUpWindowStyle]">
      <view class="header" :style="[headerStyle]">
        <view v-if="showTitle" class="title" :style="[titleStyle]">
          <text>{{ title }}</text>
        </view>
        <view v-if="imageUrl" class="img">
          <image
            :src="imageUrl"
            mode="scaleToFill"
            :style="[{width:`${imageWidth}rpx`},{height:`${imageHeight}rpx`}]"
          />
          <view v-if="redDotText != 'X'" class="redDot" :style="[{right: `calc( 50% - ${imageWidth}rpx )`}]">
            <text>
              {{ "+" + redDotText }}
            </text>
          </view>
        </view>
        <view class="textBox">
          <view v-if="bigText" class="bigText" :style="[bigTextStyle]">
            <text>
              {{ bigText }}
            </text>
          </view>
          <view v-if="smallText" class="smallText" :style="[smallTextStyle]">
            <text>
              {{ smallText }}
            </text>
          </view>
        </view>
      </view>
      <view class="footer">
        <view v-if="showCancel" class="btnBox">
          <view class="btn cancelBtn" @tap="closePopUp(0)">{{ cancelText }}</view>
        </view>
        <view class="btnBox">
          <view class="btn sureBtn" @tap="closePopUp(1)">{{ sureText }}</view>
        </view>
      </view>
    </view>
  </div>
</template>

<script>

export default {
  name: 'Popup',

  props: {
    success: {
      type: Function,
      default: undefined
    }, // 确定的回调
    cancel: {
      type: Function,
      default: undefined
    }, // 取消的回调
    headerStyle: {
      type: Object,
      default: () => {}
    }, // 头部样式
    showTitle: {
      type: Boolean,
      default: true
    }, // 是否展示标题(默认展示)
    title: {
      type: String,
      default: '提示'
    }, // 标题
    showCancel: {
      type: Boolean,
      default: false
    }, // 是否展示取消按钮(默认不展示)
    titleStyle: {
      type: Object,
      default: () => {}
    }, // 标题样式不会覆盖掉标题大小以及颜色
    popUpWindowStyle: {
      type: Object,
      default: () => {}
    }, // 弹窗窗口样式
    imageUrl: {
      type: String,
      default: ''
    }, // 图片地址(没有就不显示,图片地址相对位置以当前文件(就是这个文件)为基准)
    imageWidth: {
      type: Number,
      default: 116
    }, // 图片宽度
    imageHeight: {
      type: Number,
      default: 116
    }, // 图片宽度
    redDotText: {
      type: String,
      default: 'X'
    }, // 图片右上角小红点数字
    bigText: {
      type: String,
      default: '这是一个提示弹窗'
    }, // 大文本
    bigTextStyle: {
      type: Object,
      default: () => {}
    }, // 大文本样式
    smallText: {
      type: String,
      default: ''
    }, // 小文本
    smallTextStyle: {
      type: Object,
      default: () => {}
    }, // 小文本样式
    cancelText: {
      type: String,
      default: '取消'
    }, // 取消按钮文本
    sureText: {
      type: String,
      default: '确定'
    } // 确认按钮文本
  },

  data() {
    return {}
  },

  mounted() {
  },

  methods: {
    closePopUp(flag) {
      this.$closePopUp() // 关闭弹窗
      if (flag === 1 && this.success) {
        this.success()
      } else if (flag === 0 && this.cancel) {
        this.cancel()
      }
    }
  }
}
</script>
<style scoped>
.popup-box {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,0.5);
  z-index: 9999;
}
.popup-box .center-box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 532rpx;
  border-radius: 24rpx;
  opacity: 1;
  background: rgba(255,255,255,1);
}
.popup-box .center-box .header {
  padding: 30rpx;
  border-bottom:  rgba(235, 237, 240, 1) solid 2rpx;
  /* margin叠加问题 */
  /* overflow: hidden; */
}
.popup-box .center-box .header .title{
  font-size: 32rpx;
  font-weight: 500;
  text-align: center;
  margin-bottom: 40rpx;
  /* background-color: aqua; */
}
.popup-box .center-box .header .img{
  position: relative;
}
.popup-box .center-box .header .img .redDot{
  position: absolute;
  top: 0;
  right: calc( 50% - 116rpx);
  font-weight: 700;
  color: rgba(241, 58, 58, 1);
  text-align: left;
}
.popup-box .center-box .header .img image{
  width: 116rpx;
  height: 116rpx;
  display: block;
  margin: 30rpx auto;
}
.popup-box .center-box .header .textBox{
  margin: 20rpx 30rpx;
}
.popup-box .center-box .header .textBox .bigText {
  margin-top: 40rpx;
  font-size: 28rpx;
  line-height: 44rpx;
  font-weight: 400;
  color: rgba(35, 47, 63, 1);
  text-align: center;
}
.popup-box .center-box .header .textBox .smallText {
  margin-top: 16rpx;
  font-size: 24rpx;
  font-weight: 400;
  line-height: 40rpx;
  color: #929292;
}
.popup-box .center-box .footer {
  display: flex;
  width: 100%;
}
.popup-box .center-box .footer .btnBox {
  width: 50%;
  height: 90rpx;
  line-height: 90rpx;
  font-size: 32rpx;
  font-weight: 400;
  text-align: center;
  flex: 1;
}
.popup-box .center-box .btnBox .btn {
  color: rgba(161, 166, 179, 1);
}
.popup-box .center-box .btnBox .btn.sureBtn {
  color: rgba(241, 58, 58, 1);
}
</style>

4、prop

success: {
  type: Function,
  default: undefined
}, // 确定的回调
cancel: {
  type: Function,
  default: undefined
}, // 取消的回调
headerStyle: {
  type: Object,
  default: () => {}
}, // 头部样式
showTitle: {
  type: Boolean,
  default: true
}, // 是否展示标题(默认展示)
title: {
  type: String,
  default: '提示'
}, // 标题
showCancel: {
  type: Boolean,
  default: false
}, // 是否展示取消按钮(默认不展示)
titleStyle: {
  type: Object,
  default: () => {}
}, // 标题样式不会覆盖掉标题大小以及颜色
popUpWindowStyle: {
  type: Object,
  default: () => {}
}, // 弹窗窗口样式
imageUrl: {
  type: String,
  default: ''
}, // 图片地址(没有就不显示,图片地址相对位置以当前文件(就是这个文件)为基准)
imageWidth: {
  type: Number,
  default: 116
}, // 图片宽度
imageHeight: {
  type: Number,
  default: 116
}, // 图片宽度
redDotText: {
  type: String,
  default: 'X'
}, // 图片右上角小红点数字
bigText: {
  type: String,
  default: '这是一个提示弹窗'
}, // 大文本
bigTextStyle: {
  type: Object,
  default: () => {}
}, // 大文本样式
smallText: {
  type: String,
  default: ''
}, // 小文本
smallTextStyle: {
  type: Object,
  default: () => {}
}, // 小文本样式
cancelText: {
  type: String,
  default: '取消'
}, // 取消按钮文本
sureText: {
  type: String,
  default: '确定'
} // 确认按钮文本

四、解释

1、弹窗样式啥的可以自己在popup.vue文件中修改

2、使用this.$openPopUp调用,使用this.$closePopUp关闭

3、全局挂载在mian.j,全局皆可使,可自行修改挂载位置

4、本文知识点涉及到了vue的组件传值以及组件挂载使用等,可以去查阅相关知识点,不多啰嗦

### 封装自定义弹窗组件的教程 在 UniApp封装一个自定义弹窗组件可以通过 Vue 的组件机制来实现。以下是详细的说明以及示例代码。 #### 1. 创建弹窗组件 (BottomPopup.vue) 创建一个新的文件 `BottomPopup.vue`,用于定义底部弹窗的功能和结构: ```vue <template> <view v-if="visible" class="bottom-popup-container"> <!-- 遮罩层 --> <view class="mask" @click="handleClose"></view> <!-- 弹窗主体 --> <view class="popup-content"> <slot></slot> <!-- 插槽用于接收父组件传入的内容 --> </view> </view> </template> <script> export default { data() { return { visible: false, // 控制弹窗显示状态 }; }, methods: { show() { this.visible = true; }, handleClose() { this.visible = false; this.$emit('close'); // 触发关闭事件 } } }; </script> <style scoped> .bottom-popup-container { position: fixed; bottom: 0; left: 0; width: 100%; height: 100%; z-index: 999; } .mask { background-color: rgba(0, 0, 0, 0.5); width: 100%; height: 100%; } .popup-content { background-color: white; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: 20px; } </style> ``` 此部分实现了基本的弹窗逻辑,并提供了插槽支持以便于父组件传入自定义内容[^1]。 --- #### 2. 使用弹窗组件 在父组件中引入并注册该弹窗组件,然后通过按钮或其他方式控制其显示/隐藏。 ##### 父组件示例 (ParentComponent.vue) ```vue <template> <view> <!-- 打开弹窗的按钮 --> <button @click="openPopup">打开弹窗</button> <!-- 自定义弹窗组件 --> <BottomPopup ref="popup" @close="onClose"> <div style="padding: 20px;"> <p>这里是弹窗的自定义内容</p> <input type="text" placeholder="请输入一些内容..." /> </div> </BottomPopup> </view> </template> <script> import BottomPopup from './components/BottomPopup.vue'; export default { components: { BottomPopup }, methods: { openPopup() { this.$refs.popup.show(); // 调用子组件的 show 方法 }, onClose() { console.log('弹窗已关闭'); } } }; </script> ``` 上述代码展示了如何在父组件中调用子组件的方法 (`show`) 并监听其事件 (`@close`)--- #### 3. 注册全局组件(可选) 如果希望在整个项目中频繁使用这个弹窗组件,则可以将其注册为全局组件。 在项目的入口文件 `main.js` 或类似的初始化脚本中添加如下代码: ```javascript import Vue from 'vue'; import BottomPopup from '@/components/BottomPopup.vue'; // 替换为实际路径 Vue.component('BottomPopup', BottomPopup); // 注册为全局组件 ``` 完成这一步后,在任何地方都可以直接使用 `<BottomPopup>` 标签而无需单独导入[^4]。 --- #### 4. 设计原则回顾 为了使组件更加灵活且易于维护,建议遵循以下设计原则: - **单一职责**:确保每个组件专注于解决一个问题或提供一种功能[^3]。 - **可复用性**:通过 props 和 events 提供足够的灵活性,使得同一个组件能够在不同场景下工作。 - **封装性**:将内部实现细节隐藏起来,仅暴露必要的 API 接口给外界访问。 - **可配置性**:允许开发者通过参数调整外观与交互行为,比如颜色主题、动画效果等设置项。 --- ### 示例总结 以上是一个完整的 UniApp 自定义弹窗组件开发流程,涵盖了从基础构建到高级优化的过程。利用这些技术手段可以帮助团队快速搭建高质量的应用程序界面[^2]。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值