1.组件通信
1.1父向子
1.分析谁是父组件 谁是子组件;
2.子组件中通过props 定义变量,直接使用变量;
3.父组件 中 自定义变量 传递值
注意:父向子可以传递任意类型的数据
props数据验证
1.props选项的值可以为数组类型也可以是对象类型;
2.props选项的对象类型可以对外部传递进来的参数进行数据验证;
3.比如说某个数据必须是数字类型,如果传入字符串,不会报错 会弹出警告
<template>
<div>
子组件
<hr />
{{ num }}----{{ s }}---{{ flag }}
{{ obj.name }}
</div>
</template>
<script>
export default {
// props: ["num", "s", "flag", "obj"],
props: {
// 必须是数字类型
num: Number,
//必须是数字或者字符串
s: [String, Number],
// 布尔类型,默认为true
flag: {
type: Boolean,
default: true,
},
// 如果是对象或者数组,默认必须是一个函数返回
obj: {
type: Object,
default: function () {
return {};
},
},
},
};
</script>
<style scoped>
</style>
单向数据流
在vue中需要遵循单向数据流原则:
1.父组件数据发生了改变,子组件会自动跟着变;
2.子组件不能直接修改父组件传递过来的props,props是只读的;
父组件传给子组件是一个对象,子组件修改对象的属性,是不会报错的,对象是引用类型
1.2子向父
从子组件把值传给父组件
语法:
- 父组件:@自定义事件名=“父methods函数”
- 子组件:this.$emit(‘自定义事件名’,传值)–执行父methods函数代码
1.3非父子
常用于跨组件通信;
两个组件关系非常的复杂,通过父子组件通信是非常麻烦的,可以使用通用的组件通信方案—事件总线(event-bus)
1.1:src下创建EventBus/index.js --定义事件总线bus对象
// 定义事件总线bus对象
import Vue from ‘vue’
// 导出空白vue对象
export default new Vue()
2.ToDo案例
结构样式
1:创建3个组件和里面的代码还有样式
2:APP.vue中引入三个组件
渲染认为列表
需求:把任务列表展示到页面TodoMain.vue中
需求:选中状态 设置相关的样式
步骤:
1.App.vue 中定义数组传入TodoMain.vue组件中;
2.v-for循环展示数据;
3.v-model绑定复选框选中状态;
4.根据选中状态 设置样式
<template>
<div class="todo">
<todo-head></todo-head>
<todo-main :arr="list"></todo-main>
<todo-foot></todo-foot>
</div>
</template>
<script>
import TodoFoot from "./components/TodoFoot.vue";
import TodoHead from "./components/TodoHead.vue";
import TodoMain from "./components/TodoMain.vue";
export default {
components: { TodoHead, TodoMain, TodoFoot },
data() {
return {
list: [
{ id: 100, name: "吃饭", ischeck: false },
{ id: 101, name: "睡觉", ischeck: false },
{ id: 102, name: "打游戏", ischeck: false },
],
};
},
};
</script>
<style scoped>
.todo {
width: 500px;
height: 500px;
border: 1px solid #333;
margin: 200px auto;
}
</style>
<template>
<div>
<div class="main">
<ul>
<li v-for="item in arr" :key="item.id">
<div class="left">
<input type="checkbox" v-model="item.ischeck" />
<span :class="{ underline: item.ischeck }">{{ item.name }}</span>
</div>
<button>删除</button>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ["arr"],
};
</script>
<style scoped>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 5px;
height: 50px;
}
.underline {
text-decoration-line: line-through;
}
</style>
添加任务
需求:输入任务回车,新增任务
1.TodoHead.vue 输入框 --键盘事件—回车;
2.子传父 把任务 —App.vue中 加入到数组中;
3.数组改变,所有用到数组的地方都会更新;
4.输入框为空,提示用户必须输入内容
//TodoHead.vue
<input type="text" v-model="name" @keyup.enter="addFn" />
methods: {
addFn() {
// 非空判断
if (this.name.trim().length === 0) {
alert('任务内容不能为空')
return
}
// 子传父
this.$emit('create', this.name)
this.name = ''
},
},
//App.vue
<todo-head @create="createFn"></todo-head>
methods: {
createFn(name) {
var id =
this.list.length === 0 ? 100 : this.list[this.list.length - 1].id + 1
this.list.push({
id: id,
name: name,
ischeck: false,
})
},
},
删除任务
.删除按钮–点击事件 传id;
子传父-把id传给App.vue 删除数组list里对应的对象
数组改变所有用到数组的地方都会更新