五、什么是props
1.Props 定义
组件上 注册的一些 自定义属性
2.Props 作用
向子组件传递数据
3.特点
- 可以 传递 任意数量 的prop
- 可以 传递 任意类型 的prop
4.代码演示
父组件App.vue
<template> <div class="app"> <UserInfo :username="username" :age="age" :isSingle="isSingle" :car="car" :hobby="hobby" ></UserInfo> </div> </template> <script> import UserInfo from './components/UserInfo.vue' export default { data() { return { username: '小帅', age: 28, isSingle: true, car: { brand: '宝马', }, hobby: ['篮球', '足球', '羽毛球'], } }, components: { UserInfo, }, } </script> <style> </style> 子组件UserInfo.vue <template> <div class="userinfo"> <h3>我是个人信息组件</h3> <div>姓名:</div> <div>年龄:</div> <div>是否单身:</div> <div>座驾:</div> <div>兴趣爱好:</div> </div> </template> <script> export default { }
六、props校验
1.思考
组件的props可以乱传吗
2.作用
为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误
3.语法
- 类型校验
- 非空校验
- 默认值
- 自定义校验
4.代码演示
<template> <div class="app"> <BaseProgress :w="width"></BaseProgress> </div> </template> <script> import BaseProgress from './components/BaseProgress.vue' export default { data() { return { width: 30, } }, components: { BaseProgress, }, } </script> <style> </style> BaseProgress.vue <template> <div class="base-progress"> <div class="inner" :style="{ width: w + '%' }"> <span>{{ w }}%</span> </div> </div> </template> <script> export default { props: ['w'], } </script> <style scoped>
七、props校验完整写法
1.语法
props: { 校验的属性名: { type: 类型, // Number String Boolean ... required: true, // 是否必填 default: 默认值, // 默认值 validator (value) { // 自定义校验逻辑 return 是否通过校验 } } },
2.代码实例
<script> export default { // 完整写法(类型、默认值、非空、自定义校验) props: { w: { type: Number, //required: true, default: 0, validator(val) { // console.log(val) if (val >= 100 || val <= 0) { console.error('传入的范围必须是0-100之间') return false } else { return true
3.注意
1.default和required一般不同时写(因为当时必填项时,肯定是有值的)
2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值
八、props&data、单向数据流
1.共同点
都可以给组件提供数据
2.区别
- data 的数据是自己的 → 随便改
- prop 的数据是外部的 → 不能直接改,要遵循 单向数据流
3.单向数据流:
父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的
4.代码演示
App.vue <template> <div class="app"> <BaseCount></BaseCount> </div> </template> <script> import BaseCount from './components/BaseCount.vue' export default { components:{ BaseCount }, data(){ }, } </script> <style> </style> BaseCount.vue <template> <div class="base-count"> <button @click="count--">-</button> <span>{{ count }}</span> <button @click="count++">+</button> </div> </template> <script> export default { // 1.自己的数据随便修改 (谁的数据 谁负责) data () { return { count: 100, }
5.口诀
谁的数据谁负责
九、综合案例-组件拆分
1.需求说明
- 拆分基础组件
- 渲染待办任务
- 添加任务
- 删除任务
- 底部合计 和 清空功能
- 持久化存储
2.拆分基础组件
咱们可以把小黑记事本原有的结构拆成三部分内容:头部(TodoHeader)、列表(TodoMain)、底部(TodoFooter)
十、综合案例-列表渲染
思路分析:
- 提供数据:提供在公共的父组件 App.vue
- 通过父传子,将数据传递给TodoMain
- 利用v-for进行渲染
十一、综合案例-添加功能
思路分析:
- 收集表单数据 v-model
- 监听时间 (回车+点击 都要进行添加)
- 子传父,将任务名称传递给父组件App.vue
- 父组件接受到数据后 进行添加 unshift(自己的数据自己负责)
十二、综合案例-删除功能
思路分析:
- 监听时间(监听删除的点击)携带id
- 子传父,将删除的id传递给父组件App.vue
- 进行删除 filter (自己的数据自己负责)
十三、综合案例-底部功能及持久化存储
思路分析:
- 底部合计:父组件传递list到底部组件 —>展示合计
- 清空功能:监听事件 —> 子组件通知父组件 —>父组件清空
- 持久化存储:watch监听数据变化,持久化到本地
十四、非父子通信-event bus 事件总线
1.作用
非父子组件之间,进行简易消息传递。(复杂场景→ Vuex)
2.步骤
- 创建一个都能访问的事件总线 (空Vue实例)
import Vue from 'vue'
const Bus = new Vue()
export default Bus
- A组件(接受方),监听Bus的 $on事件
created () {
Bus.$on('sendMsg', (msg) => {
this.msg = msg
})
}
B组件(发送方),触发Bus的$emit事件
Bus.$emit('sendMsg', '这是一个消息')
3.代码示例
EventBus.js import Vue from 'vue' const Bus = new Vue() export default Bus BaseA.vue(接受方) <template> <div class="base-a"> 我是A组件(接收方) <p>{{msg}}</p> </div> </template> <script> import Bus from '../utils/EventBus' export default { data() { return { msg: '', } }, } </script> <style scoped> .base-a { width: 200px; height: 200px; border: 3px solid #000; border-radius: 3px; margin: 10px; } </style> BaseB.vue(发送方) <template> <div class="base-b"> <div>我是B组件(发布方)</div> <button>发送消息</button> </div> </template> <script> import Bus from '../utils/EventBus' export default { } </script> <style scoped> .base-b { width: 200px; height: 200px; border: 3px solid #000; border-radius: 3px; margin: 10px; } </style> App.vue <template> <div class="app"> <BaseA></BaseA> <BaseB></BaseB> </div> </template> <script> import BaseA from './components/BaseA.vue' import BaseB from './components/BaseB.vue' export default { components:{ BaseA, BaseB }
4.总结
1.非父子组件传值借助什么?
2.什么是事件总线
3.发送方应该调用事件总线的哪个方法
4.接收方应该调用事件总线的哪个方法
5.一个组件发送数据,可不可以被多个组件接收