将Vue待办事项列表项标记为已完成

时间:2018-07-24 22:37:15

标签: vuejs2

这可能以前已经回答过,但是我无法找到在这种特定情况下可行的答案。

我是Vue的新手,正尝试构建一个Todo列表,在其中,我可以在列表项完成后单击它,更改或添加一个会更改项目样式的类。

我想我不完全了解示波器在主Vue和组件之间如何协同工作。我现在拥有的代码绝对没有任何作用。我尝试过在主体和组件之间移动方法,但是它总是给我带来一些错误。

我想我只是在寻找有关应如何完成操作的指导。

Vue.component('todo-item', {
	props: ['todo'],
	template: '<li>{{ todo.id + 1 }}. {{ todo.text }}</li>'
})

var app = new Vue({
	el: '#app',
	data: {
		isDone: false,
		todos: [
			{ id: 0, text: 'This is an item to do today' },
			{ id: 1, text: 'This is an item to do today' },
			{ id: 2, text: 'This is an item to do today' },
			{ id: 3, text: 'This is an item to do today' },
			{ id: 4, text: 'This is an item to do today' },
			{ id: 5, text: 'This is an item to do today' }
		]
	},
	methods: {
		markDone: function(todo) {
			console.log(todo)
			this.isDone = true
		}
	}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
  <div class="content">
    <ul class="flex">
      <todo-item 
        v-for="todo in todos"
        :todo="todo"
        :key="todo.id"
        @click="markDone"
        :class="{'done': isDone}"
      ></todo-item>
    </ul>
  </div>
</div>

谢谢大家的帮助。

3 个答案:

答案 0 :(得分:0)

在您的代码中,用click事件处理的是<li>元素,但是您试图在组件的根目录中处理它,有几种方法可以解决此问题

使用本地修饰符

<todo-item 
    v-for="todo in todos"
    :todo="todo"
    :key="todo.id"
    @click.native="markDone"
    :class="{'done': isDone}"
>
</todo-item>

您可以在此处找到更多信息 https://vuejs.org/v2/guide/migration.html#Listening-for-Native-Events-on-Components-with-v-on-changed

从组件中发出点击事件

Vue.component('todo-item', {
  props: ['todo'],
  template: '<li @click="click()">{{ todo.id + 1 }}. {{ todo.text }}</li>',
  methods: {
    click () {
      this.$emit('click')
    }
  }
})

顺便说一句,在您当前的代码中,一旦您单击一个待办事项,所有待办事项都将被“标记为已完成”,因为您只对所有待办事项使用了一个变量。

答案 1 :(得分:0)

First of all, your current implementation will affect all items in the list when you mark one item as done because you are associating a single isDone property to all the items and when that property becomes true, it will be applied to all the items in your list.

So to fix that, you need to find a way to associate done to each item. And because your item is an object, you just assign a new property done dynamically and set the value to true which means it is marked as done. It will be very confusing to just explain it, so I included a full example using your existing code.

See this JS Fiddle: https://jsfiddle.net/eywraw8t/205021/

答案 2 :(得分:0)

You were getting so close! You simply had your :class="{'done': isDone}" @click="markDone" in the wrong place!

The important thing to remember with components is that each one has to have their own data. In your case, you were binding all todo's to your root Vue instance's done variable. You want to instead bind each one to their own done variable in their own data.

The way you do this is by creating a function version of data that returns individual data for each component. It would look like this:

data () {
    return {
      isDone: false,
    }
  },

And then you move the :class="{'done': isDone} from the todo to the li internal to it:

<li :class="{'done': isDone}">{{ todo.id + 1 }}. {{ todo.text }}</li>

Now we have the 'done' class depending on an individual data piece for each individual todo element. All we need to do now is be able to mark it as complete. So we also want each todo component to have it's own method to do so. Add a methods: object to your todo component and move your markDone method there:

methods: {
    markDone() {
      this.isDone = true;
    },
  }

Now move the @click="markDone" to the li as well:

<li :class="{'done': isDone}" @click="markDone">{{ todo.id + 1 }}. {{ todo.text }}</li>

And there you go! Now you should be able to create as many todo's as you want, and mark them all complete!

Bonus:

Consider changing your function to toggleDone() { this.isDone = !this.isDone; }, that way you can toggle them back and forth between done and not done!

Full code below :)

Vue.component('todo-item', {
	props: ['todo'],
	template: `<li :class="{'done': isDone}" @click="toggleDone">{{ todo.id + 1 }}. {{ todo.text }}</li>`,
  data () {
    return {
      isDone: false,
    }
  },
  methods: {
    toggleDone() {
      this.isDone = !this.isDone;
    },
  }
})

var app = new Vue({
	el: '#app',
	data: {
		isDone: false,
		todos: [
			{ id: 0, text: 'This is an item to do today' },
			{ id: 1, text: 'This is an item to do today' },
			{ id: 2, text: 'This is an item to do today' },
			{ id: 3, text: 'This is an item to do today' },
			{ id: 4, text: 'This is an item to do today' },
			{ id: 5, text: 'This is an item to do today' }
		]
	},
	methods: {
		markDone: function(todo) {
			console.log(todo)
			this.isDone = true
		}
	}
})
.done {
  text-decoration: line-through;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
  <div class="content">
    <ul class="flex">
      <todo-item 
        v-for="todo in todos"
        :todo="todo"
        :key="todo.id"
      ></todo-item>
    </ul>
  </div>
</div>