Vue2 移动端(H5)项目封装弹窗组件

前言

vant-uidialog组件没有自定义footer插槽

效果

参数配置

1、代码示例:

html 复制代码
<t-dialog :visible.sync="show" :title="title" @submit="submit"></t-dialog>

2、配置参数(t-dialog Attributes)

参数 说明 类型 默认值
visible 是否显示弹窗 (必须加.sync 修饰符) Boolean false
title 弹窗标题 String '-
width 弹窗宽度 String 351px
height 弹窗高度 String auto
cancelButtonText 取消按钮文字 String 取消
confirmButtonText 确定按钮文字 String 确定
showCancelButton 是否显示取消按钮 Boolean true
showConfirmButton 是否显示确定按钮 Boolean true
isShowHeader 是否显示头部 Boolean true
isShowMask 是否显示遮罩层 Boolean true
isClickMaskClose 是否点击遮罩关闭弹窗 Boolean true
isCloseMask 是否显示标题右侧关闭icon Boolean true
footer 是否显示底部操作按钮(:footer="null") Object -

3、events 事件

事件名 说明 返回值
submit 点击确定按钮 -

4、slot 插槽

事件名 说明 返回值
title title插槽 -
- 默认内容区域插槽 -
footer 操作按钮插槽 -

三、源码

html 复制代码
<template>
  <div class="t_dialog" v-if="isShow">
    <div class="dialog_content" :style="{width: width, height: height}">
      <div class="header_title" v-if="isShowHeader">
        {{ title }}
        <slot name="title" />
        <van-icon @click="closePopup" v-if="isCloseMask" name="cross" />
      </div>
      <div class="content">
        <slot />
      </div>
      <div
        class="footer"
        :class="{'footer-no-button': !showCancelButton||!showConfirmButton, 'footer-null': (!showCancelButton&&!showConfirmButton)}"
        v-if="(footer!==null)"
      >
        <slot name="footer" />
        <template v-if="!$slots.footer">
          <van-button @click="closePopup" v-if="showCancelButton">{{cancelButtonText}}</van-button>
          <van-button type="danger" @click="submit" v-if="showConfirmButton">{{confirmButtonText}}</van-button>
        </template>
      </div>
    </div>
    <div class="dialog-mask" v-if="isShowMask" @click="closeMask"></div>
  </div>
</template>
<script>
export default {
  name: 'TDialog',
  props: {
    // 是否显示弹窗
    visible: {
      type: Boolean,
      default: false
    },
    // 弹窗标题
    title: {
      type: String,
    },
    width: {
      type: String,
      default: '351px'
    },
    height: {
      type: String,
      default: 'auto'
    },
    // 取消按钮文字
    cancelButtonText: {
      type: String,
      default: '取消'
    },
    // 确定按钮文字
    confirmButtonText: {
      type: String,
      default: '确定'
    },
    // 是否显示取消按钮
    showCancelButton: {
      type: Boolean,
      default: true
    },
    // 是否显示确定按钮
    showConfirmButton: {
      type: Boolean,
      default: true
    },
    // 是否显示头部
    isShowHeader: {
      type: Boolean,
      default: true
    },
    // 是否显示遮罩层
    isShowMask: {
      type: Boolean,
      default: true
    },
    // 是否点击遮罩关闭弹窗
    isClickMaskClose: {
      type: Boolean,
      default: true
    },
    // 是否显示关闭按钮
    isCloseMask: {
      type: Boolean,
      default: true
    },
    // 是否显示底部操作按钮 :footer="null"
    footer: Object,
  },
  computed: {
    isShow: {
      get() {
        return this.visible
      },
      set(val) {
        this.$emit('update:visible', val)
      }
    }
  },
  methods: {
    closePopup() {
      this.isShow = false
    },
    closeMask() {
      if (!this.isClickMaskClose) return
      this.isShow = false
    },
    submit() {
      this.$emit('submit')
      // this.isShow = false
    }
  },

}
</script>
<style lang="scss" scoped>
.t_dialog {
  .dialog_content {
    position: fixed;
    top: 50%;
    left: 50%;
    -webkit-transform: translate3d(-50%, -50%, 0);
    transform: translate3d(-50%, -50%, 0);
    max-width: 100%;
    max-height: 100%;
    background-color: #fff;
    z-index: 1000;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  }
  .header_title {
    height: 40px;
    padding: 0 20px;
    font-size: 16px;
    color: #101010;
    background: #fff;
    border-bottom: 1px solid #e5e5e5;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    border-radius: 8px 8px 0 0;
    .van-icon {
      cursor: pointer;
      position: absolute;
      right: 20px;
      top: 50%;
      -webkit-transform: translateY(-50%);
      transform: translateY(-50%);
      font-size: 16px;
      color: #999;
      &:hover {
        color: #333;
      }
    }
  }
  .content {
    padding: 15px;
    width: calc(100% - 30px);
    overflow-y: auto;
  }
  .footer {
    height: 40px;
    line-height: 40px;
    color: #101010;
    background: #fff;
    border-top: 1px solid #e5e5e5;
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
    border-radius: 0 0 8px 8px;
    button {
      flex: 0 50%;
      height: 40px;
      line-height: 40px;
      padding: 0;
      font-size: 16px;
      border: none;
      border-radius: 0 0 8px 0px;
      &:first-child {
        border-right: 1px solid #e5e5e5;
        border-radius: 0 0 0px 8px;
      }
    }
    .van-button--primary {
      color: #007aff;
      border: none;
      background-color: #fff;
    }
    .van-button--danger {
      color: #ff4444;
      border: none;
      background-color: #fff;
    }
    &.footer-no-button {
      button {
        flex: 0 auto;
        border: none;
        border-radius: 0 0 8px 8px;
        width: 100%;
      }
    }
    &.footer-null {
      display: none;
    }
  }
  .dialog-mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #000;
    opacity: 0.7;
    z-index: 999;
  }
}
</style>

相关文章

基于ElementUi再次封装基础组件文档


基于ant-design-vue再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档

相关推荐
哲此一生9841 小时前
搭建Vue3工程(去除不必要的文件)
前端·javascript·vue.js
黑云压城After4 小时前
H5使用环信实现视频或语音通话
前端·javascript·vue.js
牧杉-惊蛰7 小时前
disable-devtool 网络安全 禁止打开控制台
前端·css·vue.js
C+ 安口木8 小时前
vue中监听window某个属性被添加或值的变化
前端·javascript·vue.js
FuckPatience8 小时前
前后端分离项目部署完成后 前后端交互过程
vue.js·asp.net
LuckySusu8 小时前
【vue篇】Vue 自定义指令完全指南:从入门到高级实战
前端·vue.js
LuckySusu8 小时前
【vue篇】Vue 响应式核心:依赖收集机制深度解密
前端·vue.js
LuckySusu8 小时前
【vue篇】Vue.js 2025:为何全球开发者都在拥抱这个前端框架?
前端·vue.js
LuckySusu8 小时前
【vue篇】Vue 单向数据流铁律:子组件为何不能直接修改父组件数据?
前端·vue.js
LuckySusu8 小时前
【vue篇】React vs Vue:2025 前端双雄终极对比
前端·vue.js