父组件给子组件传值
-
子组件中通过
props
接收父组件传递的数据 -
父组件给子组件通过属性传值
-
props
- 类型:
Array<string> | Object
- 类型:
-
Object
的选项配置type
default
:any
required
:Boolean
validator
:Function
,自定义验证函数会将该prop
的值作为唯一的参数代入
-
示例:
-
父组件
<template> <div> <child :title="msg" :age="age"></child> </div> </template> <script> import child from "./Child"; export default { components: { child, }, data() { return { msg: "我是父组件传递的title", age: 18, }; }, }; </script>
-
-
子组件
-
props
是数组<template> <div> <h2>title:{{ title }}</h2> <h2>age:{{ age }}</h2> </div> </template> <script> export default { props: ["title", "age"], }; </script>
-
props
是对象<template> <div> <h2>title:{{ title }}</h2> <h2>age:{{ age }}</h2> </div> </template> <script> export default { props: { title: String, age: { type: Number, default: 0, required: true, validator: function (value) { // 父组件传递的age小于0时会抛出警告: // Invalid prop: custom validator check failed for prop "age" return value >= 0; }, }, }, }; </script>
-
子组件给父组件传值
- 在子组件中使用
$emit
发布一个自定义事件$emit
参数:eventName:string
[...args]
- 在父组件中使用
v-on
或者@
监听这个自定义事件- 父组件在
html
中可以使用$event
获取传递的值
- 父组件在
- 示例
-
子组件
<template> <div> <h3>{{ Ccount }}</h3> <button @click="add">count++</button> </div> </template> <script> export default { props: { Ccount: Number, }, methods: { add() { this.$emit("addCount", this.Ccount); }, }, }; </script>
-
父组件
<template> <div> <h2>{{ count }}</h2> <!-- <child :Ccount="count" v-on:addCount="getCount"></child> --> <child :Ccount="count" @addCount="getCount"></child> <child :Ccount="count" @addCount="count = $event + 1"></child> </div> </template> <script> import child from "./02-Child"; export default { components: { child, }, data() { return { count: 1, }; }, methods: { getCount(data) { this.count = data + 1; }, }, }; </script>
-
不相关组件之间传值
- 在组件中创建公共
vue
实例作为事件中心- 使用
$emit
发布 - 使用
$on
订阅 - 示例:
-
公共
vue
实例作为事件中心import Vue from 'vue' export default new Vue()
-
发布组件
<template> <div> <h1>Event Bus Sibling01</h1> <div class="number" @click="sub">-</div> <input type="text" style="width: 30px; text-align: center" :value="value"> <div class="number" @click="add">+</div> </div> </template> <script> import bus from './eventbus' export default { props: { num: Number }, created () { this.value = this.num }, data () { return { value: -1 } }, methods: { sub () { if (this.value > 1) { this.value-- bus.$emit('numchange', this.value) } }, add () { this.value++ bus.$emit('numchange', this.value) } } } </script>
-
订阅组件
<template> <div> <h1>Event Bus Sibling02</h1> <div>{{ msg }}</div> </div> </template> <script> import bus from "./eventbus"; export default { data() { return { msg: "", }; }, created() { bus.$on("numchange", (value) => { this.msg = `您选择了${value}件商品`; }); }, }; </script>
-
- 使用
- 在
main.js
文件初始化vue
实例时设置事件中心-
main.js
文件new Vue({ render: h => h(App), data: { eventHub: new Vue() //使用集中事件处理器,在任何组件调用事件发射和事件接收 } }).$mount('#app')
-
发布组件
<template> <div> <h1>Event Bus Sibling01</h1> <div class="number" @click="sub">-</div> <input type="text" style="width: 30px; text-align: center" :value="value" /> <div class="number" @click="add">+</div> </div> </template> <script> export default { props: { num: Number, }, created() { this.value = this.num; }, data() { return { value: -1, }; }, methods: { sub() { if (this.value > 1) { this.value--; this.$root["eventHub"].$emit("numchange", this.value); } }, add() { this.value++; this.$root["eventHub"].$emit("numchange", this.value); }, }, }; </script>
-
订阅组件
<template> <div> <h1>Event Bus Sibling02</h1> <div>{{ msg }}</div> </div> </template> <script> export default { data() { return { msg: "", }; }, created() { this.$root["eventHub"].$on("numchange", (value) => { this.msg = `您选择了${value}件商品`; }); }, }; </script>
-
父直接访问子组件——不推荐
-
通过
ref
获取子组件 -
ref
有两个作用:- 如果你把它作用到普通
HTML
标签上,则获取到的是DOM
- 如果你把它作用到组件标签上,则获取到的是组件实例
- 如果你把它作用到普通
-
代码示例:
-
父组件:使用
this.$refs.c
直接访问子组件<template> <div> <h1>ref Parent</h1> {{ msg }} <child ref="c" @inputChange="getInputChange"></child> </div> </template> <script> import child from "./04-Child"; export default { components: { child, }, data() { return { msg: "hello input", }; }, mounted() { this.$refs.c.focus(); this.$refs.c.value = this.msg; }, methods: { getInputChange(val) { this.msg = val; }, }, }; </script>
-
子组件:
watch
监听input
值的变化,使用$emit
通知父组件<template> <div> <h1>ref Child</h1> <input ref="input" type="text" v-model="value" /> </div> </template> <script> export default { data() { return { value: "", }; }, watch: { value: function(val) { this.$emit("inputChange", val); }, }, methods: { focus() { this.$refs.input.focus(); }, }, }; </script>
-
vuex
-
什么是
Vuex
?-
Vuex
是专门为Vue.js
设计的状态管理库 -
Vuex
采用集中式的方式存储需要共享的数据 -
Vuex
的作用是进行状态管理,解决复杂组件通信,数据共享 -
Vuex
集成了devtools
,提供了time-travel
时光旅行历史回滚功能
-
-
什么情况下使用
Vuex
?-
非必要的情况不要使用
Vuex
-
大型的单页应用程序
-
多个视图依赖于同一个状态
-
来自不同视图的行为需要变更同一状态
-
-
Vuex的核心概念
vuex
的示例代码:
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
state: {
count: 0,
msg: 'Hello Vuex'
},
getters: {
reverseMsg (state) {
return state.msg.split('').reverse().join('')
}
},
mutations: {
increate (state, payload) {
state.count += payload
}
},
actions: {
increateAsync (context, payload) {
setTimeout(() => {
context.commit('increate', payload)
}, 2000)
}
},
modules: {
products,
cart
}
})
-
state
-
单一状态树,用一个对象就包含了全部的应用层级状态,也是响应式的
-
使用
mapState
简化state
在视图中的使用,mapState
返回计算属性 -
获取
state
的值-
使用
this.$store.state
获取,示例mounted() { console.log(this.$store.state.count); }
-
使用
mapState
获取state
的值,mapState
有两种使用的方式-
接收数组参数
// 该方法是 vuex 提供的,所以使用前要先导入 import { mapState } from 'vuex' computed: { // 不使用`modules` ...mapState(['count', 'msg']) // 使用`modules` ...mapState('module的名称',['count', 'msg']) },
-
接收对象参数,可以重命名返回的计算属性的名称
import { mapState } from 'vuex' computed: { // 不使用`modules` ...mapState({ num: 'count', message: 'msg' }) // 使用`modules` ...mapState('module的名称',{ num: 'count', message: 'msg' }) /*...mapState({ num: state => state.count, message: state => state.msg })*/ },
-
-
-
-
getter
-
getter
是store
中的计算属性 -
getter
的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算 -
getter
接受state
作为第一个参数 -
getter
也可以接受其他getter
作为第二个参数 -
使用
mapGetter
简化视图中的使用-
mapGetter
和mapState
的使用类似,可以接受数组参数,也可以接受对象参数 -
mapGetter
示例:import { mapGetter } from 'vuex' computed: { ...mapGetter(['reverseMsg']), // 重命名,在模板中使用 reverse ...mapGetter({ reverse: 'reverseMsg' }) }
-
-
-
mutation
-
Vuex
中的mutation
非常类似于事件: -
不要在
mutation
中执行异步修改 -
每个
mutation
都有一个字符串的事件类型(type)
和 一个回调函数(handler)
-
回调函数就是实际进行状态更改的地方
-
接受
state
作为第一个参数 -
载荷(
payload
)是第二个参数,是用户执行store.commit
的时候传入的额外参数
-
-
调用
mutation
:-
使用
commit
提交:this.$store.commit('increate',3)
-
使用
mapMutations
提交,示例:import { mapMutations } from 'vuex' methods: { // 把increate映射成this.$store.commit('increate',3) ...mapMutations(['increate']), // 重命名,在模板中使用 increateMut ...mapMutations({ increateMut: 'increate' }) }
-
-
-
action
-
在
action
中可以执行异步操作 -
修改
state
需要提交mutation
-
执行
action
:-
使用
dispatch
,例如:this.$store.dispatch('increateAsync', 5)
-
可以使用
mapActions
简化action
的调用,示例:import { mapActions } from 'vuex' methods: { // 把increateAsync映射成this.$store.dispatch('increateAsync', 5) ...mapActions(["increateAsync"]), // 重命名,在模板中使用 increateAction ...mapActions({ increateAction: 'increateAsync' }) },
-
-
-
module
-
Vuex
允许我们将store
分割成模块(module
)。每个模块拥有自己的state
、mutation
、action
、getter
-
module
示例:const moduleA = { state: () => ({ ... }), mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: () => ({ ... }), mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
-
-
插件
-
Vuex
的插件是一个函数,接收一个store
的参数 -
store.subscribe
:订阅每个store
中的mutation
,接收的回调函数会在每个mutation
完成之后调用 -
示例:
// 定义插件 const myPlugin = store => { // store.subscribe:订阅每个store中的mutation,接收的回调函数会在每个mutation完成之后调用 store.subscribe((mutation, state) => { // 每次mutation之后调用的操作 .... }) } // 使用插件 export default new Vuex.Store({ modules: { product, shoppingCart }, plugins: [myPlugin] })
-