vue 组件分类
一. 简介
之所以写这篇文章,是因为前段时间作为面试官,陆陆续续面试了几十个人,其中一个问题就是 "vue
的组件分类都有哪些?" ,令人惊讶的是大多数人都只回答了全局组件
和局部组件
,难道vue
的组件就只是这两种吗?其实谈分类,是一定要谈分类标准的,没有分类标准的分类都是耍流氓。以下是个人总结,不喜勿喷。
二.分类
1.按组件注册方式分类:可以分为全局组件
和局部组件
全局组件
a. 全局组件注册
Vue.component("my-component-name", {
/****/
});
b. 使用
<my-component-name></my-component-name>
c. 什么情况下需要将组件注册为全局组件?
一般是一些基础组件,频繁(3 次以上)需要用到的,需要全局注册。比如常用的 dialog 组件,search 组件,toast 组件,message 组件等。
局部组件
a. 局部组件注册
import ComponentA from "./ComponentA.vue";
export default {
components: {
ComponentA
}
// ...
};
b. 使用
<component-a></component-a>
c. 什么情况下需要将组件注册为局部组件?
一般情况下的组件都应该是局部组件,这样会极大的减少构建应用后的代码体积,但是对于频繁使用的组件就显得麻烦了,所以建议,组件使用频率低,组件比较大的时候注册为局部组件。比如 table 组件,chart 组件等
2.按组件有无自己的状态分类:可以分为函数式(无状态)组件
和普通(有状态)组件
a. 函数式组件
新建文件
src/components/FunctionComponent/index.vue
functional
字段标记该组件是一个函数式组件
函数式组件里面用的是 jsx 的语法
<script>
import OtherComponent from "./other";
export default {
name: "FunctionComponent",
functional: true,
components: {
OtherComponent
},
props: {
title: {
type: String,
required: true
}
},
render(h, { props }) {
const { title } = props;
return (
<div>
<p> 我是函数式组件</p>
<p>props {title}</p>
<OtherComponent otherInfo={title} title="我是函数式组件的其他组件" />
</div>
);
}
};
</script>
src/components/FunctionComponent/other.vue
基于模板的函数式组件 template 标签要标记 functional
<template functional>
<div>
{{ props.title }}
<p>
otherInfo {{ props.otherInfo }}
</p>
</div>
</template>
<script>
export default {
functional: true,
props: {
title: {
default: "",
type: String
},
otherInfo: {
default: "",
type: String
}
}
};
</script>
b. 使用
import FunctionComponent from "./components/FunctionComponent/index";
export default {
components: {
FunctionComponent
}
};
<function-component title="函数式组件" />
c. 什么情况下需要将组件写为函数式组件?
一般是无状态 (没有响应式数据)的组件可以注册成函数式组件,好像不用函数式组件也可以呀,为啥要注册成函数式组件?
当一个组件是一个函数式组件的时候,它没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。实际上,它只是一个接受一些 prop 的函数,所以渲染开销也低很多。
3.按组件是否动态分类:可以分为动态组件
和普通(非动态)组件
a. 动态组件
新建文件
src/components/DynamicComponent/1.vue
<template>
<div>
动态组件1
</div>
</template>
src/components/DynamicComponent/1.vue
<template>
<div>
动态组件1
</div>
</template>
b. 使用
<button @click="toggle('1')">点击切换组件1</button>
<button class="btn" @click="toggle('2')">点击切换组件2</button>
<component :is="currentTabComponent"></component>
import DynamicComponent1 from "./components/DynamicComponent/1";
import DynamicComponent2 from "./components/DynamicComponent/2";
export default {
components: {
DynamicComponent1,
DynamicComponent2
},
data() {
return {
currentTabComponent: "DynamicComponent1"
};
},
methods: {
toggle(type) {
this.currentTabComponent = "DynamicComponent" + type;
}
}
};
可能大家见到过最多是这样子的,有没有很熟悉
<button @click="toggle">点击切换组件1</button>
<dynamic-component1 v-if="show" />
<dynamic-component2 v-else />
import DynamicComponent1 from "./components/DynamicComponent/1";
import DynamicComponent2 from "./components/DynamicComponent/2";
export default {
components: {
DynamicComponent1,
DynamicComponent2
},
data() {
return { show: false };
},
methods: {
toggle() {
this.show = !this.show;
}
}
};
c. 什么情况下需要将组件写为动态组件?
一般是是需要组件之间切换的情况下,好像不用动态组件也可以呀,为啥要动态组件?
可能当你写导入 DynamicComponent1 从 1 写到 10 的时候,然后 template 再写 DynamicComponent 10 次的时候,它的好处就出来了。
4.按组件是否异步分类:可以分为异步组件
和普通(非异步)组件
a.异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染
新建文件
src/components/AsyncComponent.vue
<template>
<div>
<ul>
<li v-for="item in list" :key="item.name">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
export default {
name: "AsyncComponents",
components: {},
data() {
return { list: [] };
},
created() {
this.getList();
},
methods: {
getList() {
setTimeout(() => {
const data = [
{ name: "你好", time: "2019-01-01 10:10:55" },
{ name: "世界", time: "2012012-01 12:20:00" }
];
this.list = data;
}, 2000);
}
}
};
</script>
b. 使用
<async-component />
import AsyncComponent from "./components/AsyncComponent";
export default {
components: {
AsyncComponent
}
};
c. 什么情况下需要将组件写为异步组件?
一般是需要从服务器加载数据的组件,且需要多个地方使用的,因为它会把结果缓存起来供未来重渲染。
还有就是大家使用最多的 是在 Vue Router 里使用,异步组件结合 Webpack 的代码分割功能,可以轻松实现路由组件的懒加载。
5.按组件是否循环引用分类:可以分为递归组件
和普通(非递归)组件
a.递归组件
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。
新建文件
src/components/RecursiveComponent.vue
<template>
<div>
<ul>
<li v-for="item in list" :key="item.name">
<span>{{ item.name }}</span>
<recursive-component v-if="item.children" :list="item.children" />
</li>
</ul>
</div>
</template>
<script>
export default {
name: "RecursiveComponent",
props: {
list: {
default: () => [],
type: Array
}
}
};
</script>
b. 使用
<recursive-component :list="list" />
import RecursiveComponent from "./components/RecursiveComponent";
export default {
components: {
RecursiveComponent
},
data() {
return {
list: [
{
name: "1",
children: [
{
name: "1-1"
},
{
name: "1-2",
children: [
{
name: "1-2-1"
},
{
name: "1-2-2"
}
]
}
]
},
{
name: "2",
children: [
{
name: "2-1",
children: [
{
name: "2-1-1"
},
{
name: "2-1-2",
children: [
{
name: "2-1-2-1"
},
{
name: "2-1-2-2"
}
]
}
]
}
]
}
]
};
}
};
c. 什么情况下需要将组件写为递归组件?
一般是组件需要调用自身的时候,比如树组件,侧边栏路由组件等
三.总结
分类标准 | 分类 1 | 分类 2 |
---|---|---|
注册方式 | 全局组件 | 局部组件 |
有无自己的状态 | 函数式(无状态)组件 | 普通(有状态)组件 |
是否动态 | 动态组件 | 普通(非动态)组件 |
是否异步 | 异步组件 | 普通(非异步)组件 |
是否循环引用 | 递归组件 | 普通(非递归)组件 |
参考链接