props
父组件内,在子组件标签里边使用v-bind(简写为 : )绑定属性,在子组件内使用props接收数据.
props接收数据有三种形式
数组形式
props: ['count', 'userInfo', 'changeCount'],
对象形式
props: { count: Number, userInfo: Object, changeCount: Function },
配置对象形式
props:
{
count: { type: Number,
required: true, // 必填
default: 4 // 默认值
// required 和 default 是互斥的,如果必填还设置默认值没有意义 },
userInfo: { type: Object, default() { return { name: '老六', age: 22 } }
},
changeCount: { type: Function, required: true }
},
props传参分为函数类型和非函数类型
非函数类型
基本数据类型(数组形式): 子组件不能修改父组件传过来的数据
引用数据类型(对象形式): 子组件不能修改父组件传过来的引用数据类型地址,可以改里面的属性(但是不推荐,违反了单项数据流)
函数数据类型
传函数的目的是为了子组件调用修改父组件的数据
自定义事件
( @change----->$emit )
父组件 ( 使用v-on( 简写为@ ) 绑定事件 )
子组件 ( 使用$emit触发父组件绑定的事件 )
事件类型 - changeCount - 自定义事件是给组件绑定的,自己定义的,名字自己取,有无限个数
触发机制 - 自己触发的,参数需要自己传递,没有事件对象,使用$emit触发
$emit('changeCount', 9)
参数一:触发的事件类型 参数二: 传递的参数
自定义事件关于$event
函数不加小括号 - 触发的函数中的参数直接是 $emit 传过来的数据
函数加小括号 - 自定义事件是没有事件对象的,$event变成了子组件传过来的参数
原生事件
原生事件 1. 事件类型 - click - 在原生事件中,事件类型一定是有限个数 2. 触发机制 - 浏览器触发的,触发的时候会给函数传一个事件对象,事件对象是浏览器生成的 原生事件关于$event 函数不加小括号 - 默认系统触发原生事件的时候,第一个参数是 事件对象 函数加小括号 - 加小括号的时候,如果需要事件对象必须使用 $event (底层上是当前这个函数外部套了一层函数,套的这个函数形参是$event,我们用的就是这个形参)
安装总线
new Vue({
beforeCreate() {
Vue.prototype.$bus = this; // 安装总线
},
}
接收数据
在接收数据的组件中,绑定事件,留下回调,接收参数
Child2组件 - 接数据
mounted() {
this.$bus.$on('receiveParams', this.receiveParams)
},
methods: {
receiveParams(params) {
console.log('接收到的参数', params);
}
}
发送数据
在发送数据的组件中,触发事件,传递参数
在父组件的子组件标签中绑定
-----------------------------------------------------------------------------------------------
data() {
return {
keyword: "abc",
};
},
在子组件中绑定value和input事件,留下回调触发回调
----------------------------------------------------------------------------------------------
props: ['value'],
methods: {
changeValue(e) {
this.$emit('input', e.target.value);
}
}
条件: 必须实现
1. 绑定:value值
2.绑定@input事件
数据的流向:
\1. 通过:value把数据绑定给子组件
\2. 子组件中使用props接收父组件传过来的数据
\3. 修改数据,使用$emit触发自定义事件,把参数传递给父组件
\4. 父组件接收到数据之后,更新keyword的值
\5. keyword值更新之后,又重新通过:value传递给子组件
什么情况下会使用v-model?
封装组件的时候,组件中有表单元素的时候一般会使用v-model
多数用在表单元素上,双向数据绑定,用来收集表达数据
在哪见过?
在element ui 中的 el-input组件使用的就是 v-model
父组件中的子组件标签里使用( :msg(属性名).sync='' )绑定数据
----------------------------------------------------------------------------------------------------------
data() {
return {
string: "我爱你",
};
},
子组件使用原生事件绑定一个方法,方法内使用( this.$emit('update:msg', "666") )来触发 从而实现父子组件数据同步
-----------------------------------------------------------------------------------------------------------
props: ['msg'],
methods: {
changeParentMsg() {
this.$emit('update:msg', "666")
}
}
条件: 必须实现 1. :msg(属性名) 2. @update:msg
:msg="msg" 给子组件绑定数据,用于展示
@update:msg="changeMsg" 绑定自定义事件
这里 必须使用 @update:msg 冒号后面跟绑定的数据名称
这里的msg是v-bind绑定的属性
在哪见过?
在element UI中的对话框dialog中见过
使用场景(主要是却别v-model)
v-model 在封装表单元素的时候实现父子组件数据同步,经常使用v-model
.sync 在封装非表单元素的组件时候实现父子组件数据同步,经常使用.sync
数据的流向:
通过:msg把数据传给子组件
子组件修改数据,$emit 触发了事件把参数传给父组件,父组件修改数据
父组件更改msg,再通过 :msg 传给子组件
$attrs 可以接收到绑定在组件上的所有属性,除去props接收过的属性、style、class类名
$listeners 可以接收到所有绑定在组件上的事件
{{ content }}
对element ui 组件进行二次封装的时候,把element里面的每个属性往外一个一个暴露,很累
$attrs
$attrs 可以接收到绑定在组件上的所有属性,除去props接收过的属性、style、class类名
在使用的时候使用 v-bind="$attrs" 直接将这个对象绑定到组件上即可
注意: v-bind不能写成 :
$listeners
$listeners 可以接收到所有绑定在组件上的事件
在使用的时候使用 v-on="$listeners" 直接将这个对象绑定到组件上即可
注意: v-on 不能简写成 @
$refs 可以获取到组件实例,拿到组件实例可以拿到组件中的数据,在标签上使用的时候获取到的是标签
$children 当前组件的所有子组件,得到的是一个数组
$parent 获取当前组件的父组件
只有可以获取到当前的组件实例,就可以获取到数据,修改数据
注意: 这里不推荐使用 $parent, 为什么?
因为父组件不确定是谁
mixin 是混入
组件中有公共提取的时候就需要用到mixin
使用:
首先创建一个mixin.js的文件,
暴露一个对象,这个对象就是vue的配置对象( Vue组件中能配置什么,这里就能配置什么 )
mixin.js 文件 --------------------------------------------------------------------------------------------------------
export default {
data() {
return {
};
},
computed: {
},
mounted() {
console.log("mixin的挂载");
},
methods: {
},
};
然后在需要混入的组件当中 引入并配置 就OK了
import Mixin from './mixin'
export default {
mixins: [Mixin], // 混入的配置项
}
在mixin中配置的内容(内容包括但不限于数据,方法等),都可以混入到组件当中
如果在组件中有重复的内容,会发生覆盖,组件中的内容会覆盖混入的内容
注意:
钩子函数不会被覆盖,先执行mixin中的钩子,再执行组件中的钩子
使用方式类似于props
provide 理解成广播
inject 就是用来接数据的
注意: 广播只广播一次,当数据发生改变的时候,后代组件当中接收不到更新的信息(包含基本数据类型和引用数据类型的地址)
在使用引用数据类型的时候,对象中的属性发生改变,后代组件是可以接收到的
祖先组件-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
祖先组件
content1: {{ content1 }}
content2.name: {{ content2.name }}
子组件
子组件
孙组件---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
孙组件
祖先传过来的content1: {{ content1 }}
祖先传过来的content2.name {{ content2.name }}
使用场景: 多个组件依赖同一数据的时候使用 vuex,
例如说: 一般情况下用户信息会放在store中 (因为权限问题)
vuex使用步骤
安装 npm i vuex@3 -S
引入 并 暴露
创建 store.js 文件
import Vue from "vue";
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules //模块化
})
创建vm关联store
在 main.js 文件中
//暴露
import store from '@/store'
new Vue({
render: h => h(App),
store //关联
}).$mount('#app')
模块化
配置 modules 只要开启模块化,state中的数据就是加了一层,而mutations、actions、getters和之前的使用方式一样
state
$store.state.test.count //普通写法
...mapState({ // 辅助函数 - 往computed中映射
count: state => state.test.count
})
actions
$store.dispath('increment') //普通写法
//actions怎么写,mutaions就怎么写,只改一个地方dispath改成commit即可
...mapActions(['increment']) // 辅助函数 - 往methods中映射
getters
$store.getters.dblCount //普通写法
//辅助函数 - 往compouted中映射
...mapGetters(['dblCount'])
//命名空间
在store当中配置 namespaced: true //加了命名空间,每一个模块都是独立的
state和开启模块化的时候一样,mutations、actions、getters都多加了一层
state - 还是开启模块化的写法
actions
$store.dispatch('test/increment') //普通写法
...mapActions('test', ['increment']) //辅助函数
getters
$store.getters['test/dblCount'] //普通写法
...mapGetters('test', ['dblCount']) // 辅助函数
作用: 父子组件之间的通信,父给子传 html 和 css
插槽有三种
普通插槽、具名插槽、作用域插槽
父组件--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
组件间通信10: 插槽==> 作用域插槽
需求: 自定义TODO列表组件能实现下面需求
效果一: 显示TODO列表时, 已完成的TODO为绿色
父组件传的Header
父组件传的Footer
内容: {{ data.row.text }} -
是否完成: {{ data.row.isComplete ? '完成' : '未完成' }} -
msg: {{ data.msg }}
效果二: 显示TODO列表时, 带序号, TODO的颜色为蓝绿搭配
序号: {{ $index }} - 内容: {{ row.text }}
子组件---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
header
--------------------------------
-
内容
--------------------------------
footer
安装
npm i pubsub-js
接收数据,接收数据的组件,绑定事件(订阅消息),留下回调,接收参数
Pubsub.subscribe('changeMessage', this.changeMessage)
传递出局,传递数据的组件,触发事件(发布消息),传递参数
Pubsub.publish('changeMessage')
这里和总线唯一的区别在接收数据的函数中,参数一是消息类型
父组件------------------------------------------------------------------------------------------------------------------------------------------------------------------------
pubsub - 父组件
子组件1------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Child1 - 发数据
子组件2------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Child2 - 接数据