You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue2如何不使用TypeScript自定义类似this.$swal的全局$ask调用方法

实现方案(Vue2版本,Vue3适配方案附后)

核心思路是通过Vue插件+动态创建组件实例的方式实现,既可以加载.vue格式的模态框单文件组件,又能全局挂载可await的调用方法,完全符合你要的调用效果。

步骤1:编写模态框单文件组件

新建 src/components/AskModal.vue,内置模态框UI、表单渲染逻辑,对外暴露确认/取消事件:

<template>
  <!-- 可直接替换为项目在用UI框架的模态框,比如ElementUI的el-dialog -->
  <div class="ask-modal-mask" v-if="visible" @click.self="handleCancel">
    <div class="ask-modal">
      <div class="ask-modal-header">{{ modalConfig.title }}</div>
      <div class="ask-modal-body">
        <div class="form-item" v-for="field in fieldConfig" :key="field.key">
          <label>{{ field.title }}</label>
          <input 
            v-model="formData[field.key]" 
            :type="field.type" 
            :placeholder="field.placeholder"
          >
        </div>
      </div>
      <div class="ask-modal-footer">
        <button @click="handleCancel">{{ modalConfig.cancelButtonText }}</button>
        <button @click="handleConfirm" :class="`btn-${modalConfig.variant}`">
          {{ modalConfig.confirmButtonText }}
        </button>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      visible: false,
      fieldConfig: [],
      modalConfig: {
        variant: 'primary',
        icon: null,
        title: '提示',
        confirmButtonText: '确定',
        cancelButtonText: '取消'
      },
      formData: {}
    }
  },
  methods: {
    // 初始化传入配置
    init(config) {
      this.fieldConfig = config.fields || []
      this.modalConfig = Object.assign({}, this.modalConfig, config.modal || {})
      // 初始化表单响应式字段
      this.fieldConfig.forEach(field => {
        this.$set(this.formData, field.key, '')
      })
      this.visible = true
    },
    handleConfirm() {
      this.$emit('confirm', { data: this.formData })
      this.visible = false
    },
    handleCancel() {
      this.$emit('cancel')
      this.visible = false
    }
  }
}
</script>
<style scoped>
/* 可根据项目UI规范自定义样式 */
.ask-modal-mask {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.ask-modal {
  background: #fff;
  border-radius: 8px;
  min-width: 400px;
  padding: 20px;
}
.form-item {
  margin-bottom: 15px;
}
.form-item label {
  display: block;
  margin-bottom: 5px;
}
.form-item input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-sizing: border-box;
}
.ask-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}
.btn-primary {
  background: #409eff;
  color: #fff;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
}
</style>

步骤2:编写全局挂载插件

新建 src/plugins/ask.js,实现动态创建组件、返回Promise的核心逻辑:

import Vue from 'vue'
import AskModal from '../components/AskModal.vue'

// 创建模态框组件构造器
const AskModalConstructor = Vue.extend(AskModal)

const askPlugin = {
  install(Vue) {
    // 挂载到Vue原型,所有组件可通过this.$ask直接调用
    Vue.prototype.$ask = (config) => {
      return new Promise((resolve, reject) => {
        // 创建组件实例
        const modalInstance = new AskModalConstructor()
        // 创建挂载节点并插入body
        const mountNode = document.createElement('div')
        document.body.appendChild(mountNode)
        modalInstance.$mount(mountNode)

        // 初始化模态框配置
        modalInstance.init(config)

        // 监听确认事件,返回表单结果
        modalInstance.$on('confirm', (result) => {
          resolve(result)
          // 动画结束后销毁组件、移除节点,避免内存泄漏
          setTimeout(() => {
            modalInstance.$destroy()
            document.body.removeChild(mountNode)
          }, 300)
        })

        // 监听取消事件
        modalInstance.$on('cancel', () => {
          reject(new Error('用户取消输入'))
          setTimeout(() => {
            modalInstance.$destroy()
            document.body.removeChild(mountNode)
          }, 300)
        })
      })
    }
  }
}

export default askPlugin

步骤3:全局注册插件

在入口文件 main.js 中注册插件即可全局使用:

import Vue from 'vue'
import App from './App.vue'
import askPlugin from './plugins/ask'

Vue.use(askPlugin)

new Vue({
  render: h => h(App)
}).$mount('#app')

使用方式

和你期望的调用逻辑完全一致:

// 任意组件内调用
async function createTeam() {
  try {
    const modalResult = await this.$ask({
      fields: [
        {
          title: "Team name",
          placeholder: "Give your team a name!",
          key: "teamName",
          type: "text"
        }, {
          title: "Team description",
          placeholder: "What's your team about?",
          key: "teamDescription",
          type: "text"
        }
      ],
      modal: {
        variant: "primary",
        icon: null,
        title: "Make a new team",
        confirmButtonText: "Create team",
        cancelButtonText: "Cancel"
      }
    })
    console.log("Team name: ", modalResult.data.teamName)
    console.log("Team description: ", modalResult.data.teamDescription)
  } catch (err) {
    // 可自定义用户点击取消后的处理逻辑
    console.log('用户取消了输入')
  }
}

Vue3适配调整

如果是Vue3项目,仅需修改插件部分的动态创建逻辑即可:

// src/plugins/ask.js(Vue3版本)
import { createApp } from 'vue'
import AskModal from '../components/AskModal.vue'

const askPlugin = {
  install(app) {
    app.config.globalProperties.$ask = (config) => {
      return new Promise((resolve, reject) => {
        const mountNode = document.createElement('div')
        document.body.appendChild(mountNode)
        const appInstance = createApp(AskModal)
        const modalInstance = appInstance.mount(mountNode)
        
        modalInstance.init(config)
        
        modalInstance.$on('confirm', (result) => {
          resolve(result)
          setTimeout(() => {
            appInstance.unmount()
            document.body.removeChild(mountNode)
          }, 300)
        })
        
        modalInstance.$on('cancel', () => {
          reject(new Error('用户取消输入'))
          setTimeout(() => {
            appInstance.unmount()
            document.body.removeChild(mountNode)
          }, 300)
        })
      })
    }
  }
}

export default askPlugin

内容的提问来源于stack exchange,提问作者Jonas Van der Reysen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:54:03