Vue2信息提示(Modal)

简介: 这是一个基于 Vue3 的信息提示模态框(Modal)组件,提供了丰富的自定义属性,包括标题、内容、宽度、按钮文本等。它支持两种模式:确认提示框(confirm)和信息提示框(info),并有六种不同的展示效果。模态框可以水平垂直居中或固定高度水平居中显示,支持加载中状态。该组件模仿了 ant-design-vue 的样式,适用于各种场景下的信息提示。

可自定义设置以下属性:

  • 标题描述(title),默认 'Title'

  • 内容描述(content),默认 'content'

  • 提示框宽度(width),默认 420px

  • 取消按钮文字(cancelText),默认 '取消'

  • 确认按钮文字(okText),默认 '确认'

  • 通知按钮文字(noticeText),默认 '知道了'

  • 提示框类型(mode),默认 'confirm',可选 'info'(确认提示框:confirm 信息提示框:info)

  • 提示框类型(type),默认 'confirm',可选(mode: confirm时 'confirm' 'delete' mode: info时 'info' 'success' 'error' 'warn')

  • 是否水平垂直居中(center),默认 true,(false时是固定高度水平居中)

  • 固定高度水平居中时,距顶部高度(top), 默认 100px

  • 加载中(loading),默认 false

  • 提示框是否可见(visible),默认 false

效果如下图:(整体样式模仿ant-design-vue Modal,同时阴影覆盖浏览器窗口)

一共有两种模式,六种展示效果,弹窗随内容自适应增加高度,同时支持对弹窗位置进行设置:①水平垂直居中②高度固定水平居中,具体效果如下图:

mode: 'confirm' type: 'confirm'

mode: 'confirm' type: 'delete'

mode: 'info' type: 'info'

mode: 'info' type: 'success'

mode: 'info' type: 'error'

mode: 'info' type: 'warn'

①创建模态对话框组件Modal.vue:

<template>
  <transition>
    <div class="m-modal-mask" v-show="visible" @click.self="onBlur">
      <div :class="['m-modal', center ? 'relative-hv-center' : 'top-center']" :style="`width: ${width}px; top: ${!center ? top + 'px':'50%'};`">
        <div :class="['m-modal-body', {'loading':loading}]">
          <div class="m-spin-dot" v-show="loading">
            <span class="u-dot-item"></span>
            <span class="u-dot-item"></span>
            <span class="u-dot-item"></span>
            <span class="u-dot-item"></span>
          </div>
          <div class="m-body">
            <div class="m-title">
              <template v-if="mode==='confirm'">
                <svg focusable="false" class="u-icon confirm" data-icon="exclamation-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M464 688a48 48 0 1096 0 48 48 0 10-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z"></path></svg>
              </template>
              <template v-if="mode==='info'">
                <svg focusable="false" class="u-icon info" v-if="type==='info'" data-icon="info-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"></path></svg>
                <svg focusable="false" class="u-icon success" v-if="type==='success'" data-icon="check-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg>
                <svg focusable="false" class="u-icon error" v-if="type==='error'" data-icon="close-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path></svg>
                <svg focusable="false" class="u-icon warn" v-if="type==='warn'" data-icon="exclamation-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"></path></svg>
              </template>
              <div class="u-title">{
  { title }}</div>
            </div>
            <div class="u-content">{
  { content }}</div>
          </div>
          <div class="m-btns">
            <template v-if="mode==='confirm'">
              <button class="u-cancel" @click="onCancel">{
  { cancelText }}</button>
              <button class="u-confirm primary" @click="onConfirm" v-if="type==='confirm'">{
  { okText }}</button>
              <button class="u-confirm delete" @click="onConfirm" v-if="type==='delete'">{
  { okText }}</button>
            </template>
            <template v-if="mode==='info'">
              <button class="u-confirm primary" @click="onConfirm">{
  { noticeText }}</button>
            </template>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>
<script>
export default { // 运行时声明
  name: 'Modal',
  props: {
    title: { // 标题描述
      type: String,
      default: 'Title'
    },
    content: { // 内容描述
      type: String,
      default: 'Content'
    },
    width: { // 提示框宽度
      type: Number,
      default: 420
    },
    cancelText: { // 取消按钮文字
      type: String,
      default: '取消'
    },
    okText: { // 确认按钮文字
      type: String,
      default: '确定'
    },
    noticeText: { // 通知按钮文字
      type: String,
      default: '知道了'
    },
    mode: { // 确认提示框:confirm  信息提示框:info
      type: String,
      default: 'confirm'
    },
    type: { // confirm mode: 'confirm', 'delete'   info mode: 'info', 'success', 'error', 'warn'
      type: String,
      default: 'confirm'
    },
    center: { // 水平垂直居中:true  固定高度水平居中:false
      type: Boolean,
      default: true
    },
    top: { // 固定高度水平居中时,距顶部高度
      type: Number,
      default: 100
    },
    loading: { // 加载中...
      type: Boolean,
      default: false
    },
    visible: { // 提示框是否可见
      type: Boolean,
      default: false
    }
  },
  methods: {
    onBlur () {
      this.$emit('cancel')
    },
    onCancel () {
      this.$emit('cancel')
    },
    onConfirm () {
      this.$emit('ok')
    }
  }
}
</script>
<style lang="less" scoped>
.v-enter-active, .v-leave-active {
  transition: opacity 0.3s ease;
}
.v-enter, .v-leave-to {
  opacity: 0;
}
.flex-hv-center { // 水平垂直居中方法①:弹性布局,随内容增大高度,并自适应水平垂直居中
  display: flex;
  justify-content: center;
  align-items: center;
}
.relative-hv-center { // 水平垂直居中方法②:相对定位,随内容增大高度,并自适应水平垂直居中
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}
.top-center { // 相对定位,固定高度,始终距离视图顶端100px
  position: relative;
  // top: 100px;
}
.m-modal-mask {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
  background: rgba(0,0,0,0.45);
  .m-modal {
    width: 420px;
    margin: 0 auto;
    color: rgba(0, 0, 0, 0.88);
    font-size: 14px;
    line-height: 1.5;
    .m-modal-body {
      position: relative;
      word-wrap: break-word;
      padding: 20px 24px;
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
      .m-spin-dot { // 绝对定位,并设置水平垂直居中
        position: absolute;
        display: inline-block;
        right: 0;
        left: 0;
        top: 0;
        bottom: 0;
        margin: auto;
        width: 20px;
        height: 20px;
        transform: rotate(45deg);
        -ms-transform: rotate(45deg); /* Internet Explorer */
        -moz-transform: rotate(45deg); /* Firefox */
        -webkit-transform: rotate(45deg); /* Safari 和 Chrome */
        -o-transform: rotate(45deg); /* Opera */
        animation: rotate 1.2s linear infinite;
        -webkit-animation: rotate 1.2s linear infinite;
        @keyframes rotate {
          100% {transform: rotate(405deg);}
        }
        .u-dot-item { // 单个圆点样式
          position: absolute;
          width: 8px;
          height: 8px;
          background: @themeColor;
          border-radius: 50%;
          opacity: .3;
          animation: spinMove 1s linear infinite alternate;
          -webkit-animation: spinMove 1s linear infinite alternate;
          @keyframes spinMove {
            100% {opacity: 1;}
          }
        }
        .u-dot-item:first-child {
          top: 0;
          left: 0;
        }
        .u-dot-item:nth-child(2) {
          top: 0;
          right: 0;
          animation-delay: .4s;
          -webkit-animation-delay: .4s;
        }
        .u-dot-item:nth-child(3) {
          bottom: 0;
          right: 0;
          animation-delay: .8s;
          -webkit-animation-delay: .8s;
        }
        .u-dot-item:last-child {
          bottom: 0;
          left: 0;
          animation-delay: 1.2s;
          -webkit-animation-delay: 1.2s;
        }
      }
      .m-body {
        .m-title {
          width: 100%;
          .u-icon {
            display: inline-block;
            margin-right: 12px;
            margin-top: 1px;
            width: 22px;
            height: 22px;
            font-size: 16px;
            font-weight: bold;
            vertical-align: top;
          }
          .confirm {
            fill: #faad14;
          }
          .info {
            fill: @themeColor;
          }
          .success {
            fill: #52c41a;
          }
          .error {
            fill: #ff4d4f;
          }
          .warn {
            fill: #faad14;
          }
          .u-title {
            display: inline-block;
            vertical-align: top;
            font-size: 16px;
            font-weight: 600;
            max-width: calc(100% - 34px);
          }
        }
        .u-content {
          margin-left: 34px;
          margin-top: 8px;
          font-size: 14px;
          max-width: calc(100% - 34px);
        }
      }
      .m-btns {
        margin-top: 24px;
        text-align: right;
        .u-cancel {
          height: 32px;
          line-height: 32px;
          padding: 0 15px;
          font-size: 14px;
          border-radius: 4px;
          color: rgba(0,0,0,.65);
          background: #fff;
          border: 1px solid #d9d9d9;
          cursor: pointer;
          transition: all .3s cubic-bezier(.645,.045,.355,1);
          &:hover {
            color: fade(@themeColor, 80%);
            border-color: fade(@themeColor, 80%);
          }
          &:focus {
            color: shade(@themeColor, 12%);
            border-color: shade(@themeColor, 12%);
          }
        }
        .u-confirm {
          margin-left: 8px;
          height: 32px;
          line-height: 32px;
          padding: 0 15px;
          font-size: 14px;
          border-radius: 4px;
          color: #fff;
          transition: all .3s cubic-bezier(.645,.045,.355,1);
          cursor: pointer;
        }
        .primary {
          background: @themeColor;
          border: 1px solid @themeColor;
          &:hover {
            background: fade(@themeColor, 80%);
            border-color: fade(@themeColor, 80%);
          }
          &:focus {
            background: shade(@themeColor, 12%);
            border-color: shade(@themeColor, 12%);
          }
        }
        .delete {
          background: #ff4d4f;
          border: 1px solid #ff4d4f;
          &:hover {
            background-color: #ff7875;
            border-color: #ff7875;
          }
          &:focus {
            background-color: #d9363e;
            border-color: #d9363e;
          }
        }
      }
    }
    .loading { // 加载过程背景虚化
      background: rgb(248, 248, 248);
      pointer-events: none; // 屏蔽鼠标事件
    }
  }
}
</style>

②在要使用的页面引入组件,并配置相应的mode和type:

<template>
  <div>
    <h2 class="mb10">Modal 信息提示基本使用</h2>
    <Button class="mr30" @click="showConfirmModal('Some descriptions ...')">提交确认</Button>
    <Button class="mr30" @click="showDeleteModal('Some descriptions ...')">删除确认</Button>
    <Button class="mr30" @click="showInfoModal('Some descriptions ...')">Info</Button>
    <Button class="mr30" @click="showSuccessModal('Some descriptions ...')">Success</Button>
    <Button class="mr30" @click="showErrorModal('Some descriptions ...')">Error</Button>
    <Button class="mr30" @click="showWarnModal('Some descriptions ...')">Warn</Button>
    <Button class="mr30" @click="showFixModal('Some descriptions ...')">高度固定</Button>
    <Modal
      :title="title"
      :content="content"
      :width="416"
      :top="200"
      cancelText="取消"
      okText="确认"
      noticeText="知道了"
      :mode="mode"
      :type="type"
      :center="center"
      :loading="loading"
      @cancel="onCancel"
      @ok="onConfirm"
      :visible="visible"
    />
  </div>
</template>
<script>
import { Modal } from './Modal.vue'
export default {
  name: 'ModalPage',
  data () {
    return {
      center: true,
      loading: false,
      visible: false,
      title: '',
      content: 'Content of the modal ...',
      mode: 'confirm',
      type: 'delete'
    }
  },
  methods: {
    showConfirmModal (info) {
      this.mode = 'confirm'
      this.type = 'confirm'
      this.title = 'Do you Want to submit these items ?'
      this.content = info
      this.center = true
      this.visible = true
    },
    showDeleteModal (info) {
      this.mode= 'confirm'
      this.type = 'delete'
      this.title = 'Do you Want to delete these items ?'
      this.content = info
      this.center = true
      this.visible = true
    },
    showInfoModal (info) {
      this.mode = 'info'
      this.type = 'info'
      this.title = 'Do you See these items ?'
      this.content= info
      this.center = true
      this.visible = true
    },
    showSuccessModal (info) {
      this.mode = 'info'
      this.type = 'success'
      this.title = 'Do you See these items ?'
      this.content = info
      this.center = true
      this.visible = true
    },
    showErrorModal (info) {
      this.mode = 'info'
      this.type = 'error'
      this.title = 'Do you See these items ?'
      this.content = info
      this.center = true
      this.visible= true
    },
    showWarnModal (info) {
      this.mode = 'info'
      this.type = 'warn'
      this.title = 'Do you See these items ?'
      this.content = info
      this.center = true
      this.visible = true
    },
    showFixModal (info) {
      this.mode = 'info'
      this.type = 'success'
      this.title = 'Do you See these items ?'
      this.center = false
      this.content = info
      this.visible = true
    },
    onCancel () { // “取消”按钮回调
      this.visible = false
    },
    onConfirm () { // “确定”,“知道了”按钮回调
      this.loading = true // 开启加载状态
      setTimeout(() => {
        this.visible = false
        this.loading = false
      }, 500)
    }
  }
}
</script>
<style lang="less" scoped>
</style>
相关文章
|
6月前
|
JSON JavaScript 前端开发
【form-generator在线表单生成---vue父组件调用vue弹框组件】
【form-generator在线表单生成---vue父组件调用vue弹框组件】
240 1
|
JavaScript Go 数据安全/隐私保护
【Vue】组件封装——input输入框
【Vue】组件封装——input输入框
255 0
【Vue】组件封装——input输入框
|
前端开发
Vue3输入框focus失效
Vue3引入elementplus的输入框el-input,如果想在鼠标点击即搜索框获得焦点后发生变化,那就得用到css的:focus选择器
543 1
|
3月前
Vue3信息提示(Modal)
这是一个基于 Vue2 的信息提示模态框组件,支持多种弹窗类型(如 info、success、error 等),并提供丰富的自定义属性,包括按钮文本、按钮类型、居中方式等。该组件可根据内容自动调整高度,并兼容不同按钮样式配置。预览效果展示了不同类型的模态框及其样式。代码中详细介绍了组件的实现方式和使用方法。
Vue3信息提示(Modal)
|
3月前
|
JavaScript
Vue2按钮组件(Button)
这篇文章介绍了如何在Vue框架中创建一个可自定义样式和行为的按钮组件,包括按钮的文本、类型、尺寸、宽度、高度、圆角、跳转目标、禁用状态和是否居中显示等属性。
128 1
Vue2按钮组件(Button)
|
3月前
|
JavaScript
Vue3按钮(Button)
这是一个高度可定制的按钮组件,支持多种属性设置,包括按钮类型、形状、图标、尺寸、背景透明度、波纹颜色、跳转地址、打开方式、禁用状态、加载状态及指示符样式等。预览图展示了不同配置下的按钮样式变化。组件通过Vue实现,并提供了丰富的自定义选项以适应各种场景需求。
123 1
Vue3按钮(Button)
|
3月前
在 Vue3 + ElementPlus 项目中使用 el-autocomplete 控件
本文介绍了在Vue3 + ElementPlus项目中如何使用`el-autocomplete`控件实现自动补全输入功能,并探讨了不同版本ElementPlus中`clearable`属性的兼容性问题。
402 0
在 Vue3 + ElementPlus 项目中使用 el-autocomplete 控件
|
6月前
|
JavaScript
【vue】 vue2 点击按钮获取按钮上的值
【vue】 vue2 点击按钮获取按钮上的值
56 0
|
6月前
解决vue2升级vue3后,输入框无法输入的问题
解决vue2升级vue3后,输入框无法输入的问题
482 0
|
JavaScript API
Vue + ElementUI el-input无法输入、修改、删除的问题
# 1、业务背景 查询资料此问题出现的原因是:vue页面进行数据渲染时,层次嵌套或者多重数据绑定导致该组件信息框数据不能被Vue实时监听到,以此出现了数据发生改变但页面上更新或删除对应信息框的数据毫无反应的现象,此时需要强制更新,重新渲染。 # 2、代码示例 ## 1)核心代码 ```html <el-input type="textarea" clearable placeholder="请输入测试文本:" v-model="form.Message" @input="changeMessage($event)"> </el-input> ``` 方法: ```j
245 0