如何使用vue.js构造modal组件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用vue.js构造modal组件相关的知识,希望对你有一定的参考价值。

基本上每个项目都需要用到模态框组件,由于在最近的项目中,alert组件和confirm是两套完全不一样的设计,所以我将他们分成了两个组件,本文主要讨论的是confirm组件的实现。

组件结构
<template>
<div class="modal" v-show="show" transition="fade">
<div class="modal-dialog">
<div class="modal-content">
<!--头部-->
<div class="modal-header">
<slot name="header">
<p class="title">modal.title</p>
</slot>
<a v-touch:tap="close(0)" class="close" href="javascript:void(0)"></a>
</div>
<!--内容区域-->
<div class="modal-body">
<slot name="body">
<p class="notice">modal.text</p>
</slot>
</div>
<!--尾部,操作按钮-->
<div class="modal-footer">
<slot name="button">
<a v-if="modal.showCancelButton" href="javascript:void(0)" class="button modal.cancelButtonClass" v-touch:tap="close(1)">modal.cancelButtonText</a>
<a v-if="modal.showConfirmButton" href="javascript:void(0)" class="button modal.confirmButtonClass" v-touch:tap="submit">modal.confirmButtonText</a>
</slot>
</div>
</div>
</div>
</div>
<div v-show="show" class="modal-backup" transition="fade"></div>
</template>

模态框结构分为三部分,分别为头部、内部区域和操作区域,都提供了slot,可以根据需要定制。

样式
.modal
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1001;
-webkit-overflow-scrolling: touch;
outline: 0;
overflow: scroll;
margin: 30/@rate auto;

.modal-dialog
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%,0);
width: 690/@rate;
padding: 50/@rate 40/@rate;
background: #fff;

.modal-backup
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.5);


这里只是一些基本样式,没什么好说的,这次项目是在移动端,用了淘宝的 自适应布局方案 ,@rate是切稿时候的转换率。

接口定义
/**
* modal 模态接口参数
* @param string modal.title 模态框标题
* @param string modal.text 模态框内容
* @param boolean modal.showCancelButton 是否显示取消按钮
* @param string modal.cancelButtonClass 取消按钮样式
* @param string modal.cancelButtonText 取消按钮文字
* @param string modal.showConfirmButton 是否显示确定按钮
* @param string modal.confirmButtonClass 确定按钮样式
* @param string modal.confirmButtonText 确定按钮标文字
*/
props: ['modalOptions'],
computed:
/**
* 格式化props进来的参数,对参数赋予默认值
*/
modal:
get()
let modal = this.modalOptions;
modal =
title: modal.title || '提示',
text: modal.text,
showCancelButton: typeof modal.showCancelButton === 'undefined' ? true : modal.showCancelButton,
cancelButtonClass: modal.cancelButtonClass ? modal.showCancelButton : 'btn-default',
cancelButtonText: modal.cancelButtonText ? modal.cancelButtonText : '取消',
showConfirmButton: typeof modal.showConfirmButton === 'undefined' ? true : modal.cancelButtonClass,
confirmButtonClass: modal.confirmButtonClass ? modal.confirmButtonClass : 'btn-active',
confirmButtonText: modal.confirmButtonText ? modal.confirmButtonText : '确定',
;
return modal;
,
,
,

这里定义了接口的参数,可以自定义标题、内容、是否显示按钮和按钮的样式,用一个computed来做参数默认值的控制。

模态框内部方法
data()
return
show: false, // 是否显示模态框
resolve: '',
reject: '',
promise: '', // 保存promise对象
;
,
methods:
/**
* 确定,将promise断定为完成态
*/
submit()
this.resolve('submit');
,
/**
* 关闭,将promise断定为reject状态
* @param type number 关闭的方式 0表示关闭按钮关闭,1表示取消按钮关闭
*/
close(type)
this.show = false;
this.reject(type);
,
/**
* 显示confirm弹出,并创建promise对象
* @returns Promise
*/
confirm()
this.show = true;
this.promise = new Promise((resolve, reject) =>
this.resolve = resolve;
this.reject = reject;
);
return this.promise; //返回promise对象,给父级组件调用
,
,

在模态框内部定义了三个方法,最核心部分confirm方法,这是一个定义在模态框内部,但是是给使用模态框的父级组件调用的方法,该方法返回的是一个promise对象,并将resolve和reject存放于modal组件的data中,点击取消按钮时,断定为reject状态,并将模态框关闭掉,点确定按钮时,断定为resolve状态,模态框没有关闭,由调用modal组件的父级组件的回调处理完成后手动控制关闭模态框。

调用
<!-- template -->
<confirm v-ref:dialog :modal-options.sync="modal"></confirm>
<!-- methods -->
this.$refs.dialog.confirm().then(() =>
// 点击确定按钮的回调处理
callback();
this.$refs.dialog.show = false;
).catch(() =>
// 点击取消按钮的回调处理
callback();
);

用 v-ref 创建一个索引,就很方便拿到模态框组件内部的方法了。这样一个模态框组件就完成了。

其他实现方法

在模态框组件中,比较难实现的应该是点击确定和取消按钮时,父级的回调处理,我在做这个组件时,也参考了一些其实实现方案。

使用事件转发

这个方法是我的同事实现的,用在上一个项目,采用的是$dispatch和$broadcast来派发或广播事件。

首先在根组件接收dispatch过来的transmit事件,再将transmit事件传递过来的eventName广播下去
events:
/**
* 转发事件
* @param string eventName 事件名称
* @param object arg 事件参数
* @return null
*/
'transmit': function (eventName, arg)
this.$broadcast(eventName, arg);

,

其次是模态框组件内部接收从父级组件传递过来的确定和取消按钮所触发的事件名,点击取消和确定按钮的时候触发
// 接收事件,获得需要取消和确定按钮的事件名
events:
'tip': function(obj)
this.events =
cancel: obj.events.cancel,
confirm: obj.events.confirm



// 取消按钮
cancel:function()
this.$dispatch('transmit',this.events.cancel);

// 确定按钮
submit: function()
this.$dispatch('transmit',this.events.submit);


在父级组件中调用模态框如下:
this.$dispatch('transmit','tip',
events:
confirm: 'confirmEvent'

);
this.$once('confirmEvent',function()
callback();


先是传递tip事件,将事件名传递给模态框,再用$once监听确定或取消按钮所触发的事件,事件触发后进行回调。

这种方法看起来是不是很晕?所以vue 2.0取消了$dispatch和$broadcast,我们在最近的项目中虽然还在用1.0,但是也不再用$dispatch和$broadcast,方便以后的升级。

使用emit来触发

这种方法来自 vue-bootstrap-modal ,点击取消和确定按钮的时候分别emit一个事件,直接在组件上监听这个事件,这种做法的好处是事件比较容易追踪。
// 确定按钮
ok ()
this.$emit('ok');
if (this.closeWhenOK)
this.show = false;

,
// 取消按钮
cancel ()
this.$emit('cancel');
this.show = false;
,

调用:
<modal title="Modal Title" :show.sync="show" @ok="ok" @cancel="cancel">
Modal Text
</modal>

但是我们在使用的时候经常会遇到这样的场景,在一个组件的内部,经常会用到多个对话框,对话框可能只是文字有点区别,回调不同,这时就需要在template中为每个对话框都写一次,有点麻烦。
参考技术A 其实以前也有一些用户跟我纠结过这个问题,他们觉得一定要在需要的时候创建这个组件才是符合他们思维的做法。在我看来,这是没有理解『状态驱动的界面』的一种表现。

传统的命令式 (Imperative) 的思维写出来的代码:

$('.open-modal').on('click', function ()
var modal = new Modal()
modal.$appendTo('body')
modal.open()
)

// 在 modal 内部还要处理关闭、销毁自身的逻辑

状态驱动的思维写出来的代码:

this.showModal = true

// 关掉
this.showModal = false

哪个干净,哪个容易理解、容易测试、容易维护?

从模板的角度来看:在父模板里直接写入 <modal> 标签,那么这个 modal 渲染的位置是清晰明确的,你看一眼父模板就知道,哦,这里可能会有个 modal,也就是说,你的模板描述了最终可能渲染出来的 DOM 结构。但命令式思维下异步添加的 modal,你看模板的时候是根本看不见的,你的模板和最终的 DOM 结构没有可靠的映射关系,因为你完全可能随手把 modal 插到任何地方。你觉得这两者哪个更容易维护?

题主可能会觉得总是渲染 <modal> 不太效率。官网示例里面的 modal 用的是 v-show,换成 v-if 就好了。v-if 和 v-show 的区别在于 v-if 是真正的 conditional rendering,如果初始状态是 false,它什么都不会干。

另外一个情况是,我们可能需要在一个嵌套了很多层的子组件里面触发 modal。这种情况下,你应该把 modal 放在根组件里面,然后从子组件触发一个事件上去。

使用 vue.js 2.0 打开引导模式

【中文标题】使用 vue.js 2.0 打开引导模式【英文标题】:Open bootstrap modal with vue.js 2.0 【发布时间】:2017-08-10 22:49:31 【问题描述】:

有人知道如何使用 vue 2.0 打开引导模式吗?在 vue.js 之前,我只需使用 jQuery 打开模式:$('#myModal').modal('show');

但是,我应该在 Vue 中执行此操作吗?

谢谢。

【问题讨论】:

你的模态是一个组件吗?还是只是模板的一部分? 嗨 - 它在它自己的 Vue 组件中 基本上还是 jQuery。 $(this.$el).modal('show')。如果您想完全消除 jQuery,还有很多工作要做,因为 Bootstrap 依赖于它。 你可以使用Bootstrap-Vue 【参考方案1】:

我将Vue.js Modal example 和Bootstrap 3.* live demo 合并。

基本上,我使用了 Vue.js 模态示例,但用引导模态 html 标记替换了(排序)Vue.js“html”部分,节省一件事(我认为)。我不得不从引导程序 3 中剥离外部的 div,然后它就可以工作了,瞧!

所以相关代码是关于引导程序的。只需从引导标记中剥离外部 div 即可。所以...

呃,开发人员的网站,我不能轻易粘贴代码?这对我来说一直是一个严重的问题。我是唯一一个?根据历史,我是个白痴,有一种简单的方法可以粘贴代码,请指教。每次我尝试时,充其量都是一种可怕的格式化黑客攻击。 如果需要,我将提供一个示例 jsfiddle,说明我是如何做到的。

【讨论】:

您可以发布带有缩进、反引号或嵌入小提琴的代码。 Here is a detailed reference。问题编辑器也有插入代码的按钮。【参考方案2】:

我的代码基于 Michael Tranchida 的回答。

引导 3 html:

<div id="app">
  <div v-if="showModal">
    <transition name="modal">
      <div class="modal-mask">
        <div class="modal-wrapper">
          <div class="modal-dialog">
            <div class="modal-content">
              <div class="modal-header">
                <button type="button" class="close" @click="showModal=false">
                  <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">Modal title</h4>
              </div>
              <div class="modal-body">
                modal body
              </div>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
  <button id="show-modal" @click="showModal = true">Show Modal</button>
</div>

引导程序 4 html:

<div id="app">
  <div v-if="showModal">
    <transition name="modal">
      <div class="modal-mask">
        <div class="modal-wrapper">
          <div class="modal-dialog" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title">Modal title</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                  <span aria-hidden="true" @click="showModal = false">&times;</span>
                </button>
              </div>
              <div class="modal-body">
                <p>Modal body text goes here.</p>
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-secondary" @click="showModal = false">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
  <button @click="showModal = true">Click</button>
</div>

js:

new Vue(
  el: '#app',
  data: 
    showModal: false
  
)

css:

.modal-mask 
  position: fixed;
  z-index: 9998;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, .5);
  display: table;
  transition: opacity .3s ease;


.modal-wrapper 
  display: table-cell;
  vertical-align: middle;

在jsfiddle

【讨论】:

如何使用 BS 3 溢出? 为了防止表单提交,将 preventDefault() 添加到按钮。 &lt;button @click.prevent="showModal = true"&gt;Click&lt;/button&gt;。为防止加载时模态闪烁,请添加 v-cloak:&lt;div v-if="showModal" v-cloak&gt; 和在 css 内:[v-cloak] display:none; 优秀的答案。只是要补充一点,对于 Bootstrap 4,关键是根本没有添加类“模态”div。它将对话框拉出屏幕,似乎需要 JS 来打开它,这当然可以在 mounted() 事件中完成。尽管如此,这种方法似乎太复杂了,我发现这个解决方案更干净。一,实际上可以跳过所有内容,直到&lt;div class="modal-dialog" ...&gt;,因为我们自己使用 Vue 显示组件。除非,当然你想要一些花哨的过渡。 我试过了,它似乎没有播放过渡动画。我也试过the example from the Vue 3 docs,它也不播放过渡动画。我对 CSS 过渡不是很有经验。我研究了导入 Bootstrap JavaScript 模块(以及 jQuery 和 Popper),嗯,对于这么简单的东西来说,实在是太臃肿了。 (实际上我几乎可以这么说 Vue。几乎......)去他妈的!对话框会立即出现和消失。 好的,我解决了。在使用 &lt;transition&gt; 元素时,您实际上需要定义一个过渡(现在我想起来这听起来很明显!)。见the docs。您还需要将v-if 放在&lt;transition&gt; 中。【参考方案3】:

modal doc

Vue.component('modal', 
      template: '#modal-template'
    )

    // start app
    new Vue(
      el: '#app',
      data: 
        showModal: false
      
    )

<script type="text/x-template" id="modal-template">
  <transition name="modal">
    <div class="modal-mask">
      <div class="modal-wrapper">
        <div class="modal-container">

          <div class="modal-header">
            <slot name="header">
              default header
            </slot>
          </div>

          <div class="modal-body">
            <slot name="body">
              default body
            </slot>
          </div>

          <div class="modal-footer">
            <slot name="footer">
              default footer
              <button class="modal-default-button" @click="$emit('close')">
                OK
              </button>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</script>

<!-- app -->
<div id="app">
  <button id="show-modal" @click="showModal = true">Show Modal</button>
  <!-- use the modal component, pass in the prop -->
  <modal v-if="showModal" @close="showModal = false">
    <!--
      you can use custom content here to overwrite
      default content
    -->
    <h3 slot="header">custom header</h3>
  </modal>
</div>

【讨论】:

【参考方案4】:

试图写一段代码,使用 VueJS 的转场来操作原生的 Bootsrap 动画。

HTML:

    <div id="exampleModal">
      <!-- Button trigger modal-->
      <button class="btn btn-primary m-5" type="button" @click="showModal = !showModal">Launch demo modal</button>
      <!-- Modal-->
      <transition @enter="startTransitionModal" @after-enter="endTransitionModal" @before-leave="endTransitionModal" @after-leave="startTransitionModal">
        <div class="modal fade" v-if="showModal" ref="modal">
          <div class="modal-dialog" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
                <button class="close" type="button" @click="showModal = !showModal"><span aria-hidden="true">×</span></button>
              </div>
              <div class="modal-body">...</div>
              <div class="modal-footer">
                <button class="btn btn-secondary" @click="showModal = !showModal">Close</button>
                <button class="btn btn-primary" type="button">Save changes</button>
              </div>
            </div>
          </div>
        </div>
      </transition>
      <div class="modal-backdrop fade d-none" ref="backdrop"></div>
    </div>

Vue.JS:

    var vm = new Vue(
      el: "#exampleModal",
      data: 
        showModal: false,
      ,
      methods: 
        startTransitionModal() 
          vm.$refs.backdrop.classList.toggle("d-block");
          vm.$refs.modal.classList.toggle("d-block");
        ,
        endTransitionModal() 
          vm.$refs.backdrop.classList.toggle("show");
          vm.$refs.modal.classList.toggle("show");
        
      
    );

Example on Codepen 如果您不熟悉 Pug,请在 HTML 部分的下拉窗口中单击 查看编译的 HTML

这是 Modals 如何在 Bootstrap 中工作的基本示例。如果有人将其用于一般用途,我将不胜感激。

有一个很棒的代码?!

【讨论】:

【参考方案5】:

来自https://getbootstrap.com/docs/4.0/getting-started/javascript/#programmatic-api

$('#myModal').modal('show')

您可以通过 Vue 方法执行此操作,并且效果很好。

【讨论】:

您的回答遭到反对,但没有给出任何理由。我在网络应用程序中使用您的答案,我的印象是打开这样的对话框会导致内存泄漏。但我没有确凿的证据证明这一点。如果有人能解释为什么这个答案不起作用,那就太好了。 仅使用程序化 API 不会导致内存泄漏。此处的调用将仅显示附加到元素的现有模式。但是,如果它在您使用的代码中不起作用,您可能会遇到由于 Vue 重新渲染而导致模式最初附加到的 DOM 元素不再存在的问题。这是使用传统 Javascript 和基于 jQuery 的库的主要问题:它们依赖于 DOM 元素不会一直在变化,这对于像 Vue 这样的响应式框架来说是一个无效的假设。 如果 Bootstrap 能适应响应式框架就好了,Vue 不是唯一的,甚至不是最流行的。 这可能会被否决,因为它是 jquery 而不是 vue。 Bootstrap 4 是用 jQuery 实现的。该 jQuery 代码直接来自 Bootstrap 文档。【参考方案6】:

使用$nextTick() 函数对我有用。它只是等到 Vue 更新了 DOM,然后显示模态:

HTML

<div v-if="is_modal_visible" id="modal" class="modal fade">...</div>

JS


  data: 
    isModalVisible: false,
  ,
  methods: 
    showModal() 
      this.isModalVisible = true;
      this.$nextTick(() => 
        $('#modal').modal('show');
      );
    
  ,

【讨论】:

【参考方案7】:

这是打开 Bootstrap 模式的 Vue 方式..

引导程序 5

既然 Bootstrap 5 不再需要 jQuery,那么模块化地使用 Bootstrap 模态组件就很容易了。您可以简单地使用 data-bs 属性,或者像这样创建一个 Vue 包装器组件...

<bs-modal id="theModal">
        <button class="btn btn-info" slot="trigger"> Bootstrap modal </button>
        <div slot="target" class="modal" tabindex="-1">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title">Modal title</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">
                            <p>Modal body text goes here.</p>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                            <button type="button" class="btn btn-primary">Save changes</button>
                        </div>
                    </div>
                </div>
        </div>
</bs-modal>


const  Modal  = bootstrap

const modal = Vue.component('bsModal', 
    template: `
        <div>
            <slot name="trigger"></slot>
            <slot name="target"></slot>
        </div>
    `,
    mounted() 
        var trigger = this.$slots['trigger'][0].elm
        var target = this.$slots['target'][0].elm
        trigger.addEventListener('click',()=>
            var theModal = new Modal(target, )
            theModal.show()
        )
    ,
)

Bootstrap 5 Modal in Vue Demo

引导程序 4

Bootstrap 4 JS 组件需要 jQuery,但在 Vue 组件中使用 jQuery 不是必需的(或可取的)。而是使用 Vue 操作 DOM...

   <a href="#reject" role="button" class="btn btn-primary" @click="toggle()">Launch modal</a>
   <div :class="modalClasses" class="fade" id="reject" role="dialog">
       <div class="modal-dialog">
             <div class="modal-content">
                  <div class="modal-header">
                    <h4 class="modal-title">Modal</h4>
                    <button type="button" class="close" @click="toggle()">&times;</button>
                  </div>
                  <div class="modal-body"> ... </div>
              </div>
       </div>
   </div>

var vm = new Vue(
  el: '#app',
  data () 
    return 
        modalClasses: ['modal','fade'],
    
  ,
  methods: 
    toggle() 
        document.body.className += ' modal-open'
        let modalClasses = this.modalClasses
    
        if (modalClasses.indexOf('d-block') > -1) 
            modalClasses.pop()
            modalClasses.pop()
    
            //hide backdrop
            let backdrop = document.querySelector('.modal-backdrop')
            document.body.removeChild(backdrop)
        
        else 
            modalClasses.push('d-block')
            modalClasses.push('show')
    
            //show backdrop
            let backdrop = document.createElement('div')
            backdrop.classList = "modal-backdrop fade show"
            document.body.appendChild(backdrop)
        
    
  
)

Bootstrap 4 Vue Modal Demo

【讨论】:

【参考方案8】:

我的首要任务是继续使用 Bootstrap 代码,因为他们努力使模式工作,修复滚动条等等。我发现现有的提案试图模仿这一点,但它们只是完成了一部分。我什至不想碰运气:我只想使用实际的引导代码。

另外,我想要一个程序界面,例如调用dialog.show(gimme plenty of parameters here),而不仅仅是在某处切换变量(即使该变量可能是一个复杂对象)。

我还想为实际的对话框内容提供 Vue 的反应性和组件渲染。

要解决的问题是,如果 Vue 发现组件的 DOM 被外部操纵,它会拒绝合作。因此,基本上,我将声明模态本身的外部 div 移出组件并注册了组件,以便我还可以通过程序访问对话框。

这样的代码是可能的:

window.mydialog.yesNo('Question', 'Do you like this dialog?')

解决方案。

main.html(基本上只是包装我们组件的外部 div):

<div class="modal fade" id="df-modal-handler" tabindex="-1" role="dialog" aria-hidden="true">
  <df-modal-handler/>
</div>

component-template.html(模态的其余部分):

<script type="text/x-template" id="df-modal-handler-template">
  <div :class="'modal-dialog ' + sizeClass" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title"> title </h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body" v-html="body"/>
      <div class="modal-footer">
        <button type="button" v-for="button in buttons" :class="button.classes" v-bind="button.arias"
                @click.stop="buttonClick(button, callback)"> button.text 
        </button>
      </div>
    </div>
  </div>
</script>

component-def.js - 包含显示和操作对话框的逻辑,还支持对话框堆栈以防您出错并按顺序调用两个对话框:

  Vue.component('df-modal-handler', 
    template: `#df-modal-handler-template`,
    props: ,
    data() 
      return 
        dialogs: [],
        initialEventAssignDone: false,
      ;
    ,
    computed: 
      bootstrapDialog()  return document.querySelector('#df-modal-handler'); ,
      currentDialog()  return this.dialogs.length ? this.dialogs[this.dialogs.length - 1] : null; ,
      sizeClass() 
        let dlg = this.currentDialog;
        if (!dlg) return 'modal-sm';
        if (dlg.large || ['large', 'lg', 'modal-lg'].includes(dlg.size)) return 'modal-lg';
        else if (dlg.small || ['small', 'sm', 'modal-sm'].includes(dlg.size)) return 'modal-sm';
        return '';
      ,
      title()  return this.currentDialog ? this.currentDialog.title : 'No dialogs to show!'; ,
      body()  return this.currentDialog ? this.currentDialog.body : 'No dialogs have been invoked'; ,
      callback()  return this.currentDialog ? this.currentDialog.callback : null; ,
      buttons() 
        const self = this;
        let res = this.currentDialog && this.currentDialog.buttons ? this.currentDialog.buttons : [close: 'default'];
        return res.map(value => 
          if (value.close == 'default') value = 
            text: 'Close',
            classes: 'btn btn-secondary',
            data_return: 'close'
          ;
          else if (value.yes == 'default') value = 
            text: 'Yes',
            classes: 'btn btn-primary',
            data_return: 'yes'
          ;
          else if (value.no == 'default') value = 
            text: 'No',
            classes: 'btn btn-secondary',
            data_return: 'no'
          ;
          value.arias = value.arias || ;
          let clss = (value.classes || '').split(' ');
          if (clss.indexOf('btn') == -1) clss.push('btn');
          value.classes = clss.join(' ');
          return value;
        );
      ,
    ,
    created() 
      // make our API available
      window.mydialog = this;
    ,
    methods: 
      show: function show() 
        const self = this;
        if (!self.initialEventAssignDone) 
          // created is too soon. if we try to do this there, the dialog won't even show.
          self.initialEventAssignDone = true;
          $(self.bootstrapDialog).on('hide.bs.modal', function (event) 
            let callback = null;
            if (self.dialogs.length) callback = self.dialogs.pop().callback;
            if (self.dialogs.length) event.preventDefault();
            if (callback && callback.df_called !== true) callback(null);
          );
        
        $(self.bootstrapDialog).modal('show');
      ,
      hide: function hide() 
        $(this.bootstrapDialog).modal('hide');
      ,
      buttonClick(button, callback) 
        if (callback)  callback(button.data_return); callback.df_called = true; 
        else console.log(button);
        this.hide();
      ,
      yesNo(title, question, callback) 
        this.dialogs.push(
          title: title, body: question, buttons: [yes: 'default', no: 'default'], callback: callback
        );
        this.show();
      ,
    ,
  );

请注意,此解决方案会在 DOM 中创建一个单独的对话框实例,并重复使用该实例来满足您的所有对话框需求。 (还)没有过渡,所以当有多个活动对话框时,用户体验不是很好。无论如何,这是不好的做法,但我希望它涵盖,因为你永远不知道......

对话框主体实际上是一个 v-html,所以只需用一些参数实例化您的组件,让它自己绘制主体。

【讨论】:

以上是关于如何使用vue.js构造modal组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue js:如何在两个组件中使用 mixin 功能?通过执行错误

如何在 Vue.js 中构造 api 调用?

如何在 Vue.js 中的两个组件之间共享一个方法?

使用 vue.js 2.0 打开引导模式

如何从模板 vue.js 2 调用 javascript?

如何在按钮标签中添加条件? (vue.js 2)