组件通信
1.组件间通信props
-
props
属性子组件声明接收有三种写法props: ['msg'], // 数组写法,不严谨,不推荐使用 props: { msg: String, //对象简单写法,严谨度一般,不推荐使用 }, props: { msg: { // 对象复杂写法,推荐使用 type: String, default: '我是默认数据', }, },
-
props
用于父子之间传递函数数据,非函数数据,传递非函数数据是父给子传递,传递函数数据本质是子给父传递如果子组件向父组件传输数据,使用函数,利用调用函数参数模式把数据传递回来
-
props
的特殊用法,在router
(路由)中使用,属性值为true是则默认返回params参数,属性值为对象是,则返回这个对象的数据(没意义),属性为函数时则可以自定义返回值
2.自定义事件
要先知道什么是自定义事件,什么是
DOM
事件
-
原生Dom事件
事件类型 回调函数 谁调用 默认传递的实参是什么
- 事件类型 固定的那几个
- 回调函数,自己去定义的
- 谁掉了这个回调**(系统调用,浏览器调用)**
- 默认传递的参数是什么?
event
对象
-
自定义事件
事件类型 回调函数 谁调用 默认传递的实参是什么
- 事件类型无数个
- 回调函数,自己定义的
- 谁调用了这个回调**(自己调用)**
- 默认传递的参数是什么? 默认传递的是自己给的参数(有就有,没有就是
undefined
)
原生Dom事件绑在HTML标签上,如果绑在组件标签上,那么就是自定义事件,如果想绑在组件标签上还想用原生Dom事件,那么可以使用修饰符给native
<Event1 @click.native="test2"></Event1>
3.全局事件总线
适用于所有场合
什么玩意能当全局事件总线?
全局事件总线的角色标准
- 全局所有的地方都可以看到
- 必须有
$on
和$emit
方法
怎么添加事件总线
-
在
Vue
的圆形中添加方法(我们通常教bus)
他的值为自己也就是this
(我们的vm
)对象beforeCreate() { Vue.prototype.$bus = this//vm //在Vue的原型上添加了一个属性 $bus $bus指向了一个对象 这个对象就是我们vm对象 //1、为什么要在Vue原型上添加 //(让所有的组件对象都能看到它,找到它) // 组件对象原型的原型就是vm的原型 //2、事件总线对象必须能够使用$on和$emit,$on和$emit 两个是在Vue的原型当中 },
怎么使用事件总线
- 在要接收数据的组件中找到
bus
,在bus
身上添加一个事件,回调就留在这个组件中- 也就是说在哪里
$on
了,他的回调必定留在这里,当然他也是接收数据的地方
- 也就是说在哪里
- 在要发送的数据组件中找到
bus
,触发bus
身上添加的对应的事件,通过实参来传递数据- 也就是说在哪里
$emit
了,哪里必定是调用这个事件的地方,通过实参进行把数据传递回去
- 也就是说在哪里
4.v-model深入
html
input v-model
的本质:value = "data"
读取数据@input = "data = $event.target.value"
写数据
- 组件标签上的
v-model
本质:value = 'data'
父组件传递数据给子组件,子组件需要就收props
@input = "data=$event"
- 数据在父组件中
- 子组件中必须这样写
- 先接收
props:['value']
- 子组件表单类元素
:value='value'
@input = "$emit('input',$event.target.value)"'
- 先接收
- 干了两件事
- 显示数据
- 绑定修改数据的事件
- 在
html
和组件标签上绑定的@input
事件不同,一个是原生的一个是自定义的
- 实现了父子双向数据绑定(数据同步)
5..sync
修饰符
- 实现父子组件双向数据同步问题,和
v-model
实现效果几乎一样,只不过v-model
一般用域表单项组件sync
属性修饰符一般用于不带表单项的组件 - 父组件给子组件属性传递数据后门加
.sync
,子组件修改数据,需要分发事件,@click = $emit("update:属性名",要更新的数据)
- 本质上还是自定义事件
6.$attrs
和$listeners
-
本质就是父组件给子组件传递所有的属性组成对象及自定义事件方法组成的对象
-
$attrs
如果不声名props
那么子组件中可以看到,如果声明了哪个属性,那么哪个属性在$attrs
当中看不到,他会排除props
声明接受的属性 以及class stylethis.$attrs // 子组件中,可以获取传过来的所有没用props接收的属性
-
可以通过
v-bind
一次性把父组件传递过来的属性添加给子组件 -
可以通过
v-on
一次性把父组件传递过来的方法添加给子组件 -
二次封装
el-button
// 子组件 <template> <a href="javascript:;" :title="title"> <el-button v-bind="$attrs" v-on="$listeners"></el-button> // 一次性添加所有没接受的属性,以及绑定所有没有接受的事件 </a> </template> // 父组件 <HintButton type="primary" icon="el-icon-plus" size="mini" title="添加"></HintButton> <HintButton type="danger" icon="el-icon-delete" size="mini" title="删除"></HintButton>
-
我们发现如果有些棒的事件如果没法使用的话,我们可以强行改绑用
native
方法强行把自定义事件改成DOM事件,不过要注意,他绑定的是配置对象模板
中最大的标签 -
用
$attrs
获取全部属性,对象方法,用$listeners
获取所有绑定的自定义事件返回的是对象
7.$parent
和$children
以及$ref
-
$children
: 所有的组件对象的数组-
不准确(谁先谁后不一定)
//this.$children拿到的数组内部谁前谁后不确定
-
-
$parent
获取父组件对象-
相对于较准确,但也不常用,因为不一定几个
父组件
this.$parent.money += money //不要滥用 如果一个儿子多个爹,无法使用
-
-
$refs
获取指定组件的对象-
准确,拿到的就是指定的对象
this.$refs.son 拿的就是小明这个组件对象,子组件 this.$refs.son.money -= 100
-
-
如果想要获取子组件,并且指定子组件用
$refs
但是在组件处必须定义ref
,如果子组件想获取父组件的对象,用parent
,children
尽量不用,太不稳定,
8.作用域插槽
默认插槽和带名字的插槽(具名插槽)是父组件要给子组件传递的数据,带标签版本
-
必须要在子组件处留空也就是给他留一个
后门
,就比如router-view
// 子组件 <slot> // 给父组件留空 </slot>
-
默认插槽和具名插槽
- 具名插槽必须在子组件
slot
标签上添加name
属性,好和父组件对应
// 父组件 <template slot="yangmi"> // 跟slot标签的name对应 <button>按钮2</button> </template> // 子组件 <slot name="yangmi"> 我爱你杨幂 // 默认内容 </slot>
如果父组件传递数据了,那么就是父组件传递过来的数据,如果没有那么就是默认值
- 具名插槽必须在子组件
-
数据在子组件中去展示的,而子组件的数据结构则是父组件决定的,父子组件通信.数据可以符传递给子,让子去展示,子展示数据的时候也可以把组件传递给父,让父根据数据添加结构
// 子组件 <slot :todo="todo" :index="index"> // 把属性传递给父,让父进行判断 <!-- :todo="todo" 写在slot里面就不是props传递属性,而是子给父传递的数据(对象)当中的一个 --> {{ todo.text }} </slot> // 父组件 <List :todos="todos"> <template slot-scope="{todo,index}"> // 父组件接收传递过来的数据进行判断 <span :style="{color:index%2 === 0?'hotpink':'skyblue'}">{{index+1}} {{todo.text}}</span> </template> </List>
9.Vuex
如果有则直接创建文件如果没用 npm i vuex -S
-
配置
vuex
文件 -
创建一个
store
文件夹 里面放vuex
文件 -
进行
vuex
模块化管理一个功能一个子模块方便管理- 三步走
- 在
state
中定义共用数据state
只能存储数据
- 在
mutations
中修改共用数据mutations
中只能修改数据不可以进行逻辑判断或者异步请求
- 在
actions
中发送修改数据的结果actions
中可以进行逻辑判断或者异步请求,但是无法直接修改数据
- 在
// 引入请求的api import { reqBaseCategoryList } from '@/Api' // 第一步存储数据并初始化 const state = { categoryList: [] } // 第二步修改数据 const mutations = { REVISECATEGORYLIST(state, categoryList) { state.categoryList = categoryList } } // 第三步分发(提交)修改数据的结果 const actions = { async getCategoryList({ commit }) { const result = await reqBaseCategoryList() commit('REVISECATEGORYLIST', result.data) } } const getters = {} export default { state, mutations, actions, getters }
- 三步走