【问题标题】:Vuejs bind class to row then later hide/show the row?Vuejs将类绑定到行然后隐藏/显示行?
【发布时间】:2018-05-31 23:19:32
【问题描述】:

我正在尝试创建一个表,用户可以在其中隐藏行,并在删除其他行时保持隐藏。

在我的html中,我在渲染表格时使用vuejs绑定一个类:

<tr v-for="item in mylist" :class="{'noFruits': (item.fruits.length == 0)}">

有一个用户复选框可以隐藏该类的行:

<label><input type="checkbox" v-model="showBlankFruits" @change="setBlankDisplay">Show Blank Fruits</label>

在我的 Vue 实例中,复选框执行一个方法来通过 jquery 隐藏/显示该类的行以附加 css 显示属性:

methods: {
  setBlankDisplay: function() {
    if (this.showBlankFruits) {
     $('.noFruits').css('display', '');
  } else {
     $('.noFruits').css('display', 'none');
  }
},

在我的jsfiddle 中,当用户删除一行时,隐藏的行会重新出现。我看到在这种情况下使用 jquery 附加样式并不好......有人对更好的方法有建议吗?

【问题讨论】:

标签: javascript jquery vue.js vuejs2


【解决方案1】:

这是一个很好的例子,展示了声明式渲染的强大功能,而不是在组件中使用 DOM 操作。您遇到的问题是当 Vue 引擎重新呈现您的列表时,它不知道您在 setBlankDisplay 方法中对元素进行的手动操作。解决这个问题的方法是在视图本身的定义中使用组件逻辑,有点像您首先设置 noFruits 类。

所以,我建议你把setBlankDisplay去掉,换成方法:

itemDisplay(item) {
    if (item.fruits.length === 0 && !this.showBlankFruits) {
    return 'none';
  }
  return '';
},

然后您可以在链接到 css display 属性的 tr 元素的定义中引用它,如下所示:

<tr v-for="item in mylist" :class="{'noFruits': (item.fruits.length == 0)}" :style="{display: itemDisplay(item)}">

我已经用这个修改更新了jsfiddle,显示当其他项目被删除时隐藏水果的状态仍然存在。

以此作为使用 jquery 更改视图状态的危险的一般示例。应尽一切努力根据组件逻辑定义整个视图。

【讨论】:

    【解决方案2】:

    不建议混合使用 Vue 和 jQuery,因为您几乎可以使用 Vue 完成所有事情,而且您不会遇到任何不知道其他库/框架在做什么的冲突操作。

    如果 fruits 数组长度为真,即不为 ​​0,或者 showBlankFruits 为真,则以下将显示该行:

    <tr v-for="item in mylist" v-show="item.fruits.length || showBlankFruits">
    

    单击复选框时,以下内容将切换 showBlankFruits:

    <label><input type="checkbox" v-model="showBlankFruits">Show Blank Fruits</label>
    

    完整代码示例:

    JSFiddle

    【讨论】:

      【解决方案3】:

      你也可以这样写。 我已经完全使用了计算并删除了 jQuery 部分。 您必须将数据声明为函数而不是数据对象 (https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function)

      您不需要调用 mounted 方法来设置初始状态。它已经用你的数据对象设置好了。 在您的代码中,您必须调用mounted,因为jQuery 只能在加载DOM 时隐藏结果。

      new Vue({
        el: '#app',
        data() {
          return {
            showBlankFruits: true,
            mylist: [
              {'user': 'Alice', 'fruits': [{'name': 'apple'}]},
              {'user': 'Bob', 'fruits': [{'name': 'orange'}]},
              {'user': 'Charlie', 'fruits': []},
              {'user': 'Denise', 'fruits': [{'name': 'apple'}, {'name': 'orange'}]},
            ]
          }
        },
        computed: {
          list() {
            return this.mylist.filter(item => (item.fruits.length > 0 && !this.showBlankFruits) || (item.fruits.length === 0 && this.showBlankFruits))
          },
        },
        methods: {
          delItem(item) {
            let index = this.mylist.indexOf(item);
            if (index > -1) {
              this.mylist.splice(index, 1);
            }
          }
        }
      })
      <script src="https://unpkg.com/vue"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
      
      <div id="app">
        <label><input type="checkbox" v-model="showBlankFruits">Show Blank Fruits</label>
        <br> <br>
        <table>
          <tr> <th class="col">User</th> <th class="col">Fruits</th> <th class="col"></th> </tr>
          <tr v-for="item in list">
            <td>{{ item.user }}</td>
            <td> <span v-for="f in item.fruits"> {{ f.name }} </span> </td>
            <td> <button @click="delItem(item)">Delete</button> </td>
          </tr>
        </table>
      </div>

      【讨论】:

      • 比起@cstricklan 解决方案中的样式绑定,我更喜欢这样做。使用计算过滤数据使组件更具可测试性。
      • 数据必须成为组件的函数。据我所知,对于根 Vue 实例,不“推荐”它是任何地方的函数。事实上,文档会引导您使用来自 very beginning 的对象。
      • 我写了“推荐”,因为在这个例子中他使用的是单个实例,它不会破坏应用程序。但你是对的!我会更新我的答案。
      • 过滤条件可以简化,item.fruits.length || this.showBlankFruits
      • @LeeComstock 是的,你是对的,如果你想每次都显示完整的列表,无论是否有空水果。我坚持认为 Andrew 不能同时想要两者,因为复选框标签上写着“显示空白水果”而不是“显示空白水果”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      • 2020-08-12
      • 2017-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-07-06
      相关资源
      最近更新 更多