为啥在 Vue 中使用模态时我的 v-if 不触发?

Posted

技术标签:

【中文标题】为啥在 Vue 中使用模态时我的 v-if 不触发?【英文标题】:Why does my v-if not fire when using modals with Vue?为什么在 Vue 中使用模态时我的 v-if 不触发? 【发布时间】:2019-10-07 03:34:17 【问题描述】:

我正在使用 v-if 来控制我的 Vue 应用程序中页面的显示。 'page' 数据属性跟踪当前页面并通过按钮单击进行更新。在我引入模态之前,这非常有效,因为现在当我打开一个模态并导航回几个页面(使用我的应用程序的导航按钮)时,尽管属性已正确更新,但页面仍无法显示。

这是一个简化的示例 - 导航到页面 B 然后 C 然后显示模式 2。取消模式 2,然后导航到页面 B 并且没有任何显示(尽管标题指示页面属性是 B)。

https://jsfiddle.net/fLmq0dxn/1/

我已经在引导模式和本机 js 模式中尝试过这种方法,但会出现同样的问题。控制台中没有报告错误。我认为这可能是错误嵌套的 div,但我已经检查了这些并通过了验证器。

我意识到我的导航方法是原始的,并且模态可能应该是组件,但我是 Vue 的新手,据我了解,我的方法“应该”工作。谁能解释为什么不喜欢?

html

<div id="app">

  <p>(app.page = page)</p>
  <br/>

  <div class="page" id="A" v-if="page=='A'">
  Page A
  <br/>
  <button v-on:click="pager('B')">To B</button>
  </div>

  <div class="page" id="B" v-if="page=='B'">
  Page B
  <br/>
  <button v-on:click="pager('C')">To C</button>
  <button v-on:click="modalOpen('mod1')">Modal</button>
  </div>

  <!-- ************ Modal 1 ************************************ -->
  <div id="mod1" class="mod">
    <div class="mod-content">
      <span class="mod-close" v-on:click="modalClose">&times;</span>
      <h1>Modal 1</h1>

      <button v-on:click="modalClose" class="btn btn-secondary">Cancel</button>
    </div>
  </div>


  <div class="page" id="C" v-if="page=='C'">
  Page C
  <br/>
  <button v-on:click="pager('B')">To B</button>
  <button v-on:click="modalOpen('mod2')">Modal</button>
  </div>


     <!-- ************ Modal 2 ************************************ -->
  <div id="mod2" class="mod">
    <div class="mod-content">
      <span class="mod-close" v-on:click="modalClose">&times;</span>
      <h1>Modal 2</h1>

      <button v-on:click="modalClose" class="btn btn-secondary">Cancel</button>
    </div>
  </div>

</div>

CSS:

/* The Modal (background) */
.mod 
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 1; /* Sit on top */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
  

  /* Modal Content/Box */
  .mod-content 
    background-color: #fefefe;
    margin: 20% auto;
    padding: 20px;
    border: 1px solid #888;
    border-radius:8px;
    width: 90%;
    max-width:800px;
  

  /* The Close Button */
  .mod-close 
    color: #aaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
  

  .mod-close:hover,
  .mod-close:focus 
    color: black;
    text-decoration: none;
    cursor: pointer;
  

javascript

new Vue(
  el: "#app",
  data: 
        page: "A"
  ,
  methods: 
    pager: function(target)
        this.page=target;
    ,
    modalOpen: function(modID) 
        $('#'+ modID).css('display','block');
      ,
    modalClose: function()     
            $('.mod').css('display','none');
    
  
)

【问题讨论】:

使用#id模型关闭$('#'+modeid).css('display','none') 感谢@Alaa - 修复了这个非常简单的示例,但不适用于我的实际应用程序。为什么我不能使用他们的类关闭模式? $('.mod').css('display','none'); 【参考方案1】:

不幸的是,将 Vue 与 jQuery 结合是有风险的。

在您的特定情况下,似乎当您尝试关闭模式时,jQuery 会查找所有具有“mod”类的元素,但是在隐藏它们时,选择会被 Vue 篡改,最终会隐藏不正确的元素(在您的情况下,您的页面 B) 的内容。 Vue 的设计初衷不是让另一个库摆弄 DOM。

您可以仅使用 Vue“轻松”实现您的目标。由于您通过更改样式来管理模态框,因此您可以使用 Vue class and/or style binding 做类似的事情。

例如您可以拥有一个覆盖您的display: none 的类,并且您可以根据数据有条件地应用该类,这与您对页面所做的非常相似。您甚至可以使用 v-if 管理您的模式,就像您对页面所做的一样。

条件类示例:https://jsfiddle.net/jfx8mbya/

由 v-if 管理的模态示例:

new Vue(
  el: "#app",
  data: 
    page: "A",
    modal: null
  ,
  methods: 
    pager: function(target) 
      this.page = target;
    ,
    modalOpen: function(modID) 
      this.modal = modID;
    ,
    modalClose: function() 
      this.modal = null;
    
  
)
/* The Modal (background) */

.mod 
  /*display: none;*/
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: auto;
  /* Enable scroll if needed */
  background-color: rgb(0, 0, 0);
  /* Fallback color */
  background-color: rgba(0, 0, 0, 0.4);
  /* Black w/ opacity */



/* Modal Content/Box */

.mod-content 
  background-color: #fefefe;
  margin: 20% auto;
  padding: 20px;
  border: 1px solid #888;
  border-radius: 8px;
  width: 90%;
  max-width: 800px;



/* The Close Button */

.mod-close 
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;


.mod-close:hover,
.mod-close:focus 
  color: black;
  text-decoration: none;
  cursor: pointer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">

  <p>(app.page = page)</p>
  <br/>

  <div class="page" id="A" v-if="page=='A'">
    Page A
    <br/>
    <button v-on:click="pager('B')">To B</button>
  </div>

  <div class="page" id="B" v-if="page=='B'">
    Page B
    <br/>
    <button v-on:click="pager('C')">To C</button>
    <button v-on:click="modalOpen('mod1')">Modal</button>
  </div>

  <!-- ************ Modal 1 ************************************ -->
  <div id="mod1" class="mod" v-if="modal === 'mod1'">
    <div class="mod-content">
      <span class="mod-close" v-on:click="modalClose">&times;</span>
      <h1>Modal 1</h1>

      <button v-on:click="modalClose" class="btn btn-secondary">Cancel</button>
    </div>
  </div>


  <div class="page" id="C" v-if="page=='C'">
    Page C
    <br/>
    <button v-on:click="pager('B')">To B</button>
    <button v-on:click="modalOpen('mod2')">Modal</button>
  </div>


  <!-- ************ Modal 2 ************************************ -->
  <div id="mod2" class="mod" v-if="modal === 'mod2'">
    <div class="mod-content">
      <span class="mod-close" v-on:click="modalClose">&times;</span>
      <h1>Modal 2</h1>

      <button v-on:click="modalClose" class="btn btn-secondary">Cancel</button>
    </div>
  </div>

</div>

【讨论】:

同意。优秀的答案.. 并详细说明(更多的长期解决方案).. 如果您想在 Vue 应用程序中呈现浏览页面的外观 - 最好使用Vue Router,imo。这正是它所做的——隐藏/显示 DOM 的不同部分,特别是看起来好像你正在浏览页面......在 Vue 中抛弃 jQuery 式的思维)——你可以将每个模式放在自己的“页面”中,等等。Basic Vue Router demo

以上是关于为啥在 Vue 中使用模态时我的 v-if 不触发?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Nativescript-vue 应用程序在呈现模态之前使用硬件后退按钮时崩溃?

模态仅在第二次单击后显示

vue 使用element表单不触发验证

Vue.js 使用点击事件在模态框上填充表单字段值

vuex 3.6为啥在方法中使用它时我的状态对象未定义

v-if和v-for为啥避免一起用