文章目录
子组件向父组件传递数据,可以通过props,props值是一个函数。举例见:todoList案例(vue版本)之添加todo。
子组件向父组件传递数据,也可以使用自定义事件来实现。本篇将使用自定义事件来实现添加todo。
自定义事件有以下两种写法。
- 第一种写法:
@addTodo="callback"
、$emit("addTodo")
- 第二种写法:
$on("addTodo",callback)
、$emit("addTodo")
代码变更涉及的文件有,
- App.vue,即App组件。
- Header.vue,即Header组件。
自定义事件实现子向父传递数据的第一种写法
App.vue(App组件)
<template>
<div id="app">
<div class="todo-container">
<div class="todo-wrap">
<Header @addTodo="addTodo"/>
<List :todos="todos"/>
<Footer/>
</div>
</div>
</div>
</template>
<script>
import Header from './components/Header.vue';
import List from "./components/List.vue";
import Footer from "./components/Footer.vue";
export default {
name: 'App',
components: {
Header,
List,
Footer
},
data(){
return {
todos:[
{id:"001",title:"吃饭",done:true},
{id:"002",title:"睡觉",done:true},
{id:"003",title:"打豆豆",done:false},
]
}
},
methods:{
addTodo(todoObj){
this.todos.unshift(todoObj);
}
}
}
</script>
<style>
body {
background: #fff;
}
.btn {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
.btn:focus {
outline: none;
}
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
Header.vue(Header组件)
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
</div>
</template>
<script>
import {nanoid} from "nanoid";
export default {
name:"Header",
methods:{
add(event){
if(!event.target.value.trim()) return;
const todoObj = {
id:nanoid(),
title:event.target.value,
done:false
}
this.$emit("addTodo",todoObj);
event.target.value = "";
}
}
}
</script>
<style scoped>
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style>
自定义事件实现子向父传递数据的第二种写法
App.vue(App组件)
<template>
<div id="app">
<div class="todo-container">
<div class="todo-wrap">
<Header ref="header"/>
<List :todos="todos"/>
<Footer/>
</div>
</div>
</div>
</template>
<script>
import Header from './components/Header.vue';
import List from "./components/List.vue";
import Footer from "./components/Footer.vue";
export default {
name: 'App',
components: {
Header,
List,
Footer
},
data(){
return {
todos:[
{id:"001",title:"吃饭",done:true},
{id:"002",title:"睡觉",done:true},
{id:"003",title:"打豆豆",done:false},
]
}
},
methods:{
addTodo(todoObj){
this.todos.unshift(todoObj);
}
},
mounted(){
this.$refs.header.$on("addTodo",this.addTodo);
},
beforeDestroy(){
this.$refs.header.$off("addTodo");
}
}
</script>
<style>
body {
background: #fff;
}
.btn {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
.btn:focus {
outline: none;
}
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
Header.vue(Header组件)
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
</div>
</template>
<script>
import {nanoid} from "nanoid";
export default {
name:"Header",
methods:{
add(event){
if(!event.target.value.trim()) return;
const todoObj = {
id:nanoid(),
title:event.target.value,
done:false
}
this.$emit("addTodo",todoObj);
event.target.value = "";
}
}
}
</script>
<style scoped>
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style>