14-1.访问元素 & 组件
在某些情况下,可以使用这些手段。
访问根实例,$root
访问父组件实例,$parent
访问子组件实例, $refs[childComponentName]
TIP
$refs
只会在组件渲染完成之后生效,并且它们不是响应式的。
这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs
。
在使用 $parent
时,只能父子组件通信,如果想要更深层级的通信,Vue
提供了依赖注入:
它用到了两个新的实例选项:provide
和 inject
。
祖先组件内:
provide: function () {
return {
getMap: this.getMap
}
}
任何后代组件内:
inject: ['getMap']
14-2.程序化的事件侦听器
$on
监听一个事件$off
停止监听一个事件$once
一次性监听一个事件
在某些场景下,能够更好的管理维护自己的模块代码:
mounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
TIP
Vue
的事件系统不同于浏览器的 EventTarget API
。
尽管它们工作起来是相似的,但是 $emit
、$on
, 和 $off
并不是 dispatchEvent
、addEventListener
和 removeEventListener
的别名。
14-3.循环引用
组件是可以在它们自己的模板中调用自身的。
name: 'stack-overflow',
template: '<div><stack-overflow></stack-overflow></div>'
类似上述的组件将会导致 max stack size exceeded
错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到 false
的 v-if
)。
当通过 Vue.component
全局注册组件的时候,这个循环引用悖论会被自动解开。
但如果是通过 webpack
构建工具,就有可能遇见一个错误:
Failed to mount component: template or render function not defined.
对应的解决办法是在生命周期钩子 beforeCreate
时才注册引用组件:
beforeCreate: function () {
this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}
也可以利用 webpack
的异步 import
:
components: {
TreeFolderContents: () => import('./tree-folder-contents.vue')
}
14-4.模板定义的替代品
Vue
定义模板的推荐方式有二:
template
选项.vue
单文件中的<template>
元素。
除此以外,还有两种方式:
14-5.控制更新
利用 $forceUpdate
渲染普通的 HTML
元素在 Vue
中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。
在这种情况下,你可以在根元素上添加 v-once
attribute
以确保这些内容只计算一次然后缓存起来。