Skip to content

依赖注入与动态组件

动态组件

即动态的切换组件。可以使用最简单的v-if;也可以用vue提供的component标签和它的is属性:

vue
<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>

在动态切换组件的时候,常常用到keep-alive,它所包裹的组件,在动态切换时,会被缓存,等到再次mount的时候,将使用之前被缓存的实例,而非再重新渲染一次生命周期:

vue
<!-- 非活跃的组件将会被缓存! -->
<KeepAlive>
  <component :is="activeComponent" />
</KeepAlive>

依赖注入

原理

vue允许我们在某个组件或者在全局定义provide属性。后代组件会根据自己定义的inject(注入的属性定义),在父级provide(提供的属性定义)中查找需要的值,如果找到则保留。

provide的定义方式

provide可以是一个数组,对象,函数。如果需要用到当前组件中的实例property,则需要通过函数的方式定义才能获取到值:

js
export default {
  data() {
    return {
      message: 'hello!'
    }
  },
  provide() {
    // 使用函数的形式,可以访问到 `this`
    return {
      message: this.message
    }
  }
}

响应式问题

默认情况下,这种传递是非响应式的。要达到响应式的目的,我们可以利用js对象引用的特性,把传递的数据定义为一个对象,从而更改内部的属性而非对象本身以达到响应式目的;还可以使用组合式语法中提供的computed()函数提供一个计算属性(挖坑,等学了组合式后再探究具体原理):

js
import { computed } from 'vue'

export default {
  data() {
    return {
      message: 'hello!'
    }
  },
  provide() {
    return {
      // 显式提供一个计算属性
      message: computed(() => this.message)
    }
  }
}

模板引用

初心

父子组件的数据传递手段,除了propsemits,还有provide+inject的手段。此外,模板引用的方法也可以实现数据传递,但是不能滥用,而且应该尽可能的不用:

如果一个子组件使用的是选项式 API ,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互。

Vue 的声明性渲染模型抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref attribute,而不用使用冗长的原生js。这才是ref属性被发明的初心。

vue提供了expose选项可以用于限制对子组件实例的访问,如果在子组件中提供了expose,父组件通过$refs只能访问到expose中提供的property

使用

vue提供了一个特殊的 ref attribute,它可以定义在任何标签上:

vue
<input ref="input">
<my-component ref="myComponent"></my-component>

挂载结束后(生命周期的mounted),ref属性都会被暴露在 this.$refs 之上:

vue
<script>
export default {
  mounted() {
    this.$refs.input.focus() //打开页面后自动聚焦
  }
}
</script>

<template>
  <input ref="input" />
</template>

ref attribute的值不仅仅可以是一个普通变量,可以是一个函数,参见文档

搭配v-for循环

vue
<li v-for="item in list" ref="items">
      {{ item }}
</li>

允许refv-for一起定义,这个时候ref变成一个数组,并且ref数组保证与源数组元素有相同的顺序。