vue的八种组件通信方式

组件之间的通信主要分为:

  • 父子组件之间通信
  • 非父子组件之间的通信(兄弟组件、隔代关系组件等)
八种通信方式
1. props 、$emit
2. c h i l d r e n 、 children 、 childrenparent
3. ref
4. provide 、reject
5. Vuex
6. $attrs 与listenters
7. eventBus
8. localStorage 、sessionStorage

props

详情: 用来接收来自父组件的数据,props可以是简单的数组或对象。
如果只是父子关系的组件数据交互,那么应该考虑使用props进行单向传递

基于对象的语法:

type: 可以是String、Number、Boolean、Array、Object、Date、Function、Symbol任何自定义构造函数、或上述内容组成的数组。
子组件会检查父组件传递过来的数据是否是给定的类型,否则抛出警告。

default:any: 默认情况,如果prop没有被传入,则为该prop指定一个默认值,对象或数组的默认值必须从一个工厂函数返回。
required:Boolean:在非生产环境中,如果prop没有传入,则控制台会抛出警告。

举个栗子:

父组件test.vue

<template>
  <div class="hello">
      <HelloWorld :date="date"></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
      date:new Date()
    }
  },
  components:{
      HelloWorld
  }
}
</script>

子组件 HelloWorld.vue

<template>
  <div class="hello">
   {{date}}
  </div>
</template>

<script>
export default {
  props:['date'],
  data () {
    return {
    }
  }
}
</script>

如下图:
在这里插入图片描述


$emit:

作用:子组件给父组件传递参数或者触发父组件上定义的方法
如果涉及到子组件向父组件的数据传递,那么应该考虑使用 $emit 和 $on;

举个栗子:

父组件test.vue

<template>
  <div class="hello">
      <HelloWorld :date="date" v-on:childToSayHello="sayHello"></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
      date:new Date()
    }
  },
  components:{
      HelloWorld,
  },
  methods: {
      sayHello(name){
          console.log('hello world!');
          console.log(name);
      }
  },
}
</script>


子组件 HelloWorld.vue

<template>
  <div class="hello">
   <button @click="toSayHello">sayHello</button>
  </div>
</template>

<script>
export default {
  props:['date'],
  data () {
    return {
    }
  },
  methods: {
    toSayHello(){
    this.$emit('childToSayHello','liming');
    }
  }
}
</script>

如下图:
在这里插入图片描述


$children 和 $parent:

详情:

指定已创建的实例,在两者之间建立父子关系,子实例可以用this.$parent访问父实例,

子实例被推入父实例的$children数组中。

$children特点:

  • 并不保证顺序,也不是响应式的。

建议: 节制地使用 $parent和$children,它们主要的目的是作为访问组件的应急方
法。更推荐用props和events实现父子组件通信。

举个栗子:
父组件test.vue

<template>
  <div class="hello">
      <HelloWorld></HelloWorld>
     index: {{index}}
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
      number: 100,
      index: '',
    }
  },
  components:{
      HelloWorld,
  },
  methods: {
  },
  mounted() {
    this.index = this.$children[0].count;
  },
}
</script>

子组件 HelloWorld.vue

<template>
  <div class="hello">
      msg:  {{msg}}
  </div>
</template>

<script>
export default {
  data () {
    return {
      msg:'',
      count: 99
    }
  },
  methods: {
  },
  mounted () {
    this.msg = this.$parent.number
  }
}
</script>

如下图:
在这里插入图片描述


ref

作用:为子组件赋予一个ID引用,父组件用来访问子组件实例或子元素。

举个栗子:

父组件test.vue

<template>
  <div class="hello">
      <HelloWorld ref="child"></HelloWorld>
       count:{{count}}
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
        count:''
    }
  },
  components:{
      HelloWorld,
  },
  methods: {
  },
  mounted() {
      this.count = this.$refs.child.count;
      this.$refs.child.sayHello();
  },
}
</script>


子组件 HelloWorld.vue

<template>
  <div class="hello">
    hello
  </div>
</template>

<script>
export default {
  data () {
    return {
      count: 99
    }
  },
  methods: {
      sayHello(){
        console.log('hello world!');
      }
  },
  mounted () {

  }
}
</script>

如下图:
在这里插入图片描述


provide 、reject
  • provide: 选项是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。
  • inject:一个字符串数组或一个对象,value是在可用的注入内容
    中搜索的key。

举个栗子:

父组件test.vue

<template>
  <div class="hello">
      <HelloWorld ></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
    }
  },
  provide:{
       str_1:'67',
       str: 'hello'
  },
  components:{
      HelloWorld,
  },
  methods: {
  },
  mounted() {

  },
}
</script>


子组件 HelloWorld.vue

<template>
  <div class="hello">
    {{str}}
  </div>
</template>

<script>
export default {
  // 如果有可选的值
  inject:{
      str: {
      from: 'str_1',
      default: 'str'
    }
  },
  // 直接取值
  // inject:['str'],
  data () {
    return {
    }
  },
  methods: {
  },
  mounted () {

  }
}
</script>

如下图:
在这里插入图片描述


Vuex

使用Vuex来进行数据管理,如果仅仅是传递数据,而不做中间处理,使用Vuex处理就有些大材小用。
特点:
存储的数据是响应式的,但是不会保存起来,刷新页面后又会恢复初始状态
main.js

import store from './store/index'
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

test.vue

<template>
  <div class="hello">
       <button @click="open">{{this.$store.state.app.flat?'关闭':'打开'}}</button>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
      flat:''
    }
  },
  provide:{

  },
  components:{
      HelloWorld,
  },
  methods: {
    sayHello(){
          console.log('hello');
      },
    open(){
       this.$store.commit('open');
       console.log(this.$store.state)
      },
  },
  mounted() {
  },
}
</script>


同级目录下store文件夹
index.js

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,
  },
  getters
})

export default store

getters.js

const getters = {
    GET_FLAT: state => state.app.flat,
}
export default getters

state的状态不能直接修改,需要通过commit来实现
其中核心概念:

  • state:页面状态管理容器对象
  • commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
  • mutations:存改变状态的操作方法
  • getters:读取state中的数据

store/modules/app.js

const app = {
    state: {
        flat: false,
    },
    mutations: {
         open (state) {
             if(state.flat){
                state.flat = false;

             }else {
                state.flat = true;

             }
          },

    }
}

export default app

如下图:
目录结构:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


$attrs 与listenters

假设有这样的场景,A组件调用了B组件,B组件调用了C组件,C组件想要调用A组件中的数据。那么可以通过B这个中间件进行数据传递。仅是A-B-C,我们可以使用props来传递,那如果是A-B-C-D-E-F甚至更多层的数据传递呢?就要不停的props,重复写很多代码,这时候可以使用$attrs 与listenters来解决

举个栗子(test是Helloworld的父组件,HelloWorld是demo的父组件)

父组件test.vue

<template>
  <div class="hello">
      <HelloWorld v-bind="$attrs"  age='18'></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
export default {
  data () {
    return {
    }
  },
  components:{
      HelloWorld,
  },
  methods: {
  },
  mounted() {
  },
}
</script>


子组件 HelloWorld.vue

<template>
  <div class="hello">
       我是HelloWorld组件
       <Demo v-bind="$attrs"></Demo>
  </div>
</template>

<script>
import Demo from './demo';
export default {
  data () {
    return {
    }
  },
  methods: {
  },
  mounted () {
      console.log(this.$attrs);//{age:"18"}  
  },
  components:{
    Demo
  }
}
</script>

子组件 Demo.vue

<template>
    <div>
        我是demo
    </div>
</template>
<script>
export default {
    mounted () {
      console.log(this.$attrs);   //{age:"18"}     
    }
}
</script>

如下图:
在这里插入图片描述
原谅我没找到更好的解释listenters的教程


eventBus

事件总线
找不到很好的解释来说明这个 =_=!!!

举个栗子:
test.vue

<template>
  <div class="hello">
    <HelloWorld></HelloWorld>
    <button @click="handleClick">确定</button>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld'
import {EventBus} from '../components/js/event'
export default {
  data () {
    return {
      num:0
    }
  },
  provide:{

  },
  components:{
      HelloWorld,
  },
  methods: {
    handleClick(){
      EventBus.$emit('add',{
        num:this.num++
      });
    }
  },
  mounted() {
  },
}
</script>

Helloworld.vue

我是HelloWorld组件 count: {{count}}

如下图:
在这里插入图片描述


localStorage 、sessionStorage
  • localStorage:在浏览器中存储 key/value对。没有过期时间。存放数据大小5MB(有时根据浏览器而定),仅在客户端(即浏览器)保存,不参与服务器的通信。
    语法:
window.localStorage

保存数据语法:

localStorage.setItem("key", "value");

读取数据语法:

var lastname = localStorage.getItem("key");

删除数据语法:

localStorage.removeItem("key");
  • sessionStorage: 在浏览器中存储 key/value 对。 在关闭窗口或标签页之后将会删除这些数据。存放数据大小5MB(有时根据浏览器而定),仅在客户端(即浏览器)保存,不参与服务器的通信。
    语法
window.sessionStorage

保存数据语法:

sessionStorage.setItem("key", "value");

读取数据语法:

var lastname = sessionStorage.getItem("key");

删除指定键的数据语法:

sessionStorage.removeItem("key");

删除所有数据:

sessionStorage.clear();

总结
常见使用场景可以分为三类:

  • 父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners

  • 兄弟组件通信: eventBus ; vuex

  • 跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值