这里记录的都是和处理边界情况有关的功能,即一些需要对 Vue 的规则做一些小调整的特殊情况。不过注意这些功能都是有劣势或危险的场景的。我们会在每个案例中注明,所以当你使用每个功能的时候请稍加留意。
1.访问元素&组件
1)访问根实例
在每个 new Vue
实例的子组件中,其根实例可以通过 $root
属性进行访问。例如,在这个根实例中:
// Vue 根实例
new Vue({
data: {
foo: 1
},
computed: {
bar: function () { /* ... */ }
}
methods: {
baz: function () { /* ... */ }
}
})
所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。
|
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。不过这个模式扩展到中大型应用来说就不然了。因此在绝大多数情况下,我们强烈推荐使用 Vuex 来管理应用的状态。
2)访问父级组件实例
和 $root
类似,$parent
属性可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。
另外在一些可能适当的时候,你需要特别地共享一些组件库。举个例子,在和 JavaScript API 进行交互而不渲染 HTML 的抽象组件内,诸如这些假设性的 Google 地图组件一样:
这个
组件可以定义一个 map
属性,所有的子组件都需要访问它。在这种情况下
可能想要通过类似 this.$parent.getMap
的方式访问那个地图,以便为其添加一组标记。你可以在这里查阅这种模式。
请留意,尽管如此,通过这种模式构建出来的那个组件的内部仍然是容易出现问题的。比如,设想一下我们添加一个新的
组件,当
在其内部出现的时候,只会渲染那个区域内的标记:
那么在
内部你可能发现自己需要一些类似这样的 hack:
var map = this.$parent.map || this.$parent.$parent.map
很快它就会失控。这也是我们针对需要向任意更深层级的组件提供上下文信息时推荐依赖注入的原因。
3)访问子组件实例或子元素
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref
特性为这个子组件赋予一个 ID 引用。例如:
现在在你已经定义了这个 ref
的组件里,你可以使用:
this.$refs.usernameInput
来访问这个
实例,以便不时之需。比如程序化的从一个父级组件聚焦这个输入框。在刚才那个例子中,该
组件也可以使用一个类似的 ref
提供对内部这个指定元素的访问,例如:
这样就允许父级组件通过下面的代码聚焦
里的输入框:
this.$refs.usernameInput.focus()
当 ref
和 v-for
一起使用的时候,你得到的引用将会是一个包含了对应数据源的这些子组件的数组。
$refs
只会在组件渲染完成之后生效,并且它们不是响应式的。这只意味着一个直接的子组件封装的“逃生舱”——你应该避免在模板或计算属性中访问 $refs
。
4)依赖注入
在上面那个访问父级实例的时候的一个Google Maps的例子里:
在这个组件里,所有
的后代都需要访问一个 getMap
方法,以便知道要跟那个地图进行交互。不幸的是,使用 $parent
属性无法很好的扩展到更深层级的嵌套组件上。这也是依赖注入的用武之地,它用到了两个新的实例选项:provide
和 inject
。
provide
选项允许我们指定我们想要提供给后代组件的数据/方法。在这个例子中,就是
内部的 getMap
方法:
provide: function () {
return {
getMap: this.getMap
}
}
然后在任何后代组件里,我们都可以使用 inject
选项来接收指定的我们想要添加在这个实例上的属性:
inject: ['getMap']
2.程序化的事件侦听器
现在,你已经知道了 $emit
的用法,它可以被 v-on
侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法。我们可以:
$on(eventName, eventHandler)
侦听一个事件$once(eventName, eventHandler)
一次性侦听一个事件$off(eventName, eventHandler)
停止侦听一个事件你通常不会用到这些,但是当你需要在一个组件实例上手动侦听事件时,它们是排得上用场的。它们也可以用于代码组织工具。例如,你可能经常看到这种集成一个第三方库的模式:下面代码有点不懂:
https://cn.vuejs.org/v2/guide/components-edge-cases.html#%E9%80%92%E5%BD%92%E7%BB%84%E4%BB%B6
这个的上面
3.循环引用
1)递归组件
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name
选项来做这件事:
|
当你使用 Vue.component
全局注册一个组件时,这个全局的 ID 会自动设置为该组件的 name
选项。
|
稍有不慎,递归组件就可能导致无限循环:
|
类似上述的组件将会导致“max stack size exceeded”错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到 false
的 v-if
)。