【问题标题】::class not updating when clicked in vuejs v-for在 vuejs v-for 中单击时:类不更新
【发布时间】:2019-08-28 11:54:40
【问题描述】:

我想在点击 td 时为 v-for 中的项目添加一个 css 类

      <template>
  <div>
    <h1>Forces ()</h1>

    <section v-if="errored">
      <p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
    </section>

    <section v-if="loading">
      <p>loading...</p>
    </section>

    <table class="table table-bordered table-hover">

      <thead>
        <tr>
          <th>#</th>
          <th>ID</th>

          <th 
              @click="orderByName = !orderByName">Forces</th>
        </tr>
        <th>Delete</th>
      </thead>
      <tbody>
        <tr v-for="(force, index) in forces" @click="completeTask(force)" :class="{completed: force.done}"  v-bind:key="index">

          <td>
            <router-link :to="{ name: 'ListForce', params: { name: force.id } }">Link</router-link>
          </td>

          <th>{{ force.done }}</th>

          <th>{{ force.name }}</th>
          <th><button v-on:click="removeElement(index)">remove</button></th>

        </tr>
      </tbody>
    </table>
    <div>
    </div>
  </div>

</template>


<script>
import {APIService} from '../APIService';
const apiService = new APIService();
const _ = require('lodash');

export default {

  name: 'ListForces',

  components: {

  },

  data() {
    return {
      question: '',
      forces: [{
        done: null,
        id: null,
        name: null
      }],
      errored: false,
      loading: true,
      orderByName: false,
    };

  },

  methods: {
    getForces(){
      apiService.getForces().then((data, error) => {

          this.forces = data;
          this.forces.map(function(e){
               e.done = false;
          });
          this.loading= false;
        console.log(this.forces)
      });
    },
    completeTask(force) {
      force.done = ! force.done;
      console.log(force.done);
    },
    removeElement: function (index) {
      this.forces.splice(index, 1);
    }
  },

  computed: {
/*    forcesOrdered() {
      return this.orderByName ? _.orderBy(this.forces, 'name', 'desc') : this.forces;
    }*/
  },
  mounted() {
    this.getForces();
  },
}
</script>

<style>
    .completed {
        text-decoration: line-through;
    }
</style>

我希望在单击时有一条线穿过项目,但 dom 没有更新。如果我进入 chrome 中的 vue 选项卡,我可以看到每个项目的 force.done 更改,但前提是我单击对象并重新单击它。我不确定为什么当我之前使用过点击和 css 绑定时状态没有更新。

【问题讨论】:

  • 这听起来像是反应性问题。 forcesOrdered 来自哪里?它是在组件data 或存储state 中的某处定义的吗?您可能想尝试使用this.$set(force, 'done', true) 看看是否有效。它没有解决根本问题,但有助于确认这是一个反应性问题。
  • done 是这些对象的现有属性还是您将其添加到 completeTask 中?
  • 嗨,是的,它是对象中的一个属性
  • forcesOrdered 在计算中
  • 试过this.$set(force, 'done', true) 但和以前一样,值更新但屏幕上没有更新

标签: vue.js v-for


【解决方案1】:

我已尝试进行最小的更改以使其正常工作:

// import {APIService} from '../APIService';
// const apiService = new APIService();
// const _ = require('lodash');

const apiService = {
  getForces () {
    return Promise.resolve([
      { id: 1, name: 'Red' },
      { id: 2, name: 'Green' },
      { id: 3, name: 'Blue' }
    ])
  }
}

new Vue({
  el: '#app',
  name: 'ListForces',

  components: {

  },

  data() {
    return {
      question: '',
      forces: [{
        done: null,
        id: null,
        name: null
      }],
      errored: false,
      loading: true,
      orderByName: false,
    };

  },

  methods: {
    getForces(){
      apiService.getForces().then((data, error) => {
          for (const force of data) {
            force.done = false;
          }

          this.forces = data;
          this.loading= false;
        console.log(this.forces)
      });
    },
    completeTask(force) {
      force.done = ! force.done;
      console.log(force.done);
    },
    removeElement: function (index) {
      this.forces.splice(index, 1);
    }
  },

  mounted() {
    this.getForces();
  }
})
.completed {
  text-decoration: line-through;
}
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
  <div>
    <h1>Forces ()</h1>

    <section v-if="errored">
      <p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
    </section>

    <section v-if="loading">
      <p>loading...</p>
    </section>

    <table class="table table-bordered table-hover">

      <thead>
        <tr>
          <th>#</th>
          <th>ID</th>

          <th 
              @click="orderByName = !orderByName">Forces</th>
          <th>Delete</th>
        </tr>
        
      </thead>
      <tbody>
        <tr v-for="(force, index) in forces" @click="completeTask(force)" :class="{completed: force.done}"  v-bind:key="index">

          <th>{{ force.done }}</th>

          <th>{{ force.name }}</th>
          <th><button v-on:click="removeElement(index)">remove</button></th>

        </tr>
      </tbody>
    </table>
    <div>
    </div>
  </div>
</div>

关键问题在这里:

this.forces = data;
this.forces.map(function(e){
  e.done = false;
});

这里的问题是属性done 是在它被响应后被添加到数据中的。只要this.forces = data 行运行,就会添加反应性观察者。在此之后添加done 算作添加新属性,这将不起作用。

这也是对map 的滥用,所以我将其切换为for/of 循环。

for (const force of data) {
  force.done = false;
}

this.forces = data; // <- data becomes reactive here, including 'done'

在一个不相关的注释中,我调整了模板以将Delete 标题移动到顶行内。

【讨论】:

    【解决方案2】:

    确保在初始化之前将force.done 中的false 设置为false,使其具有反应性。

    data() {
      return {
        force:{
          done: false;
        }
      }
    }
    

    如果force 存在但没有done 成员集,您可以在初始化后使用Vue.set 而不是= 来创建反应值。

    Vue.set(this.force, 'done', true);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-29
      • 2019-09-24
      • 2023-03-24
      • 2019-01-14
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      相关资源
      最近更新 更多