当前位置:首页 > VUE

vue实现dialog窗口

2026-03-08 04:50:16VUE

使用 Vue 实现 Dialog 窗口

基础 Dialog 组件实现

创建一个名为 Dialog.vue 的组件文件,包含基本的对话框结构:

vue实现dialog窗口

<template>
  <div class="dialog-overlay" v-if="visible" @click.self="close">
    <div class="dialog-content">
      <div class="dialog-header">
        <slot name="header">
          <h3>{{ title }}</h3>
        </slot>
        <button @click="close">×</button>
      </div>
      <div class="dialog-body">
        <slot></slot>
      </div>
      <div class="dialog-footer">
        <slot name="footer">
          <button @click="close">取消</button>
          <button @click="confirm">确认</button>
        </slot>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    visible: Boolean,
    title: {
      type: String,
      default: '提示'
    }
  },
  methods: {
    close() {
      this.$emit('update:visible', false)
    },
    confirm() {
      this.$emit('confirm')
      this.close()
    }
  }
}
</script>

<style scoped>
.dialog-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.dialog-content {
  background: white;
  border-radius: 4px;
  min-width: 300px;
  max-width: 80%;
}

.dialog-header {
  padding: 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #eee;
}

.dialog-body {
  padding: 16px;
}

.dialog-footer {
  padding: 16px;
  text-align: right;
  border-top: 1px solid #eee;
}
</style>

在父组件中使用 Dialog

<template>
  <div>
    <button @click="showDialog = true">打开对话框</button>
    <Dialog
      v-model:visible="showDialog"
      title="自定义标题"
      @confirm="handleConfirm"
    >
      <template #header>
        <h3>自定义头部</h3>
      </template>

      <p>这是对话框的内容区域</p>

      <template #footer>
        <button @click="showDialog = false">关闭</button>
        <button @click="submitForm">提交</button>
      </template>
    </Dialog>
  </div>
</template>

<script>
import Dialog from './Dialog.vue'

export default {
  components: { Dialog },
  data() {
    return {
      showDialog: false
    }
  },
  methods: {
    handleConfirm() {
      console.log('确认操作')
    },
    submitForm() {
      console.log('提交表单')
      this.showDialog = false
    }
  }
}
</script>

全局 Dialog 服务实现

创建全局可调用的 Dialog 服务:

vue实现dialog窗口

  1. 创建 dialog.js 服务文件:
import Vue from 'vue'

const DialogConstructor = Vue.extend(require('./Dialog.vue').default)

let dialogInstance = null

const Dialog = function(options) {
  if (dialogInstance) {
    dialogInstance.visible = false
  }

  dialogInstance = new DialogConstructor({
    el: document.createElement('div'),
    propsData: options
  })

  document.body.appendChild(dialogInstance.$el)

  return new Promise((resolve, reject) => {
    dialogInstance.$on('confirm', () => {
      resolve()
    })
    dialogInstance.$on('update:visible', (val) => {
      if (!val) {
        reject(new Error('Dialog closed'))
      }
    })

    Vue.nextTick(() => {
      dialogInstance.visible = true
    })
  })
}

Dialog.install = function(Vue) {
  Vue.prototype.$dialog = Dialog
}

export default Dialog
  1. 在 main.js 中注册:
import Dialog from './services/dialog'

Vue.use(Dialog)
  1. 在组件中使用全局 Dialog:
this.$dialog({
  title: '全局对话框',
  content: '这是通过服务调用的对话框'
}).then(() => {
  console.log('确认操作')
}).catch(() => {
  console.log('取消操作')
})

动画效果增强

为 Dialog 添加过渡动画:

<template>
  <transition name="dialog-fade">
    <div class="dialog-overlay" v-if="visible" @click.self="close">
      <transition name="dialog-slide">
        <div class="dialog-content">
          <!-- 原有内容 -->
        </div>
      </transition>
    </div>
  </transition>
</template>

<style scoped>
.dialog-fade-enter-active,
.dialog-fade-leave-active {
  transition: opacity 0.3s;
}

.dialog-fade-enter,
.dialog-fade-leave-to {
  opacity: 0;
}

.dialog-slide-enter-active,
.dialog-slide-leave-active {
  transition: transform 0.3s;
}

.dialog-slide-enter,
.dialog-slide-leave-to {
  transform: translateY(-20px);
}
</style>

可拖动 Dialog 实现

添加拖动功能:

// 在 Dialog.vue 的 script 部分添加
data() {
  return {
    dragData: {
      isDragging: false,
      startX: 0,
      startY: 0,
      startLeft: 0,
      startTop: 0
    }
  }
},
methods: {
  startDrag(e) {
    this.dragData.isDragging = true
    this.dragData.startX = e.clientX
    this.dragData.startY = e.clientY
    const rect = this.$el.getBoundingClientRect()
    this.dragData.startLeft = rect.left
    this.dragData.startTop = rect.top
    document.addEventListener('mousemove', this.onDrag)
    document.addEventListener('mouseup', this.stopDrag)
  },
  onDrag(e) {
    if (!this.dragData.isDragging) return
    const dx = e.clientX - this.dragData.startX
    const dy = e.clientY - this.dragData.startY
    this.$el.style.left = `${this.dragData.startLeft + dx}px`
    this.$el.style.top = `${this.dragData.startTop + dy}px`
  },
  stopDrag() {
    this.dragData.isDragging = false
    document.removeEventListener('mousemove', this.onDrag)
    document.removeEventListener('mouseup', this.stopDrag)
  }
}
<!-- 修改 dialog-header 部分 -->
<div class="dialog-header" @mousedown="startDrag">
  <!-- 原有内容 -->
</div>
/* 修改 dialog-overlay 样式 */
.dialog-overlay {
  /* 移除 justify-content 和 align-items */
  /* 添加 position: relative */
}

.dialog-content {
  position: absolute;
}

标签: 窗口vue
分享给朋友:

相关文章

vue公共列表的实现

vue公共列表的实现

实现 Vue 公共列表组件 公共列表组件通常用于展示重复结构的数据,例如商品列表、用户列表等。以下是一个典型的实现方式: 基础实现 创建可复用的列表组件 List.vue: <tem…

vue实现sso

vue实现sso

Vue 实现 SSO(单点登录)方案 单点登录(SSO)允许用户通过一次登录访问多个相关系统。以下是基于 Vue 的实现方案: 使用 OAuth2/OpenID Connect 协议 OAuth2…

vue实现rtc

vue实现rtc

Vue 实现 RTC 的步骤 安装依赖 在 Vue 项目中安装 WebRTC 相关依赖,如 simple-peer 或 peerjs,用于简化 WebRTC 的实现。 运行以下命令安装 simple-…

vue课程实现

vue课程实现

Vue 课程实现方案 课程内容设计 Vue课程应从基础到高级逐步展开,涵盖Vue核心概念、组件化开发、状态管理、路由、构建工具等。基础部分包括Vue实例、模板语法、计算属性和侦听器。中级部分深入组件通…

vue 实现排序

vue 实现排序

Vue 实现排序的方法 使用计算属性实现排序 通过计算属性对数组进行排序,可以保持原始数据不变。示例代码展示了如何对列表按名称升序排序: <template> <div>…

vue实现波形

vue实现波形

实现波形效果的方法 在Vue中实现波形效果可以通过多种方式完成,常见的方法包括使用Canvas绘制、CSS动画或第三方库。以下是几种实现方案: 使用Canvas绘制波形 通过Canvas API动态…