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