# Vue 组件通信方式

# 常规形式

# props/$emit

父组件通过 props 的方式向子组件传递数据,而子组件通过 $emit 向父组件传递数据

// 父向子组件传递title属性
<comA :title="title" @update="updateTitle"></comA>

// 子组件向父组件传递数据
this.$emit('update', 'newTitle')

# @update:[Prop]

@update:myPropName 相当于绑定事件的 v-on 的简写方式,省去了定义接收子组件更新的函数,可以直接对属性进行更新

// 父向子组件传递title属性
<comA @update:title="title = $event"></comA>
// 子组件向父组件传递数据
this.$emit('update:title', 'newTitle')

# :[Prop].sync

相当于 props/$emit 的简写

// 父向子组件传递title组件
<comA :title.sync="title"></comA>
// 子组件向父组件传递数据
this.$emit('update:title', 'newTitle')
  • 传递了一个 title 属性

  • 绑定了一个 v-on 监听器

适合范围:相临父子组件

# provide/inject

这对选项需要一起使用,允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深

// 父组件通过 provide 传递数擗
provide () {
    return {
        provideData: this.provideData
    }
},
data:function () {
    return {
        show: false,
        arr: [1,2,3],
        provideData: {
            name: 'lanjz'
        }
    }
}

// 子组件通过 inject 接收数据
inject: ['provideData']
  • provide: 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 Symbols 作为 key,但是只在原生支持 SymbolReflect.ownKeys 的环境下可工作

  • inject: 选项应该是:

    • 一个字符串数组

    • 一个对象,对象的 key 是本地的绑定名,value 是:

      • 在可用的注入内容中搜索用的 key (字符串或 Symbol )

      • 一个对象,该对象的:

        • from 属性是在可用的注入内容中搜索用的 key (字符串或 Symbol)

        • default 属性是降级情况下使用的 value

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}
// 利用 `ES2015 Symbols`、函数 `provide` 和对象 `inject`
const s = Symbol()

const Provider = {
  provide () {
    return {
      [s]: 'foo'
    }
  }
}

const Child = {
  inject: { s },
  // ...
}

//设置默认值
const Child = {
  inject: {
    foo: { default: 'foo' }
  }
}

// 如果它需要从一个不同名字的 property 注入,则使用 from 来表示其源 property:
const Child = {
  inject: {
    foo: {
      from: 'bar',
      default: 'foo'
    }
  }
}

// 对非原始值使用一个工厂方法:
const Child = {
  inject: {
    foo: {
      from: 'bar',
      default: () => [1, 2, 3]
    }
  }
}


// 使用一个注入的值作为一个 property 的默认值:
const Child = {
  inject: ['foo'],
  props: {
    bar: {
      default () {
        return this.foo
      }
    }
  }
}

// 使用一个注入的值作为数据入口:
const Child = {
  inject: ['foo'],
  data () {
    return {
      bar: this.foo
    }
  }
}

注意点:

  • 如果 provide 里的属性要使用组件实例中的数据,则必需使用函数的形式,如果只是静态数据则可以使用对象的形式

  • 如果希望 provide 是响应式的,即子组件能跟着父组件的 provide 变化而变化,那么 provide的值需要是一个对象,那么这个对象里的属性将是可更新

    官方解释:provideinject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的

通信范围:父传子,且可多层

# 跨组件通过

# eventBus

eventBus 又称为事件总线,在 Vue 中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件

// 初始化一个事件总线  event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()

// 发送事件
import {EventBus} from './event-bus.js'
EventBus.$emit('addition', {})

// 接收事件
import {EventBus} from './event-bus.js'
EventBus.$on('addition', param => {})

// 移除事件总线
mport { EventBus } from './event-bus.js'
EventBus.$off('addition', {})

//移除所有事件总线
EventBus.$off()

适合范围:任意位置的组件,可跨级

# VueX

# 获取组件实例

通过获取组件实例的方式来访问这个实例中的属性和方法

# ref/$refs

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

  • 如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素

  • 如果用在子组件上,引用就指向组件实例

<!-- `vm.$refs.p` will be the DOM node -->
<p ref="p">hello</p>

<!-- `vm.$refs.child` will be the child hllComponent instance -->
<child-component ref="child"></child-component>

注意点

  • 如果有同名的 ref 定义,则这个 ref 指向最后渲染出来的那个

    // 初始时 show=false
    <p ref="hi" v-if="show">hi</p>
    <p ref="hi">hello</p>
    // moutned 钩子中打印
    this.$refs.hi // <p ref="hi">hello</p>
    this.show = true
    this.$refs.hi // <p ref="hi" v-if="show">hi</p>
    this.show = false
    // 销毁 dom 后,这个 refs.hi 并不会赋值成其它名为 `hi` 的元素,而是等于 undefind
    this.$refs.hi // undefind
    
  • v-for 用于元素或组件的时候,引用信息将是包含 DOM 节点或组件实例的数组

    <span v-for="(item) in list" ref="hi">{{item}}</span>
    // this.$refs.hi // [<span>, ...]
    

# $children/$parent

  • $children :当前组件包含的子组件实例数组。需要注意 $children 并不保证顺序,也不是响应式的。

  • $parent: 当前组件对应的父组件实例

使用 $children$parent 要注意的点

  • 边界情况,如在 #app 上拿 $parent 得到的是 new Vue() 的实例,在这实例上再拿 $parent 得到的是 undefined

  • 在最底层的子组件拿 $children 是个空数组

  • 也要注意得到 $parent$children 的值不一样,$children 的值是数组,而 $parent 是个对象

适合范围:相临父子组件

# 其它

# $attrs/$listeners

  • $listeners: 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用

  • $attrs: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 ( classstyle 除外)。当一个组件没有声明任何 prop 时, 这里会包含所有父作用域的绑定 (classstyle除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有

// 父组中
 <com 
   name="lanjz"
   class="com"
   age="18"
   @click="callback"
   v-on:event-one="callback"
   v-on:event-two="callback"
  />

// com组件
mounted() {
    console.log(this.$attrs) // {age: "18", name: "lanjz"}
    console.log(this.$listeners) // {click: ƒ invoker(), event-one:ƒ invoker(),event-two: ƒ invoker()}
}