Skip to content

14-1.访问元素 & 组件

在某些情况下,可以使用这些手段。

访问根实例,$root

访问父组件实例,$parent

访问子组件实例, $refs[childComponentName]

TIP

$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。

这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

在使用 $parent 时,只能父子组件通信,如果想要更深层级的通信,Vue 提供了依赖注入

它用到了两个新的实例选项:provideinject

祖先组件内:

js
provide: function () {
  return {
    getMap: this.getMap
  }
}

任何后代组件内:

js
inject: ['getMap']

14-2.程序化的事件侦听器

  • $on 监听一个事件

  • $off 停止监听一个事件

  • $once 一次性监听一个事件

在某些场景下,能够更好的管理维护自己的模块代码:

js
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 并不是 dispatchEventaddEventListenerremoveEventListener 的别名。

14-3.循环引用

  1. 递归组件

组件是可以在它们自己的模板中调用自身的。

js
name: 'stack-overflow',
template: '<div><stack-overflow></stack-overflow></div>'

类似上述的组件将会导致 max stack size exceeded 错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到 falsev-if)。

  1. 组件之间的循环引用

当通过 Vue.component 全局注册组件的时候,这个循环引用悖论会被自动解开。

但如果是通过 webpack 构建工具,就有可能遇见一个错误:

Failed to mount component: template or render function not defined.

对应的解决办法是在生命周期钩子 beforeCreate 时才注册引用组件:

js
beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}

也可以利用 webpack 的异步 import

js
components: {
  TreeFolderContents: () => import('./tree-folder-contents.vue')
}

14-4.模板定义的替代品

Vue 定义模板的推荐方式有二:

  1. template 选项
  2. .vue 单文件中的 <template> 元素。

除此以外,还有两种方式:

  1. 内联模板

  2. X-Template

14-5.控制更新

  1. 强制更新

利用 $forceUpdate

  1. 通过 v-once 创建低开销的静态组件

渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。

在这种情况下,你可以在根元素上添加 v-once attribute 以确保这些内容只计算一次然后缓存起来。