vue组件通讯办法也是面试热点问题,这个东西十分的重要,假如不明白通讯那项目就无法开展下去,今天咱们就来一起认识下vue组件的最基本的三种办法
- 父子组件通讯:父组件v-bind绑定特点用于传值,子组件props接纳
- 子父组件通讯:父组件订阅一个事情,子组件经过$emit发布该事情,且带着事情参数,让父组件的订阅生效
- 兄弟组件通讯:vuex
为了办法解说,咱们引进一个简略的栗子—-todolist
准备工作
利用cli脚手架创立一个项目
vue create component-communicate
// 后面的选项记住勾选vuex
咱们在App.vue中简略实现一个todolist(没写css,主讲原理
App.vue
<template>
<div>
<div class="head">
<input type="text" name="" v-model="message">
<button @click="submit">确认</button>
</div>
<div class="body">
<ul>
<li v-for="(item, index) in lists" :key="index">{{ item }}</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
lists: ['html', 'css'],
message: ''
}
},
methods: {
submit() {
// console.log(this.message);
if(this.message) {
this.lists.push(this.message);
this.message = ''
}
}
}
}
</script>
<style lang="css" scoped>
</style>
head输入框中的输入数据message需求给到list数组,体现在method中的办法
这儿我分别把head输入框和body列表分红两个组件,在App.vue中保存head,把body List分出去成为一个components组件,此刻App.vue就相当于父组件,body List相当于子组件,head向body List传值便是下面的父向子通讯。也便是说list这个数组需求传给子组件去展示。
一个小知识lintOnSave
这儿我想多用几个App.vue来举例,需求命名App1.vue、App2.vue的时分,项目或许会报错,咱们需求去vue.config.js这个配置文件去加一行代码
lintOnSave: false
由于cli脚手架对你组件的命名要求很严厉,将lintOnSave
的值改为false就可随意取名,配置改完需求将项目重启一下。你想运用哪个App.vue只需求去main.js中from中修正就能够
父向子组件通讯
父组件的list值传给子组件
父组件v-bind绑定特点用于传值,子组件props接纳
props其实便是一种数据源,data是正数据源,props是负数据源,props只承受父组件的东西
现在我把body List分出一个组件来写
List.vue子组件props接纳
props中list便是父组件传过来的值
<template>
<div class="body">
<ul>
<li v-for="(item, index) in lists" :key="index">{{ item }}</li>
</ul>
<button @click="changeProps">修正props</button>
</div>
</template>
<script>
export default {
props: ['lists'],
}
</script>
<style lang="css" scoped>
</style>
props单向数据流
props遵循着单向绑定原则,props因父组件的更新而改动,自然地向下流下组件……且看文档介绍
子组件只能用props的值,不主张修正,由于数据流会变得很紊乱。改props能够行得通,可是父组件无法监听到,不是双向绑定
App.vue父组件绑定特点用于传值
绑定特点之前你需求将List子组件导入进来
导入一个组件的三个过程
导入一个组件有三个过程
- import路径引进
- components中声明
- 在template中运用,这儿记住绑定特点
App.vue
<template>
<div>
<div class="head">
<input type="text" name="" v-model="message">
<button @click="submit">确认</button>
</div>
<List :lists="lists"/>
</div>
</template>
<script>
import List from '@/components/body1/List.vue'
export default {
components: {
List
},
data() {
return {
lists: ['html', 'js'],
message: ''
}
},
methods: {
submit() {
if(this.message) {
this.lists.push(this.message);
this.message = ''
}
}
}
}
</script>
<style lang="css" scoped>
</style>
子向父组件通讯
现在我将head头部独自别离成一个组件,也便是head中的message需求传给父组件来展示
App.vue父组件订阅一个事情
只要子组件发布了订阅,父组件就会触发该事情
留意:导入head的时分留意必定是大写的Head,不能写成小写的,会与html5的head标签冲突。
App.vue
<template>
<div>
<Head @add="handle"/>
<div class="body">
<ul>
<li v-for="(item, index) in lists" :key="index">{{ item }}</li>
</ul>
</div>
</div>
</template>
<script>
import Head from '@/components/body2/Head.vue'
export default {
components: {
Head
},
data() {
return {
lists: ['html', 'css']
}
},
methods: {
handle(val) {
this.lists.push(val)
}
}
}
</script>
<style lang="css" scoped>
</style>
handle触发的条件便是有了add,里面的参数val便是子组件传过来的message
Head.vue子组件经过$emit发布该事情,且带着参数
$emit两个参数分别为抛出来的事情和抛出来的参数
emit文档:组件实例 | Vue.js (vuejs.org)
Head.vue
<template>
<div class="head">
<input type="text" name="" v-model="message">
<button @click="submit">确认</button>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
submit() {
if(this.message){
this.$emit('add', this.message)
this.message = '';
}
}
}
}
</script>
<style lang="css" scoped>
</style>
兄弟组件通讯
已然父向子,子向父你会了,兄弟组件你就能够利用父做中间人,实现兄弟组件通讯
父做中间人
Head和List都别离出去,然后Head将message发布订阅,父组件接纳订阅以及参数,然后传给List子组件的props中,经过watch监听它的改动,改动之后改动数据源中的lists即可
Head.vue
<template>
<div class="head">
<input type="text" name="" v-model="message">
<button @click="submit">确认</button>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
submit() {
if(!this.message) return
this.$emit('add', this.message)
this.message = '';
}
}
}
</script>
<style lang="css" scoped>
</style>
List.vue
<template>
<div class="body">
<ul>
<li v-for="(item, index) in lists" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: ''
}
},
watch: {
msg(newVal){
this.lists.push(newVal)
}
},
data() {
return {
lists: ['html', 'js']
}
}
}
</script>
<style lang="css" scoped>
</style>
App.vue
<template>
<div>
<Head @add="handle"/>
<List :msg="msg"/>
</div>
</template>
<script>
import Head from '@/components/body3/Head.vue'
import List from '@/components/body3/List.vue'
export default {
components: {
Head,
List
},
data() {
return {
msg: ''
}
},
methods: {
handle(val) {
console.log(val)
this.msg = val
}
}
}
</script>
<style lang="css" scoped>
</style>
vuex
经过父组件做中间人来进行兄弟组件之间的传参是十分费事的,为什么这么说,一旦项目大了起来,就相当于一个二叉树,最外层两端的叶子组件,进行通讯,就会一直去找父组件,十分难过。因而vue作者尤雨溪又打造了一个vuex,它便是一个库房,供组件运用
vuex文档:开始 | Vuex (vuejs.org)。vue3对应vuex4
vuex是为optionsAPI打造的,它是个库房,能够被任何一个组件运用
装置
这儿咱们直接用npm装置就好,从这个指令能够看出--save
就阐明项目完成后还需求这个库房,便是运行的时分要用这个嘛,合乎逻辑!
假如你在用cli装置项目的时分,选中了vuex,他就会给你在src目录下生成一个store文件夹,里面会有个index.js文件,跟路由的形式很像。
src/store/index.js
import { createStore } from 'vuex' // 从vuex中引进一个createStore
const store = createStore({
// data
state() {
return {
lists: ['html', 'css', 'js']
}
},
// methods
mutations: {
listsAdd(state, val) {
// 修正库房的数据源
state.lists.push(val)
}
}
})
export default store
state是库房的数据源data,所以List.vue中就不需求自己再弄个数据源了,直接用库房的数据即可,而库房的数据源又来自Head.vue
mutations是库房的methods,给一个修正数据源的办法,这儿留意,mutations的办法不能用this,而且mutations里面的办法必定会有个形参,就代表数据源,第二个参数是人为传进的,这儿便是传进的输入框信息
记住在main.js中引进再use掉,简直跟路由如出一辙的
import store from './store'
createApp(App).use(store).mount('#app')
此刻的App.vue写法只需如下
App.vue
<template>
<div>
<Head @add="handle"/>
<List :msg="msg"/>
</div>
</template>
<script>
import Head from '@/components/body4/Head.vue'
import List from '@/components/body4/List.vue'
export default {
components: {
Head,
List
}
}
</script>
<style lang="css" scoped>
</style>
此刻的List.vue写法如下
List.vue
<template>
<div class="body">
<ul>
<li v-for="(item, index) in lists" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: mapState(['lists']) // mapState会返回lists
}
</script>
<style lang="css" scoped>
</style>
import { mapState } from 'vuex'
便是引进库房的数据源
mapState
函数中的参数便是你想要从库房取出的数据源,而且给你返回出来给到核算特点computed
此刻的Head.vue写法如下
Head.vue
<template>
<div class="head">
<input type="text" name="" v-model="message">
<button @click="submit">确认</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
methods: {
submit() {
if(!this.message) return
this.listsAdd(this.message)
},
...mapMutations(['listsAdd'])
}
}
</script>
<style lang="css" scoped>
</style>
这儿不是从库房拿到数据源再push,库房的数据源只能库房的办法来动,所以咱们组件拿到库房的办法listAdd就好
import { mapMutations } from 'vuex'
便是引进库房的办法
...mapMutations(['listsAdd'])
解构listAdd函数的运用,为何解构?由于mutations的办法或许会有很多个,办法有了,现在搬到submit中去调用它
以上办法,不算“父做中间人”有三种,这三种办法是最基本的,组件通讯有7,8种办法,不过你会这三种就足够你开发了
别的有不明白之处欢迎在谈论区留言,假如觉得文章对你学习有所帮助,还请”点赞+谈论+保藏“一键三连,感谢支持!
本次学习代码已上传至自己GitHub学习库房:github.com/DolphinFeng…