OpenDataV计划以分库的形式添加子组件,即把每个组件看成一个分库,分库有自己的依赖,并且项目本身的依赖只是针对框架的,所以我们每开发一个组件作为一个子库。接下来,我将带大家一步步详细开发一个数显组件。创建组件目录和文件进入组件库目录所有可拖动的组件都存放在src/resource/components目录下cdsrc/resource/components根据组件名创建目录默认组件目录当然是以组件名命名也可以根据自己的要求命名,组件可以放在components目录下,也可以放在它的子目录下。mkdirDigitalText创建组件所需的固定文件每个组件的必要文件包括vue文件xxx.vue、配置文件config.ts和导出文件index.ts。每个文件都有自己的用途。vue文件不用多说,是组件渲染的主体,导出文件的名字固定为index.ts,主要是导出组件的信息,供外部参考。配置文件主要是显示在编辑页面右侧的配置项,后面我们会细说。所以这里我们需要创建三个文件:DigitalText.vue、config.ts、index.ts我们已经创建了上面组件需要的文件,接下来我们需要初始化组件和初始化组件文件,因为我们的组件是基于引入了子库,所以需要初始化包。执行如下命令cdsrc/resource/components/Text/DigitalTextnpminit这里使用npm初始化包可以让我们选择填写一些数据。接下来我们先初始化组件文件DigitalText.vue,初始化最简单的组件数据DigitalDisplay
然后我们要初始化组件的配置文件config.tsimport{ComponentGroup,FormType}from'@/enum'importtype{PropsType}from'@/types/component'import{BaseComponent}from'@/resource/models'exportconstcomponentName='Digital'classDigitalComponentextendsBaseComponent{constructor(id?:string,name?:string,icon?:string){super({component:componentName,group:ComponentGroup.TEXT,name:name?name:'数字文本',id,width:100,height:30,icon})}}exportdefaultDigitalComponent这里要说明的地方:componentName是组件在项目中的注册名称,所以必须是唯一的,group就是对组件进行分组。这里的分组主要是展示在组件拖拽页面上。它的ComponentGroup类型是固定的,可以自己添加。显示位置如下:name为组件拖拽页面显示的名称,width和height为组件拖拽到画布上显示的初始大小。配置组件数据后,可以配置导出文件index.ts,主要导出组件名称、组件对象和配置项。importDigitalTextComponent,{componentName}from'./config'exportdefault{componentName,component:()=>import('./DigitalText.vue'),config:DigitalTextComponent}初始化此时我们的组件已经可以编辑了页面正常使用,我们来看看效果:在右边的编辑页面,我们可以看到有样式和属性。所有组件包括基本样式位置大小,包括组件的上下外边距、宽度和高度,属性包括公共属性。其中components和ComponentID是不能修改的,主要是为了展示,name是可以修改的,name属性主要是在layer上展示。名称修改后,修改后的名称会响应显示在图层上。这是最基本的组件,只能显示固定数据,不能配置。接下来,我们需要配置组件。组件配置项样式配置作为一个文本显示组件,最基本的字体相关的属性配置应该有的,比如字体,字体颜色,字体大小,字体宽度,配置项还是添加在配置文件中,继承自private基本组件类Attribute_styleclassDigitalTextComponentextendsBaseComponent{constructor(id?:string,name?:string,icon?:string){...}_style:PropsType[]=[{label:'fontsettings',prop:'font',children:[{prop:'color',label:'color',type:FormType.COLOR,componentOptions:{defaultValue:'skyblue'}},{prop:'fontSize',label:'字体大小',类型:FormType.NUMBER,componentOptions:{defaultValue:20}},{prop:'fontWeight',标签:'字体宽度',类型:FormType.FONT_WEIGHT,componentOptions:{defaultValue:200}},{prop:'fontFamily',标签:'字体',类型:FormType.FONT_STYLE,componentOptions:{默认值:'Arial'}}]}]}样式配置的格式已经定义。需要注意的是children下所有子项中的prop必须是html元素的css属性。具体的css属性名不在样式文件中。填写了,但是在js中对应的名字,这个可以在网上搜索:css3中文手册,类似如下:下面详细说说各个配置项的含义:label:配置的组名displayprop:唯一属性区分,该属性与同级其他配置不同children:该属性组下的配置项label:各属性名称prop:css属性值type:属性编辑时显示的组件类型,当前可显示的组件是固定的,类型在FormType中定义componentOptions:属性对应的配置项,不同类型的组件有不同的配置项,具体可以查看src/types/component.d.ts中的定义,所有配置都有defaultValue配置,as属性初始化时的默认值。配置完样式,我们再来看看编辑页面的效果:说清楚了样式的配置,接下来说说属性的配置。property配置的格式和style配置一致,还有一些小细节需要注意属性配置属性配置是继承私有变量_prop,配置格式同style,这里我们配置一个示例属性:classDigitalTextComponentextendsBaseComponent{constructor(id?:string,name?:string,icon?:string){......}_prop:PropsType[]=[{label:'dataconfig',prop:'dataconfig',children:[{prop:'data',label:'data',type:FormType.NUMBER,componentOptions:{defaultValue:100000,max:99999999,min:0}}]}]}格式这里就不解释了,这里我们使用数值类型,所以可以配置最大值和最小值。接下来就是使用vue文件中的属性配置了。属性不像样式。样式是html元素本身支持的,所以只要我们配置一下就可以生效,但是属性是组件独有的。应该生成什么属性?什么效果取决于我们自己的编写逻辑,所以配置属性后,我们在编辑页面只会看到属性显示和配置,而实际配置后,是没有效果的。具体效果我们在vue中实现。属性的使用首先我们需要添加一个类型定义文件,因为ts最基本的优势就是类型提示,而我们封装的组件基类是通用的,所以我们需要在每个组件中使用自己的属性类型定义,定义为如下://DigitalText/type.tsexportinterfaceDigitalType{dataconfig:{data:number}}为了准确提示,类型定义必须和属性配置一致。具体来说,children下的prop作为属性值,children外的prop作为属性key,可以对比一下type.ts中的配置和_prop的配置。组件的配置信息是从外部传入的,所以所有的组件都要接收外部数据,我们定义了固定的格式constprops=defineProps<{component:DigitalTextComponent}>()所有与组件相关的信息都会通过component传入,为了监听属性变化和类型提示,我们封装了一个钩子来减少每个组件中的公共处理。UseProp的用法如下:constpropChange=(prop:string,key:string,value:number)=>{console.log(prop,key,value)}const{propValue}=useProp(props.component,propChange)useProp接收三个参数,一个是component,主要是添加类型提示,所以这里也传入了一个泛型定义定义,就是我们在type.ts中定义的类型,另外两个参数是属性变化回调函数和样式改变回调函数。一般情况下,我们只需要处理属性变化回调,样式变化自动生效,所以基本不用处理,只有有特殊需求才处理。属性变化回调函数中有三个参数,prop对应属性配置中外层的prop值,key对应属性配置中children中的prop值,value为属性变化的值。最后我们的属性处理结果如下:./config'import{useProp}from'@/resource/hooks'import{DigitalType}from'./type'constprops=defineProps<{component:DigitalTextComponent}>()constpropChange=(prop:string,key:string,value:number)=>{if(prop==='dataconfig'&&key==='data'){data.value=value}}const{propValue}=useProp(props.component,propChange)复制代码constdata=ref(propValue.dataconfig.data)看看页面上的效果:上面我们使用属性回调来处理值变化responses,其实还有其他的处理方法。我们需要了解属性回调的基本要求是什么?主要是因为在编辑了相应的属性后,我们可以监听到组件的变化,并反馈给显示。同样的一点,可用的方法更多。直接使用props传递的属性值渲染模板中的数据'./config'从'@/resource/hooks'导入{useProp}从'./type'导入{DigitalType}constprops=defineProps<{component:DigitalTextComponent}>()const{propValue}=useProp(props.component)因为vue的响应式,props中的数据可以响应变化,所以我们可以直接在模板中使用,不需要任何监听。使用computed或watch来监控属性的变化和上面是一样的。Vue会自动帮我们处理响应式数据。只要使用vue的computedproperties或者watch,也可以监控属性的变化。{{data}}
属性变化回调的另一种使用方法{{data}}
属性更改回调接收任何参数,我们可以选择是否接收参数。在一些配置项比较多的组件中,我们不想在属性回调中一个一个判断变化的属性,可以使用这个方法。在这种方式中,我们只是将属性回调作为一个通知,即通知我们属性发生了变化,而我们并不关心是哪个属性发生了变化,只修改所有的属性即可。虽然听起来很麻烦,但是在一些复杂的组件这里确实非常有用。我们需要明白,只要属性发生变化,prop中的数据也必然发生变化,所以我们总是获取prop中最新的数据。综上所述,添加一个组件的整个过程就完成了。按照目前的开发进度,基本上所有的部分都已经覆盖了。如果有人在使用过程中发现问题或者不够清楚,可以在项目的issue中提及,也可以通过其他方式进行反馈。加微信公众号获取更多资讯: