vue组件通讯办法也是面试热点问题,这个东西十分的重要,假如不明白通讯那项目就无法开展下去,今天咱们就来一起认识下vue组件的最基本的三种办法

  1. 父子组件通讯:父组件v-bind绑定特点用于传值,子组件props接纳
  2. 子父组件通讯:父组件订阅一个事情,子组件经过$emit发布该事情,且带着事情参数,让父组件的订阅生效
  3. 兄弟组件通讯: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因父组件的更新而改动,自然地向下流下组件……且看文档介绍

vue组件通讯【父子,子父,vuex】

子组件只能用props的值,不主张修正,由于数据流会变得很紊乱。改props能够行得通,可是父组件无法监听到,不是双向绑定

App.vue父组件绑定特点用于传值

绑定特点之前你需求将List子组件导入进来

导入一个组件的三个过程

导入一个组件有三个过程

  1. import路径引进
  2. components中声明
  3. 在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打造的,它是个库房,能够被任何一个组件运用

装置

vue组件通讯【父子,子父,vuex】

这儿咱们直接用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…

vue组件通讯【父子,子父,vuex】