组件注册
- 全局注册往往是不够理想的,如果你使用像webpack的构建系统,全局注册所有的组件意味着即便你已经不再使用其中一个组件了,它仍然会被包含在最终的构建结果中。
Props
- 你可以以对象形式列出prop,这些property的名称和值分别是prop各自的名称和类型;
- 即便传入的数字、布尔值、数组、对象是静态的情况下,我们仍需要通过
v-bind
来告诉Vue这是一个js表达式而不是一个字符串; - 所有的prop都使得其父子prop之间形成了一个单向下行绑定;
- 父级prop的更新会向下流动到子组件中,但是反过来则不行;
- 这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解;
- 作为一个通用规则,应该避免修改任何prop,包括对象和数组,这种做法无视了单向数据绑定;
- type可以是下列原生构造函数中的一个:
String
、Number
、Boolean
、Array
、Object
、Date
、Function
、Symbol
。
非Prop的Attribute
- 当组件返回单个根节点时,非prop的attribute将自动添加到根节点的attribute中;
- 当一个具有
change
事件的HTML元素作为date-picker
的根元素时,change
事件监听器将从父组件传递到子组件,它将在原生<select>
的change
事件上触发; - 如果你不希望组件的根元素继承attribute,可以在组件的选项中设置
inheritAttrs: false
; - 禁用attribute继承的常见场景是需要将attribute应用于根节点之外的其他元素;
app.component('date-picker', {
inheritAttrs: false,
template: `
<div class="date-picker">
<input type="datetime-local" v-bind="$attrs" />
</div>
`
})
- 具有多个根节点的组件不具有自动attribute
隐式贯穿
行为,如果未显式绑定$attrs
,将发出运行时警告。
自定义事件
- 当在
emits
选项中定义了原生事件(如click
)时,将使用组件中的事件替代原生事件侦听器。
插槽
- 如果
<todo-button>
的template中没有一个<slot>
元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃; - 父级模板里的所有内容都是在父级作用域中编译的,子模版的所有内容都是在子作用域中编译的;
<slot>
元素有一个特殊的attribute:name
,通过它可以为不同的插槽分配独立的ID,也就能够以此来决定内容应该渲染到什么地方;- 一个不带
name
的<slot>
出口会带有隐含的名字”default“; - 在向具名插槽提供内容的时候,我们可以在一个
<template>
元素上使用v-slot
指令,并以v-slot
的参数的形式提供其名称; - 只要出现多个插槽,请始终为所有的插槽使用完整的基于
<template>
的语法; - 作用域插槽的内部工作原理是将你的插槽内容包括在一个传入参数的函数里;
- 缩写:
v-slot:header
可以被重写为#header
。
Provide/Inject
- 无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者;
- 父组件有一个
provide
选项来提供数据,子组件有一个inject
选项来开始使用这些数据; - 如果需要访问组件实例property,我们需要将
provide
转换为返回对象的函数; - 实际上,你可以将依赖注入看作是”长距离的prop“,除了:
① 父组件不需要知道哪些子组件使用了它provide的property;
② 子组件不需要知道inject的property来自哪里。
- 在默认情况下,
provide/inject
绑定并不是响应式的; - 我们可以通过传递一个
ref
property或reactive
对象给provide
来改变这种行为;
app.component('todo-list', {
// ...
provide() {
return {
todoLength: Vue.computed(() => this.todos.length)
}
}
})
app.component('todo-list-statistics', {
inject: ['todoLength'],
created() {
console.log(`Injected property: ${this.todoLength.value}`) // > 注入的 property: 5
}
})
- 在这种情况下,任何对
todos.length
的改变都会被正确地反映在注入todoLength
的组件中。
动态组件&异步组件
- 当在这些组件之间切换的时候,你有时候会想保持这些组件的状态,以避免反复渲染导致的性能问题;
- 如果我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来,可以用一个
<keep-alive>
元素将其动态组件包裹起来;
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
- 在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块;
- 为了实现这个效果,Vue有一个
defineAsyncComponent
方法; - 把webpack2及以上版本和ES2015语法相结合后,我们就可以这样使用动态地导入:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
模板引用
- 有时候你可能仍然需要在js中直接访问子组件,可以使用
ref
attribute为子组件或HTML元素指定引用ID;
<input ref="input" />
- 注意:
$refs
只会在组件渲染完成之后生效。这仅作为一个用于直接操作子元素的”逃生舱“—你应该避免在模板或计算属性中访问$refs
。
处理边界情况
- 得益于其响应性系统,Vue总是知道何时更新;
- 但是,在某些边缘情况下,你可能希望强制更新(尽管事实上没有任何响应式数据发生更改);
- 排除使用错误的情况,如果必须手动强制更新,可以使用
$forceUpdate
(不建议经常使用); - 通过向根元素添加
v-once
指令来确保之对其求值一次,然后进行缓存(不建议经常使用)。