0
点赞
收藏
分享

微信扫一扫

见贤思齐——从Element Plus UI 源码中学到的技巧

萨科潘 2022-04-04 阅读 80

Element UI是世界级最优秀的UI框架之一。向优秀看齐,向卓越跟进,大家卷起来,通过阅读源码可以学到很有有趣的知识

技巧一:用代码来生成代码

源码入口文件生成:​​Element UI​​ 目前一共有80个组件,如果要导出这80个组件,那么引入、导出和声明Vue组件的代码都要写240次,而且,组件的增删都要去修改入口文件。为了减少这部分工作量,基于​​components.d.ts​​来对组件引入和导出。

​components.d.ts​​内容如下:

见贤思齐——从Element Plus UI 源码中学到的技巧_函数返回
相较于上一个版本的​​​components.json​​​来驱动新版本采用ts的方式,反而更加来的直接和干脆,分两部分来引入

  • 声明组件​​GlobalComponents​
  • 声明组件属性​​ComponentCustomProperties​

之后在​​env.d.ts​​中将component.d.ts中的声明的组件及属性信息通过全局模块公开

import type { vShow } from 'vue'

declare global {
const process: {
env: { NODE_ENV: string }
}

namespace JSX {
interface IntrinsicAttributes {
class?: any
style?: any
}
}
}

declare module '@vue/runtime-core' {
export interface GlobalComponents {
Component: (props: { is: Component | string }) => void
}

export interface ComponentCustomProperties {
vShow: typeof vShow
}
}

export {}

经过这层铺垫之后,在​​element-plus/components.ts​​上面通过​​import​​导入

import { ElAffix } from '@element-plus/components/affix'
import { ElAlert } from '@element-plus/components/alert'
import { ElAutocomplete } from '@element-plus/components/autocomplete'
import { ElAvatar } from '@element-plus/components/avatar'
import { ElBacktop } from '@element-plus/components/backtop'
import { ElBadge } from '@element-plus/components/badge'
import {
ElBreadcrumb,
ElBreadcrumbItem,
} from '@element-plus/components/breadcrumb'
import { ElButton, ElButtonGroup } from '@element-plus/components/button'
/<strong>省略 90多个组件导入</strong>/
import { ElCarousel, ElCarouselItem } from '@element-plus/components/carousel'
import { ElCascader } from '@element-plus/components/cascader'
...

export default [
ElAffix,
ElAlert,
ElAutocomplete,
ElAvatar,
ElBacktop,
ElBadge,
ElBreadcrumb,
ElBreadcrumbItem,
...
] as Plugin[]

这个配置给我的启示就是在我们的项目中,可以通过这种方式对我们需要使用的组件进行再声明,限制使用范围,以减少编译后的资源占用,如下图所示

见贤思齐——从Element Plus UI 源码中学到的技巧_复用_02


技巧二:icon组件示例

Element Plus UI 提供了非常多的icon,对于这些icon,如果需要一个个写得话,又要写很多重复的物料代码,这也太累了,人工搬砖,写文档,又得加不少班呀。对于有追求的程序员,当然要有想法了。处理技巧:使用​​Composition API​​来改写组,还利用​​packages/hooks​​目录下抽取了几个可复用的 hooks,如​​useNamespace​​,以及读取icon中的​​iconProps​​,来对文件进行个性化配置。

<template>
<i :class="ns.b()" :style="style" v-bind="$attrs">
<slot />
</i>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { addUnit, isUndefined } from '@element-plus/utils'
import { useNamespace } from '@element-plus/hooks'
import { iconProps } from './icon'
import type { CSSProperties } from 'vue'

defineOptions({
name: 'ElIcon',
inheritAttrs: false,
})
const props = defineProps(iconProps)
const ns = useNamespace('icon')

const style = computed<CSSProperties>(() => {
if (!props.size && !props.color) return {}

return {
fontSize: isUndefined(props.size) ? undefined : addUnit(props.size),
'--color': props.color,
}
})
</script>

通过这种方式,可以极大的减少重复的工作量

技巧三:文档多语言

在项目中​​packages/utils/i18n.ts​​可以看到多语言文档的配置demo,

export const isKorean = (text: string) =>
/([(\uAC00-\uD7AF)|(\u3130-\u318F)])+/gi.test(text)

如果是需要中文支持,则把Unicode编码进行转换即可

技巧四:引入了 hooks 来优化 mixin

由于​​Vue3​​中仍然保留了​​mixin​​,我们可以在特定组件或者是全局使用​​mixin​​来复用逻辑,同时也引入了 hooks 来改善 mixin 存在的一些问题:

  1. 渲染上下文中公开的属性的来源不清楚。 例如,当使用多个​​mixin​​读取组件的模板时,可能很难确定从哪个​​mixin​​注入了特定的属性。
  2. 命名空间冲突。​​Mixins​​可能会在属性和方法名称上发生冲突

通过引入hooks来解决这两个问题

  1. 暴露给模板的属性具有明确的来源,因为它们是从 Hook 函数返回的值。
  2. Hook 函数返回的值可以任意命名,因此不会发生名称空间冲突。

参考资料

  1. https://github.com/element-plus/element-plus
  2. https://juejin.cn/post/6914598983205847053
举报

相关推荐

0 条评论