vue中组件name的作用

1,403 阅读1分钟

vue中组件name的作用

起因

export default{
name:'xxxxxxx'
}

自己在写Vue项目的时候,到写name的时候就会很纠结到底写还是不写,有时怕错索性就写上。
那么这个name有什么用?怎么有时写,有时又不写?

官方文档对name的介绍

image.png

name的三种用途

项目中有用到keep-alive时

  • name可以用作include和exclude的值

新建组件:
在Table.vue组件中定义了组件名name为Table,dom加载完之后执行mounted进行数据更新,这里获取table数据。

//Table.vue
export default {
    name:'Table'
},
activated(){
  //第二种解决方案
  this.getData();
},
methods:{
   getData(){
          axios.get('/xx/table.json',{
              params:{
                id:this.$route.query.id  
              }
          }).then(()=>{
            .......
          })
     }
 }
//App.vue
<div id="app"> 
    <keep-alive exclude="Table">
      <router-view/>
    </keep-alive>
  </div>

在App.vue中使用keep-alive组件会缓存不活动的组件实例,而不是销毁它们。这样会导致我们滴二次进入页面时不会刷新页面,有两种方式可以解决这样的问题:

  1. 在keep-alive中加入exclude属性,exclude="Table"这样就不会对Table组件进行缓存,第二次进入该页面时就会得到最新数据。
  2. 当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。activated:被 keep-alive 缓存的组件激活时调用。deactivated被 keep-alive 缓存的组件停用时调用。这里把this.getData();放到activated中

keep-alive 扩展

  1. 执行顺序

页面第一次进入时,钩子的触发顺序是created -> mounted -> activated,退出时触发 deactivated.再次进入时只触发activated。所有,我们把只要执行一次的放在 created 或者 mounted 里,切换到组件需要每次获取最新数据的放在activated中。

  1. <keep-alive> 源码

地址:vuejs/vue/edit/dev/src/core/components/keep-alive.js
文章解析:juejin.cn/post/686220…

/* @flow */

import { isRegExp, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'

type VNodeCache = { [key: string]: ?VNode };

function getComponentName (opts: ?VNodeComponentOptions): ?string {
  return opts && (opts.Ctor.options.name || opts.tag)
}

function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
  if (Array.isArray(pattern)) {
    return pattern.indexOf(name) > -1
  } else if (typeof pattern === 'string') {
    return pattern.split(',').indexOf(name) > -1
  } else if (isRegExp(pattern)) {
    return pattern.test(name)
  }
  /* istanbul ignore next */
  return false
}

function pruneCache (keepAliveInstance: any, filter: Function) {
  const { cache, keys, _vnode } = keepAliveInstance
  for (const key in cache) {
    const cachedNode: ?VNode = cache[key]
    if (cachedNode) {
      const name: ?string = getComponentName(cachedNode.componentOptions)
      if (name && !filter(name)) {
        pruneCacheEntry(cache, key, keys, _vnode)
      }
    }
  }
}

function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const cached = cache[key]
  if (cached && (!current || cached.tag !== current.tag)) {
    cached.componentInstance.$destroy()
  }
  cache[key] = null
  remove(keys, key)
}

const patternTypes: Array<Function> = [String, RegExp, Array]

export default {
  name: 'keep-alive',
  abstract: true,

  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },

  created () {
    this.cache = Object.create(null)
    this.keys = []
  },

  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted () {
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  render () {
    const slot = this.$slots.default
    const vnode: VNode = getFirstComponentChild(slot)
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // check pattern
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }

      const { cache, keys } = this
      const key: ?string = vnode.key == null
        // same constructor may get registered as different local components
        // so cid alone is not enough (#3269)
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance
        // make current key freshest
        remove(keys, key)
        keys.push(key)
      } else {
        cache[key] = vnode
        keys.push(key)
        // prune oldest entry
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }
}

递归组件

递归组件,顾名思义,就是自己的内部实现又调用自己的组件。
image.png
其实,除了name选项是必须的之外,还有一点也是在实现递归组件要注意的,就是要防止无限递归,造成调用栈溢出,在不满足条件时跳出递归。
父组件:

<template>
  <div>
    <tree :model="treeData"></tree>
  </div>
</template>

<script>
  import tree from '@/components/tree'
  export default {
    data () {
      return {
        treeData: {
          title: '1',
          children: [
            {title: '1-1'},
            {
              title: '1-2',
              children: [
                {title: '1-2-1'},
                {title: '1-2-2'},
                {title: '1-2-3'},
              ]
            },
            {
              title: '1-3',
              children: [
                {
                  title: '1-3-1',
                  children: [
                    {
                      title: '1-3-1-1'
                    },
                    {
                      title: '1-3-1-2'
                    }
                  ]
                },
                {title: '1-3-2'},
                {title: '1-3-3'},
              ]
            },
          ]
        }
      }
    },
    created(){

    },
    methods:{

    },
  }
</script>

<style scoped lang="scss"></style>

子组件:

<template>
  <div>
    <div v-for="(item, index) in model" :key="index">
      {{ item.title }}
      <div
        v-if="item.children && item.children.length"
        style="margin-left:20px;"
      >
        <tree :model="item.children"></tree>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  // 这里要写name:tree才可以递归
  name: "tree",
  props: {
    model: Array
  },
  data() {
    return {};
  }
};
</script>

<style scoped lang="scss"></style>

效果:
image.png

vue-tools 调试时

vue组件中的name决定了vue-tools的显示。
image.png
image.png