目录
1. props 和 $emit
1. 父传子—props
通过props
(可以在组件上注册一些自定义的属性),向子组件传递数据
父组件
<template>
<div class="home">
<HelloWorld :parentMessage="message"/>
</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue"
export default{
data() {
return {
message: "我是父组件传过来的数据"
}
},
components: {
HelloWorld
}
</script>
子组件
子组件通过props
接收数据
<template>
<div class="hello">
<p>{{parentMessage}}</p>
</div>
</template>
<script>
export default {
// 字符串数组
// props: ["parentMessage"],
// 对象(数据验证,类型验证)
props: {
parentMessage: {
type: String, // 类型验证
default: "" // 默认值
}
},
data() {
return {
}
}
}
</script>
2. 子传父—$emit 自定义事件
- 通过自定义事件向父组件传递数据。
- 自定义事件的流程:
-
在子组件中,通过
$emit
来触发事件,传递数据; -
在父组件中,通过
v-on
去监听子组件的事件,获取传递过来的数据。 -
父组件通过
$off
来解绑自定义事件。this.$off('自定义事件名') // 解绑一个自定义事件 this.$off(['自定义事件名1', '自定义事件名2']) // 解绑多个自定义事件 this.$off() //解绑所有的自定义事件
-
子组件
<template>
<div class="hello">
<p>{{parentMessage}}</p>
<button @click="sendChildren">点击给父组件传递数据</button>
</div>
</template>
<script>
export default {
// 子组件通过props接收数据
// 字符串数组
// props: ["parentMessage"],
// 对象(数据验证,类型验证)
props: {
parentMessage: {
type: String, // 类型验证
default: "" // 默认值
}
},
data() {
return {
age: 18
}
},
methods: {
sendChildren: function() {
// 第一个参数:自定义事件名,第二个参数:传递的数据
this.$emit("parentMessage", this.age)
}
}
}
</script>
父组件
<template>
<div class="home">
<HelloWorld :parentMessage="message" @parentMessage="injectParent"/>
</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue"
export default{
data() {
return {
message: "我是父组件传过来的数据"
}
},
components: {
HelloWorld
},
methods: {
injectParent: function(value) {
// value是自定义组件传过来的数据
console.log(value)
}
}
</script>
2. $parent 和 $children
-
通过
$parent
获取父组件的数据<template> <div class="home"> <button @click="getParent">获取子组件的数据</button> </div> </teaplate> <script> export default { data() { return { age: 20 } }, methods: { getParent: function{ console.log(this.$parent.message) // 打印message的值 } }, </script>
-
通过
$children
访问子组件的数据,this.$children
是一个数组类型,包含所有的子组件对象(开发中比较少用)<template> <div class="home"> <Helloworld/> <Helloworld/> <Helloworld/> <button @click="getchildren">获取子组件的数据</button> </div> </teaplate> <script> export default { data() { return { message: "我是父组件的数据" } }, methods: { getchildren: function{ console.log(this.$children[0].age) } }, components: { Helloworld } </script>
3. $refs
通过$refs
和ref
一起使用访问子组件的数据(开发中常用)
<template>
<div class="home">
<Helloworld/>
<Helloworld ref="two"/>
<Helloworld/>
<button @click="getchildren">获取子组件的数据</button>
</div>
</teaplate>
<script>
export default {
data() {
return {
message: "我是父组件的数据"
}
},
methods: {
getchildren: function{
console.log(this.$refs.two.age)
}
},
components: {
Helloworld
}
</script>
4. provide 和 inject
父子之间的通信,跨级通信。provide/inject
-
provide
(提供):是一个对象或者一个返回对象的函数。<template> <div class="home"> <Parent/> <hr/> <h2>祖先组件</h2> <p>{{grandPa.message}}</p> <p>{{age}}</p> <button @click="changeMessage">改变message数据</button> </div> </template> <script> import Parent from "@/components/Parent.vue" export default { data() { return { // message: "我是祖先组件的数据", // 没有响应 grandPa: { message: "我是祖先组件的数据" }, age: 18 } }, provide() { return { // message: this.message grandPa: this.gandPa, // 传入可响应的对象 age: ()=>this.age // 通过计算属性计算注入的值 } }, methods: { changeMessage: function() { this.grandPa.message = "我是更改后的数据" this.age = 20 } } components: { Parent } } </script>
-
inject
(注入):可以是一个字符串的数组,也可以是一个对象。在需要使用的地方注入<template> <div class="hello"> <h2>孙子组件</h2> <!--<p>{{message}}</p>--> <p>{{grandPa.message}}</p> <p>{{newAge}}</p> </div> </template> <script> export default { data() { return {} }, // inject: ['message'], inject: ['grandPa', 'age'], computed: { newAge: function() { return this.age() } } } </script>
-
provide
和inject
绑定不是响应的。 -
provide
和inject
实现响应的方法:- 传入可响应的对象。
- 通过计算属性计算注入的值。
5. vuex
1. vuex的基本使用
1. 安装vuex依赖包
npm install vuex@3 --save
目前vue3是默认的环境,所以下载vuex的时候也是默认下载vuex的版本4,而vue2使用的是vuex的版本3,所以在vue2中安装vuex的时候,下载语法是 vuex@3
2. 导入vuex包
import Vue from 'vue'
import Vuex from 'vuex'
// 使用vuex
Vue.use(Vuex)
3. 创建store对象
const store = new Vuex.Store({
// state 存放所有的全局共享的数据
state: {
count: 0
},
mutations: {
},
actions: {
}
})
export default store
4. 将store对象挂载到vue实例中
import store from './store'
new Vue({
// 将创建的共享数据对象,挂载到vue实例中
// 所有的组件,就可以直接从store中获取全局的数据了
store,
render: h => h(App)
}).$mount('#app')
2. Vuex的核心概念
Vuex中的主要核心概念如下:
- State
- Mutation
- Action
- Getter
1. State
State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储。
const store = new Vuex.Store({
// 存储所有的共享数据
state: {
count: 0
},
})
组件访问State中数据的第一种方式:
this.$store.state.全局数据名称
组件访问State中数据的第二种方式:
// 1. 从vuex中按需导入mapState函数
import { mapState } from 'vuex'
通过导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性:
// 2. 将全局数据,映射为当前组件的计算属性
computed: {
...mapState(['count'])
}
2. Mutation
Mutation用于变更Store中的数据
- 只能通过mutation变更Store数据,不可以直接操作Store中的数据。
- 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
触发mutation的第一种方式:
const store = new Vuex.Store({
// 存储所有的共享数据
state: {
count: 0
},
// 定义Mutation
mutations: {
add(state) {
// 变更状态
state.count++
},
}
})
methods: {
handle() {
// 触发mutation的第一种方式
this.$store.commit('add')
}
}
可以在触发mutations时传递参数:
const store = new Vuex.Store({
// 存储所有的共享数据
state: {
count: 0
},
// 定义Mutation
mutations: {
add(state) {
// 变更状态
state.count++
},
addN(state, step) {
state.count += step
}
}
})
methods: {
handle1() {
// commit 的作用,就是为了调用某个mutations 的函数
// 触发mutation的第一种方式
this.$store.commit('add')
},
handle2() {
// 触发mutations时携带参数
this.$store.commit('addN', 3)
}
}
this.$store.commit()是触发mutations的第一种方式,触发mutations的第二种方式:
// 1. 从vuex中按需导入mapMutations函数
import { mapMutations } from 'vuex'
通过刚才导入的mapMutations 函数,将需要的 mutations函数,映射为当前组件的 methods方法:
methods: {
// 2. 将指定的mutations函数,映射为当前组件的methods函数
...mapMutations(['sub', 'subN'])
}
Mutation中不能执行异步操作
3. Action
Action用于处理异步任务。
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。
const store = new Vuex.Store({
// 存储所有的共享数据
state: {
count: 0
},
// 定义Mutation
mutations: {
add(state) {
// 变更状态
state.count++
},
addN(state, step) {
state.count += step
},
sub(state) {
state.count--
},
subN(state, step) {
state.count -= step
}
},
// 负责实现异步的操作,不能直接修改state中的数据,
// 需要通过commit调用mutation中的函数来修改state中的数据
actions: {
addAsync(context) {
// context相当于store
setTimeout(() => {
context.commit('add')
}, 1000)
}
}
})
methods: {
handle1() {
// commit 的作用,就是为了调用某个mutations 的函数
// 触发mutation的第一种方式
this.$store.commit('add')
},
handle2(step) {
this.$store.commit('addN', step)
},
handle3() {
// dispatch 的作用,就是为了调用某个actions 的函数
// 触发action的第一种方式
this.$store.dispatch('addAsync')
}
}
触发actions异步任务时携带参数:
actions: {
addAsync(context) {
// context相当于store
setTimeout(() => {
context.commit('add')
}, 1000)
},
addNAsync(context, step) {
setTimeout(() => {
context.commit('addN', step)
}, 1000)
}
}
handle4(step) {
// 触发actions时携带参数
this.$store.dispatch('addNAsync', step)
}
this.$store.dispatch()是触发actions的第一种方式,触发actions的第二种方式:
// 1. 从vuex中按需导入mapActions函数
import { mapActions } from 'vuex'
通过刚才导入的mapActions 函数,将需要的 Actions函数,映射为当前组件的 methods方法:
methods: {
// 2. 将指定的actions函数,映射为当前组件的methods函数
...mapActions(['subAsync'])
}
4. Getter
Getter用于对Store中的数据进行加工处理形成新的数据。
- Getter可以对Store 中已有的数据加工处理之后形成新的数据,类似Vue的计算属性。
- Store 中数据发生变化,Getter的数据也会跟着变化。
const store = new Vuex.Store({
// 存储所有的共享数据
state: {
count: 0
},
getters: {
showNum(state) {
return '当前数量为' + state.count
}
},
})
使用getters的第一种方法
this.$store.getters.名称
使用getters的第二种方法
// // 1. 从vuex中按需导入mapGetters函数
import { mapGetters } from 'vuex'
// 2. 将全局数据,映射为当前组件的计算属性
computed: {
...mapGetters(['showNum'])
},
6. eventBus
-
主要通过
Vue.$emit
和Vue.$on
来实现兄弟组件之间的传值 -
实现步骤
- 创建 eventBus.js 文件,导出Vue实例。
- 发送数据组件调用
eventBus.$emit("事件名", 传递的数据)
来触发事件。 - 接收数据组件调用
eventBus.$on("事件名", 回调函数)
来绑定事件。
注意:发送数据组件触发的事件名与接收数据组件绑定的事件名相同。
-
代码
-
发送方
<template> <div> <h1>this is brother send</h1> <button @click="send">向接收方发送消息</button> <hr> <brother-receive></brother-receive> </div> </template> <script> import eventBus from './eventBus' export default { data() { return { message: '我是发送方的消息' } }, methods: { send () { eventBus.$emit("sendMessage", this.message) } }, components: { brotherReceive: () => import("./brotherReceive.vue") } } </script>
-
接收方
<template> <div> <h1>this is brother receive</h1> <p>{{receiveMessage}}</p> </div> </template> <script> import eventBus from './eventBus' export default { data() { return { receiveMessage: '' } }, created() { eventBus.$on("sendMessage", e => { this.receiveMessage = e }) } } </script>
-
7. $attrs 和 $listeners
-
概念
-
$attrs
当父组件传数据给子组件的时候,如果子组件的props没有进行接收,那数据就会被收集到子组件的
$attrs
里面,在子组件上使用v-bind="$attrs"
可以直接将值传给当前组件的子组件(也就是孙组件) -
$listeners
包含了父作用域中的(不含
.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners”
传入内部组件――在创建更高层次的组件时非常有用。
包括组件
props
和emit property
中未包含的所有属性。即除了组件内props
已经声明了的所有给组件传的值。 -
-
使用场景
当需要给多层嵌套父子组件传值时,可以使用这个。
-
实现
父组件
parent.vue
<template> <div> <h1>this is parent</h1> <p>父组件中将要传给子组件的数据</p> <b>a: {{a}}</b> <br> <b>b: {{b}}</b> <br> <b>c: {{c}}</b> <br> <b>接收到的数据:{{message}}</b> <hr> <son :a="a" :b="b" :c="c" @funGrandson="fun1"></son> </div> </template> <script> export default { data() { return { a: 'aaaaa', b: 'bbbbb', c: 'ccccc', message: '' } }, components: { son: () => import('./son.vue') }, methods: { fun1(e) { this.message = e } }, } </script>
子组件
son.vue
<template> <div> <h1>this is son</h1> <p>父组件传给子组件,并被子组件通过props接收的数据</p> <b>a: {{a}}</b> <hr> <grandson v-bind="$attrs" v-on="$listeners"></grandson> </div> </template> <script> export default { data() { return {} }, created() { console.log(this.$attrs) // {b: 'bbbbb', c: 'ccccc'} console.log(this.$listeners) // {funGrandson: f} }, props: { a: { type: String, default: '' } }, components: { grandson: () => import('./grandson.vue') } } </script>
孙子组件
grandson.vue
<template> <div> <h1>this is grandson</h1> <p>子组件通过<b>$attrs</b>将剩余未接收的数据传给孙子组件</p> <b>b: {{b}}</b> <br> <b>c: {{c}}</b> <br> <button @click="funGrandson">孙子组件发送数据</button> </div> </template> <script> export default { data() { return { b: '', c: '' } }, created() { console.log(this.$attrs) // {b: 'bbbbb', c: 'ccccc'} this.b = this.$attrs.b this.c = this.$attrs.c }, methods: { funGrandson() { this.$emit("funGrandson", "孙子组件") } }, } </script>