v-for循环中的单个单击处理程序

时间:2018-04-17 17:20:37

标签: vue.js

我使用以下代码生成列表:

      <li class="list-group-item border" v-for="command in commands" :key="command">
        <div v-if="!command.args">
          <h3>{{ command.name }}</h3>
          <small>{{ command.desc }}</small>
        </div>
        <div v-else>
          <button @click="toggleActive">{{ command.name }}</button>
          <small>{{ command.desc }}</small>
          <div class="args" v-if="active" v-for="(argDesc, argName) in command.args" :key="argName, argDesc">
            <hr>
            <p>{{ argName }}</p>
            <small>{{ argDesc }}</small>
          </div>
        </div>
      </li>

使用以下数据:

  commands: {
    foo: { name: "foo", desc: "bar" },
    lorem: {
      name: "lorem",
      desc: "ipsum",
      args: {
        place: "holder"
      }
    },

和方法:

  methods: {
    toggleActive: function(event) {
      let clickedButton = event.currentTarget;
      clickedButton.classList.toggle("active");
      if (this.active) {
        this.active = false;
      } else if (!this.active) {
        this.active = true;
      }
    }
  }

如果有一个更优雅的解决方案,我想知道,但我真正的问题是如何才能使点击按钮而不是所有生成的按钮触发onclick事件?< / p>

1 个答案:

答案 0 :(得分:3)

您目前的整个实例都有一个 active属性。

一种解决方案是为每个active添加command属性,然后将其切换为:

  • 您的点击处理程序应为:@click="toggleActive($event, command)"
  • 您的方法现在应设置command.active,而不是this.active

    methods: {
      toggleActive: function(event, command) {   // added command arg
        // removed manual class toggling (see "Bonus" below)
        if (command.active) {                    // command.active instead of this.active
          command.active = false;                // command.active instead of this.active
        } else if (!command.active) {
          Vue.set(command, 'active', true);      // using `Vue.set()`  because `active`
        }                                        // was not initially in `data()`
      }
    }
    
  • 最后,您的v-if应该引用每个命令:v-if="command.active"

  • 加分:使用Vue,您不必直接执行clickedButton.classList.toggle("active");。您只需绑定class属性::class="{active: command.active}"

演示如下:

&#13;
&#13;
new Vue({
  el: '#app',
  data: {
    commands: {
      foo: { name: "foo", desc: "bar" },
      lorem: {
        name: "lorem",
        desc: "ipsum",
        args: {
          place: "holder"
        }
      },
      aaa: {
        name: "aaa",
        desc: "bbb",
        args: {
          place: "ccc"
        }
      },
    }
  },
  methods: {
    toggleActive: function(event, command) {
      // removed manual class toggling in favor of :class="{active: command.active}"
      if (command.active) {
        command.active = false;
      } else if (!command.active) {
        Vue.set(command, 'active', true);
      }
    }
  }
})
&#13;
.active { color: red }
&#13;
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <li class="list-group-item border" v-for="command in commands" :key="command.name">
    <div v-if="!command.args">
      <h3>{{ command.name }}</h3>
      <small>{{ command.desc }}</small>
    </div>
    <div v-else>
      <button @click="toggleActive($event, command)" :class="{active: command.active}">{{ command.name }}</button>
      <small>{{ command.desc }}</small>
      <div class="args" v-if="command.active" v-for="(argDesc, argName) in command.args" :key="argName, argDesc">
        <hr>
        <p>{{ argName }}</p>
        <small>{{ argDesc }}</small>
      </div>
    </div>
  </li>
</div>
&#13;
&#13;
&#13;

如果您不想更改每个command,另一个选择是将active转换为旗帜地图(而不是仅仅一个旗帜):

&#13;
&#13;
new Vue({
  el: '#app',
  data: {
    active: {}, // should be an object
    commands: {
      foo: { name: "foo", desc: "bar" },
      lorem: {
        name: "lorem",
        desc: "ipsum",
        args: {
          place: "holder"
        }
      },
      aaa: {
        name: "aaa",
        desc: "bbb",
        args: {
          place: "ccc"
        }
      },
    }
  },
  methods: {
    toggleActive: function(event, command) {
      // removed manual class toggling in favor of :class="{active: active[command.name]}"
      if (this.active[command.name]) {
        this.active[command.name] = false;
      } else if (!this.active[command.name]) {
        Vue.set(this.active, command.name, true);
      }
    }
  }
})
&#13;
.active { color: red }
&#13;
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <li class="list-group-item border" v-for="command in commands" :key="command.name">
    <div v-if="!command.args">
      <h3>{{ command.name }}</h3>
      <small>{{ command.desc }}</small>
    </div>
    <div v-else>
      <button @click="toggleActive($event, command)" :class="{active: active[command.name]}">{{ command.name }}</button>
      <small>{{ command.desc }}</small>
      <div class="args" v-if="active[command.name]" v-for="(argDesc, argName) in command.args" :key="argName, argDesc">
        <hr>
        <p>{{ argName }}</p>
        <small>{{ argDesc }}</small>
      </div>
    </div>
  </li>
</div>
&#13;
&#13;
&#13;