我在使用路由的vue项目中,其教学课程:https://www.youtube.com/watch?v=Wy9q22isx3U 完整代码的仓库在这里: https://github.com/bradtraversy/vue_crash_todolist
我的Home.vue看起来像这样:
<template>
<div id="app">
<AddTodo v-on:add-todo="addTodo"/>
<Todos v-bind:todos="todos" v-on:del-todo="deleteTodo"/>
</div>
</template>
<script>
import AddTodo from '../components/AddTodo'
import Todos from '../components/Todos'
export default {
name: 'home',
components: {
Todos,
AddTodo
},
data() {
return {
todos: [
{
id: 1,
title: "Todo one",
completed: false
},
{
id: 2,
title: "Todo two",
completed: true
},
{
id: 3,
title: "Todo three",
completed: false
}
]
}
},
methods: {
deleteTodo(id){
this.todos = this.todos.filter(todo => todo.id != id)
},
addTodo(newTodo){
this.todos = [...this.todos, newTodo]
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
这里重要的是标记中的Todos元素。 它是导入TodoItem本身的复杂组件。 现在Todos看起来像这样:
<template>
<div>
<div v-bind:key="todo.id" v-for="todo in todos">
<TodoItem v-bind:todo="todo" v-on:del-todo="$emit('del-todo', todo.id)"/>
</div>
</div>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
name: "Todos",
components: {
TodoItem
},
props: ["todos"]
}
</script>
<style scoped>
</style>
它导入了TodoItem,在这里:
<template>
<div class="todo-item" v-bind:class="{'is-complete':todo.completed}">
<p>
<input type="checkbox" v-on:change="markComplete">
{{todo.title}}
<button @click="$emit('del-todo', todo.id)"class="del">x</button>
</p>
</div>
</template>
<script>
export default {
name: "TodoItem",
props:["todo"],
methods: {
markComplete(){
this.todo.completed = !this.todo.completed
}
}
}
</script>
<style scoped>
.todo-item {
background: #f4f4f4;
padding: 10px;
border-bottom: 1px #ccc dotted;
}
.is-complete {
text-decoration: line-through;
}
.del {
background: #ff0000;
color: #fff;
border: none;
padding: 5px 9px;
border-radius: 50%;
cursor: pointer;
float: right;
}
</style>
现在让我困惑的是围绕发射事件的语法。 在TodoItem中,我从按钮发出了这个事件:
<button @click="$emit('del-todo', todo.id)"class="del">x</button>
现在这对我来说是完全可以理解的,因为我们已使用“ @click”指定了事件触发器。 然后将其导出到父级Todos.vue,在那里我们可以看到:
<TodoItem v-bind:todo="todo" v-on:del-todo="$emit('del-todo', todo.id)"/>
我在这里开始感到困惑。 同样,在长语法中,定义了事件触发器:
v-on:del-todo
但是del-todo并不是事件触发器。它既不单击,也不更改,也不输入。 那么,这些代码如何工作?当vue.js遇到上述代码时,意味着什么?
然后我对Home.vue的困惑更加严重
<Todos v-bind:todos="todos" v-on:del-todo="deleteTodo"/>
第三次指定事件触发器。 并且第二次,此事件触发器未指定“本地”触发器,如click。
现在我已经把头缠住了,至少可以克服一些感觉。 在Todos.vue和Home.vue中,del-todo触发后,指定的事件似乎会执行。因此,它们就像回调一样,采用del-todo的返回值。 在Todos.vue中,触发del-todo会向其父级Home.vue发出del-todo。 那是对的吗?
Home.vue然后在触发del-todo时触发deleteTodo。
但是,deleteTodo要求通过该参数传递ID,但是有趣的是,<Todos v-bind:todos="todos" v-on:del-todo="deleteTodo"/>
不需要。
尽管如此,该功能仍然有效。那么id如何到达deleteTodo?
TodoItem.vue中出现类似的问题。在这里,调用了del-todo,但是实际上我们在TodoItem.vue中的脚本中的任何地方都没有对该函数的任何形式的声明。再说一遍,当遇到一个没有被定义的函数被发出/调用的情况时,vueJS意味着什么?
答案 0 :(得分:1)
正在发生的事情是,每次单击时,都会向父组件发送一个事件AND值,父组件具有一个侦听器v-on:del-todo
,这意味着一旦侦听del-todo
事件触发/处理后,它将再次向上发射它,直到到达您要实际操作数据的组件为止(根据ID删除项目)。
注意:该值会隐式传递到处理程序函数deleteTodo
中,因此即使它不在显式位置(即deleteTodo($event)
也存在)。
答案 1 :(得分:1)
在Vue.js中,不仅有事件click
change
和input
,还允许您定义自定义事件。您所要做的全部操作是使用$emit('my-custom-event', param1, param2)
在子组件中引发一个事件,并使用v-on:my-custom-event="handler"
将其捕获到直接父组件中(您也可以写@my-custom-event
,这就是同义词)。处理程序是一个函数,它在发出事件时采用传递的参数。 Todos
组件中的处理程序将捕获事件del-todo
,并引发一个具有相同名称的新事件。 Home
组件捕获到该事件,并将其函数deleteTodo
定义为其处理程序,因此将调用此函数(随事件传递的id是deleteTodo
的参数)