基础组件的自动化全局注册
如果你使用了webpack(或在内部使用了webpack的Vue CLI 3+),那么就可以使用require.context只全局注册这些非常通用的基础组件。这里有一份可以让你在应用入口(比如src/main.js)中全局导入基础组件的视力代码
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context(
// 其组件目录的相对路径
'./components',
// 是否查询其子目录
false,
// 匹配基础组件文件名的正则表达式
/Base[A-Z]\w+\.(vue|js)$/
)
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)
// 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 获取和目录深度无关的文件名
fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
)
)
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
)
})
记住全局注册的行为必须在根Vue实例(通过new Vue)创建之前发生。
自定义事件
事件名
不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。
this.$emit('myEvent')
则监听这个名字的kebab-case版本是不会有任何效果的:
<my-component v-on:my-event="doSomething"/>
v-on事件监听器在DOM模板中会被自动转换为全小写(因为HTML是大小写不敏感的),所以v-on:myEvent将变成v-on:myevent,最终导致myEvent不会被监听到。因此,推荐你始终使用kebab-case事件名。
作用域插槽
一般情况下,插槽的作用域为父组件的作用域。为了让插槽内容可以访问到子组件的数据,我们可以将user(子组件的数据)作为slot元素的一个attribute绑定上去:
<!--子组件-->
<span>
<slot :user="user">
{{user.lastName}
</slot>
</span>
<!--父组件-->
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }
</template>
</current-user>
独占默认插槽的缩写语法
当被提供的内容只有默认插槽时,组件的标签才可以被当做插槽的模板来使用。这种情况我们就可以把v-slot直接用在组件上:
<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</current-user>
注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
<!--无效,会导致警告-->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</current-user>
只要出现多个插槽,请始终为所有的插槽使用完整的基于template的语法:
<!--正确写法-->
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</current-user>
处理边界情况
访问元素&组件
在绝大多数情况下,我们最好不要触达另一个组件实例内部或手动操作DOM元素。不过确实在一些情况下做这些事情是合适的。
#访问根实例($root)
<!--vue实例-->
new Vue({
data: { foo: 1 },
methods: {
baz() {...}
},
computed: {
bar() {...}
}
})
所有的子组件都可以将这个实例作为一个全局store来访问或者使用
//获取根组件的数据
this.$root.foo
//调用跟组件的方法
this.$root.baz()
//访问根组件的计算属性
this.$root.bar
对于demo或非常小型的有少量组件的应用来说这是很方便的。不过这个模型扩展到中大型应用来说就不然了。因此在却大多数情况下,我们强烈推荐使用Vuex来管理状态。
#访问父级组件实例($parent)
#访问子组件实例或子元素(ref)
<input ref="input"/>
this.$refs.input.force()
#依赖注入(provide) provide选项允许我们指定我们想要提供给后台组件的数据/方法。
<!--父组件-->
provide() {
return {
getMap: this.getMap
}
}
<!--子组件-->
inject: ['getMap']
然而,依赖注入还是有负面影响的。他将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。
控制更新
强制更新($forceUpdate)
####通过v-once创建低开销的静态组件
不要过度使用这种模式。当你需要渲染大量的静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全没有必要--再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once 或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新。
生命周期图示

选项/生命周期钩子
所有的生命周期钩子自动绑定this上下文到实例中(因为箭头函数绑定了父上下文,所以不能用箭头函数来定义一个生命周期方法)