无论是通过 Vue.component 的方式,还是在写 .vue 文件的方式,官方都会推荐你写一个 name 属性。但是好像这个 name 在渲染时又几乎用不到,那么它实际能干嘛呢?
方便调试
Vue 有一款官方强力推荐的浏览器上的调试插件: vue-devtools。通过打开调试工具,我们可以很轻松的看到已经渲染到页面上的各个组件,以及对应的组件的内部状态。
例如以下组件:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | <script>
 export default {
 name: 'Kawaii',
 props: ['val'],
 render (h) {
 return (
 <div>
 { this.val }
 </div>
 )
 }
 }
 </script>
 
 | 
如果在 App.vue 里引用的话:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | <template><Demo val="foo" />
 </template>
 
 <script>
 import Demo from './components/Demo'
 
 export default {
 name: 'app',
 components: {
 Demo
 }
 }
 </script>
 
 | 
那么可以在 chrome 的调试界面可以看到:

其中 Kawaii 就是刚才起了名字的组件,如果将其改名为 看不见看不见
| 12
 3
 4
 5
 6
 7
 
 | <script>
 export default {
 name: '看不见看不见',
 
 }
 </script>
 
 | 
那么在 chrome 界面则可以直接看到其显示名字就变为 看不见看不见 了。

但如果不设置名字,那么 Vue.js 默认会用 tag 名称,也就是这个组件在 template 或者 jsx 里的名字。比如:
| 12
 3
 4
 5
 6
 7
 8
 
 | <script>
 export default {
 
 
 
 }
 </script>
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | <template><D val="foo" />
 </template>
 
 <script>
 import Demo from './components/Demo'
 
 export default {
 name: 'app',
 components: {
 'D': Demo
 }
 }
 </script>
 
 | 
那么此时就会显示为 D:

Note: functional 组件不会显示在 devtools 中,因为 vue 并不会为 functional component 创建实例
递归应用
在有些时候,我们可以会递归使用自身组件,比如:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | <template><div>
 {{ val }}
 <Recursive v-if="val" :val="val - 1" />
 </div>
 </template>
 
 <script>
 
 export default {
 name: 'Recursive',
 props: {
 val: {
 required: true,
 type: Number,
 default: 5
 }
 }
 }
 </script>
 
 | 
在这种情况下,如果不设置 name,那么 console 就会报错,提示在 Recursive.vue 中找不到名为 Recursive 的组件。因此,如果想要递归应用自身组件的话,就必须设置 name 属性。
keep-alive
keep-alive 是 Vue 内置的组件,可以将 keep-alive 的子组件运行缓存,用于保存切换 (例如 v-if 的切换) 过程前的状态。
而 keep-alive 有两个 props 是 include 以及 exclude。前者指明需要缓存的组件的名字。而后者则指明不需要缓存的组件的名字。
下述例子中,Foo, Bar 两个组件的名字分别为 vue-foo, vue-bar, 且组件均包含一个 input。因为通过 input 可以很轻松的观察到切换前后的状态是否有保存:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | <template><div>
 {{ val }} <input type="text" v-model="m" />
 </div>
 </template>
 
 <script>
 
 export default {
 name: 'vue-foo',
 data () {
 return {
 val: 'vue-foo',
 m: 'vue-foo'
 }
 }
 }
 </script>
 
 | 
Bar.vue 跟 Foo.vue 内容几乎一样,除了名字,因此这里就不贴 Bar.vue 的代码了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | <template><div>
 <keep-alive include="vue-foo">
 <Foo v-if="visible" />
 <Bar v-else />
 </keep-alive>
 <Button @click="visible = !visible">
 Visible {{ visible }}
 </Button>
 </div>
 
 </template>
 
 <script>
 import Foo from './components/Foo'
 import Bar from './components/Bar'
 
 export default {
 name: 'app',
 data () {
 return {
 visible: true
 }
 },
 components: {
 Foo,
 Bar
 }
 }
 </script>
 
 | 
通过点击 button 来切换。因为设置了 include 指令,那么只有 Foo 的状态才会被保存:

通过这张效果图可以看到,在切换过程中,Foo 的状态被保存了,而 Bar 则没有,而是重新生成。
如果使用 exclude 指令:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <template><div>
 <keep-alive exclude="vue-foo">
 <Foo v-if="visible" />
 <Bar v-else />
 </keep-alive>
 <Button @click="visible = !visible">
 Visible {{ visible }}
 </Button>
 </div>
 
 </template>
 
 | 
那么就会得到一个完全相反的结果: 即 Bar 的状态被保存了,而 Foo 则没有,而是重新生成。
References
- api/#keep-alive
- api/#name
- vue-devtools/issues/280