依赖注入与动态组件
动态组件
即动态的切换组件。可以使用最简单的v-if
;也可以用vue
提供的component
标签和它的is
属性:
<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>
在动态切换组件的时候,常常用到keep-alive
,它所包裹的组件,在动态切换时,会被缓存,等到再次mount
的时候,将使用之前被缓存的实例,而非再重新渲染一次生命周期:
<!-- 非活跃的组件将会被缓存! -->
<KeepAlive>
<component :is="activeComponent" />
</KeepAlive>
依赖注入
原理
vue
允许我们在某个组件或者在全局定义provide
属性。后代组件会根据自己定义的inject
(注入的属性定义),在父级provide
(提供的属性定义)中查找需要的值,如果找到则保留。
provide的定义方式
provide
可以是一个数组,对象,函数。如果需要用到当前组件中的实例property
,则需要通过函数的方式定义才能获取到值:
export default {
data() {
return {
message: 'hello!'
}
},
provide() {
// 使用函数的形式,可以访问到 `this`
return {
message: this.message
}
}
}
响应式问题
默认情况下,这种传递是非响应式的。要达到响应式的目的,我们可以利用js对象
引用的特性,把传递的数据定义为一个对象,从而更改内部的属性而非对象本身以达到响应式目的;还可以使用组合式
语法中提供的computed()
函数提供一个计算属性(挖坑,等学了组合式后再探究具体原理):
import { computed } from 'vue'
export default {
data() {
return {
message: 'hello!'
}
},
provide() {
return {
// 显式提供一个计算属性
message: computed(() => this.message)
}
}
}
模板引用
初心
父子组件的数据传递手段,除了props
和emits
,还有provide
+inject
的手段。此外,模板引用的方法也可以实现数据传递,但是不能滥用,而且应该尽可能的不用:
如果一个子组件使用的是选项式 API ,被引用的组件实例和该子组件的
this
完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互。
Vue 的声明性渲染模型抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref
attribute,而不用使用冗长的原生js
。这才是ref
属性被发明的初心。
vue
提供了expose
选项可以用于限制对子组件实例的访问,如果在子组件中提供了expose
,父组件通过$refs
只能访问到expose
中提供的property
。
使用
vue
提供了一个特殊的 ref
attribute,它可以定义在任何标签上:
<input ref="input">
<my-component ref="myComponent"></my-component>
挂载结束后(生命周期的mounted
),ref
属性都会被暴露在 this.$refs
之上:
<script>
export default {
mounted() {
this.$refs.input.focus() //打开页面后自动聚焦
}
}
</script>
<template>
<input ref="input" />
</template>
ref
attribute的值不仅仅可以是一个普通变量,可以是一个函数,参见文档。
搭配v-for循环
<li v-for="item in list" ref="items">
{{ item }}
</li>
允许ref
和v-for
一起定义,这个时候ref
变成一个数组,并且ref数组不保证与源数组元素有相同的顺序。