OpenDataV打算采纳子库的形式增加子组件,即每一个组件都当做一个子库,子库有本人的依赖,而我的项目自身的依赖只针对框架,因而每一个组件咱们都当做一个子库来开发。上面我带着大家一步步具体的开发一个数字展现组件。

创立组件目录和文件

  • 进入组件库目录下

所有的可拖拽组件都寄存在src/resource/components目录下

cd src/resource/components
  • 依据组件名称创立目录

默认组件目录是以组件的名称命名,当然也能够依据本人的要求命名,组件能够放在components目录下,也能够放在其子目录的目录下。

mkdir DigitalText
  • 创立组件所需的固定文件

每个组件必须的文件有vue文件xxx.vue、配置文件config.ts、导出文件index.ts,每个文件有本人的用途,vue文件不用说了是组件渲染的主体,导出文件名称固定为index.ts,次要是导出组件的信息给内部援用,配置文件次要是在编辑页面右侧展现的配置项,这个咱们前面再详述。所以这里咱们须要创立三个文件:DigitalText.vue、config.ts、index.ts

以上咱们就创立好了组件所需的文件,上面就须要做组件的初始化了

初始化组件文件

因为咱们的组件都是以子库的形式引入,所以须要进行包的初始化,执行以下命令

cd src/resource/components/Text/DigitalTextnpm init

这里应用npm初始化包会让咱们抉择填写局部数据。

上面咱们先初始化一下组件文件DigitalText.vue,先初始化最简略的组件数据

<template>  <div>数字展现</div></template><script lang="ts" setup></script><style lang="less" scoped></style>

而后咱们要初始化组件的配置文件config.ts

import { ComponentGroup, FormType } from '@/enum'import type { PropsType } from '@/types/component'import { BaseComponent } from '@/resource/models'export const componentName = 'Digital'class DigitalComponent extends BaseComponent {  constructor(id?: string, name?: string, icon?: string) {    super({      component: componentName,      group: ComponentGroup.TEXT,      name: name ? name : '数字文本',      id,      width: 100,      height: 30,      icon    })  }}export default DigitalComponent

这里要阐明的点:componentName是组件在我的项目中的注册名称,因而必须保障惟一,group是给组件分组,这里的分组次要是展现在组件拖拽页面,其类型的ComponentGroup是固定好的,能够本人减少,展现地位如下:

name是组件在拖拽页面上显示的名称,widthheight是组件拖拽到画布上显示的初始大小

配置完组件后数据后,就能够配置导出文件index.ts了,次要是导出组件名、组件对象和配置项。

import DigitalTextComponent, { componentName } from './config'export default {  componentName,  component: () => import('./DigitalText.vue'),  config: DigitalTextComponent}

初始化到这一步,咱们的组件曾经能够在编辑页面失常应用了,看一下成果:

在左边的编辑页面咱们看到有款式属性,所有的组件都蕴含根底款式地位大小,包含组件的上下边距和宽高,属性蕴含公共属性,其中组件组件ID无奈批改,次要是展现来看的,名称能够批改,名称属性次要是展现在图层上,批改名称后图层上会响应的显示批改后的名称。

这是最根底的组件,只能展现固定数据,不能进行任何配置,上面咱们要做组件的配置项。

组件配置项

款式配置

作为文字显示组件,最根底的字体相干属性配置应该要有,比方字体、字体色彩、字体大小、字体宽度,配置项仍然是在配置文件中增加,继承自根底组件类的公有属性_style

class DigitalTextComponent extends BaseComponent {  constructor(id?: string, name?: string, icon?: string) {......}  _style: PropsType[] = [    {      label: '字体设置',      prop: 'font',      children: [        {          prop: 'color',          label: '色彩',          type: FormType.COLOR,          componentOptions: {            defaultValue: 'skyblue'          }        },        {          prop: 'fontSize',          label: '字体大小',          type: FormType.NUMBER,          componentOptions: {            defaultValue: 20          }        },        {          prop: 'fontWeight',          label: '字体宽度',          type: FormType.FONT_WEIGHT,          componentOptions: {            defaultValue: 200          }        },        {          prop: 'fontFamily',          label: '字体',          type: FormType.FONT_STYLE,          componentOptions: {            defaultValue: 'Arial'          }        }      ]    }  ]}

款式配置的格局曾经定义好了,其中须要留神的是所有children下的子项中prop必须是html元素的css属性,具体的css属性名称并不是咱们在style文件中填写的,而是在js中对应的名称,这个能够在网上搜寻:css3 中文手册,相似如下:

咱们再详述一下各配置项的意义:

  • label:配置显示的分组名
  • prop:惟一的属性辨别,此属性要与同级别中的其余配置不同
  • children:此属性组上面的配置项

    • label:每个属性的名称
    • prop:css属性值
    • type:属性编辑时显示的组件类型,目前可显示的组件是固定的,类型都定义在FormType
    • componentOptions:属性对应的配置项,不同类型的组件有不同的配置项,具体能够在src/types/component.d.ts中查看定义,所有配置都有defaultValue配置,作为属性初始化时的默认值

配置完款式后,咱们在编辑页面看一下成果:

搞清楚了款式的配置,上面咱们再说说属性的配置,属性配置与款式配置格局统一,有一些小细节须要留神。

属性配置

属性配置是继承公有变量_prop,配置格局与款式雷同,咱们这里配置一个示例属性:

class DigitalTextComponent extends BaseComponent {  constructor(id?: string, name?: string, icon?: string) {......}  _prop: PropsType[] = [      {        label: '数据配置',        prop: 'dataconfig',        children: [          {            prop: 'data',            label: '数据',            type: FormType.NUMBER,            componentOptions: {              defaultValue: 100000,              max: 99999999,              min: 0            }          }        ]      }    ]}

格局这里就不解释了,这里咱们用到了数值类型,因而能够配置最大最小值。

接下来就是要在vue文件中应用属性配置了,属性不像款式,款式是html元素自身就反对的,因而只有咱们配置好,就能够失效了,然而属性是组件专有的,什么属性要产生什么成果全凭咱们本人书写逻辑,因而配置好属性咱们只会在编辑页面看到属性展现和配置,然而理论配置后是没有任何成果的,具体成果咱们在vue中实现。

属性应用

首先咱们要增加一个类型定义文件,因为ts最根底的劣势就是类型提醒,而咱们封装的组件基类是通用的,因而须要在每个组件中应用本人的属性类型定义,定义如下:

// DigitalText/type.tsexport interface DigitalType {  dataconfig: {    data: number  }}

为了精确的进行提醒,类型定义必须和属性配置始终,具体来讲就是children上面的prop作为属性值,children里面的prop作为属性键,能够比照一下type.ts中的配置和_prop的配置。

组件的配置信息是通过内部传入的,所以所有组件都必须接管内部数据,咱们曾经定义好了固定的格局

const props = defineProps<{  component: DigitalTextComponent}>()

组件相干的所有信息都将通过component传入进来,为了监听属性变动和类型提醒,咱们封装了一个hook,缩小每个组件中通用的解决,useProp的应用如下:

const propChange = (prop: string, key: string, value: number) => {  console.log(prop, key, value)}const { propValue } = useProp<DigitalType>(props.component, propChange)

useProp接管三个参数,一个是component,次要是为了增加类型提醒,所以这里也传入了一个泛型定义,就是咱们在type.ts中定义的类型,另外两个参数是属性变动回调函数和款式变动回调函数。个别状况下咱们只须要解决属性变动回调,款式变动是主动失效的,所以基本上不必解决,如果有非凡需要才须要。属性变动回调函数中有三个参数,prop对应的是属性配置中外层的prop值,key对应的是属性配置中children中的prop值,而value就是属性变动的值。

最终咱们的属性处理结果如下:

<template>  <div>{{ data }}</div></template><script lang="ts" setup>import { ref } from 'vue'import DigitalTextComponent from './config'import { useProp } from '@/resource/hooks'import { DigitalType } from './type'const props = defineProps<{  component: DigitalTextComponent}>()const propChange = (prop: string, key: string, value: number) => {  if (prop === 'dataconfig' && key === 'data') {    data.value = value  }}const { propValue } = useProp<DigitalType>(props.component, propChange)const data = ref<number>(propValue.dataconfig.data)</script><style lang="less" scoped></style>

看一下页面上的成果:

下面咱们用了属性回调去解决值变动响应,实际上还有其余的形式能够解决,咱们要明确属性回调的基本需要是什么?次要就是为了编辑了对应的属性后,咱们在组件内能监测到变动反馈到显示上。雷同这一点,可用的办法就多了。

  • 间接应用props传递的属性值在template中渲染数据
<template>  <div>{{ propValue.dataconfig.data }}</div></template><script lang="ts" setup>import DigitalTextComponent from './config'import { useProp } from '@/resource/hooks'import { DigitalType } from './type'const props = defineProps<{  component: DigitalTextComponent}>()const { propValue } = useProp<DigitalType>(props.component)

因为vue响应式的起因,props中的数据是能够响应变动的,那么咱们间接在template中应用即可,不须要做任何监测。

  • 应用computed或者watch监听属性变动

这里和下面是一样的情理,vue会主动帮咱们解决响应式数据,只有用vue的计算属性或者watch也能够监听到属性变动。

<template>  <div>{{ data }}</div></template><script lang="ts" setup>import { computed } from 'vue'import DigitalTextComponent from './config'import { useProp } from '@/resource/hooks'import { DigitalType } from './type'const props = defineProps<{  component: DigitalTextComponent}>()const { propValue } = useProp<DigitalType>(props.component)const data = computed<number>(() => {  return propValue.dataconfig.data})</script><style lang="less" scoped></style>
  • 属性变动回调的另一种用法
<template>  <div>{{ data }}</div></template><script lang="ts" setup>import { ref } from 'vue'import DigitalTextComponent from './config'import { useProp } from '@/resource/hooks'import { DigitalType } from './type'const props = defineProps<{  component: DigitalTextComponent}>()const propChange = () => {  data.value = propValue.dataconfig.data}const { propValue } = useProp<DigitalType>(props.component, propChange)const data = ref<number>(propValue.dataconfig.data)</script><style lang="less" scoped></style>

属性变动回调接管任何参数,咱们能够抉择接管参数,也能够不接管参数,在一些配置项比拟多的组件中,咱们不想在属性回调中去一个一个判断变动的属性,那么就能够应用这种形式,在这种形式中咱们只是把属性回调作为一个告诉,即告诉咱们属性发生变化了,而咱们不关怀哪一个属性产生了变动,把所有的属性都批改一遍即可,尽管听起来比拟麻烦,然而在一些简单组件中的确很有作用。在这里咱们要明确,只有属性产生了变动,那么prop中的数据也必然产生了变动,所以咱们随时取prop中的数据它都是最新的。

总结

到这里,一个组件的整个增加过程就讲完了,依据目前的开发进度来看,基本上所有的局部都讲到了,如果有人在应用过程中发现了什么问题或者有哪些地方不够分明的,能够在我的项目的issue中提,也能够通过其余形式反馈。

增加微信公众号理解更多信息: