可视化拖拽组件库一些技术要点原理分析(四)
本文是可视化拖拽系列的第四篇,比起之前的三篇文章,这篇功能点要稍微少一点,总共有五点:
- SVG 组件
- 动态属性面板
- 数据来源(接口请求)
- 组件联动
- 组件按需加载
- 可视化拖拽组件库一些技术要点原理分析
- 可视化拖拽组件库一些技术要点原理分析(二)
- 可视化拖拽组件库一些技术要点原理分析(三)
- 一个低代码(可视化拖拽)教学项目
- 在线 DEMO
用 SVG 画一个五角星
假设我们需要画一个 100 * 100 的五角星,它的代码是这样的:
svg 上的版本、命名空间之类的属性不是很重要,可以先忽略。重点是 polygon 这个元素,它在 svg 中定义了一个由
一组首尾相连的直线线段构成的闭合多边形形状
,最后一点连接到第一点。也就是说这个多边形由一系列坐标点组成,相连的点之间会自动连上。polygon 的 points 属性用来表示多边形的一系列坐标点,每个坐标点由 x y 坐标组成,每个坐标点之间用 ,
逗号分隔。文章图片
上图就是一个用 svg 画的五角星,它由十个坐标点组成
50 0,62.5 37.5,100 37.5,75 62.5,87.5 100,50 75,12.5 100,25 62.5,0 37.5,37.5 37.5
。由于这是一个 100*100 的五角星,所以我们能够很容易的根据每个坐标点的数值算出它们在五角星(坐标系)中所占的比例。譬如第一个点是 p1(50,0
),那么它的 x y 坐标比例是 50%, 0
;第二个点 p2(62.5,37.5
),对应的比例是 62.5%, 37.5%
...// 五角星十个坐标点的比例集合
const points = [
[0.5, 0],
[0.625, 0.375],
[1, 0.375],
[0.75, 0.625],
[0.875, 1],
[0.5, 0.75],
[0.125, 1],
[0.25, 0.625],
[0, 0.375],
[0.375, 0.375],
]
既然知道了五角星的比例,那么要画出其他尺寸的五角星也就易如反掌了。我们只需要在每次对五角星进行放大缩小,改变它的尺寸时,等比例的给出每个坐标点的具体数值即要。
文章图片
其他 SVG 组件
同理,要画其他类型的 svg 组件,我们只要知道它们坐标点所占的比例就可以了。如果你不知道一个 svg 怎么画,可以网上搜一下,先找一个能用的 svg 代码(这个五角星的 svg 代码,就是在网上找的)。然后再计算它们每个坐标点所占的比例,转成小数点的形式,最后把这些数据代入上面提供的
drawPolygon()
函数即可。譬如画一个三角形的代码是这样的:function drawTriangle(width, height) {
const points = [
[0.5, 0.05],
[1, 0.95],
[0, 0.95],
]const coordinatePoints = points.map(point => width * point[0] + ' ' + height * point[1])
this.points = coordinatePoints.toString() // 得出三角形的 points 属性数据
}
文章图片
动态属性面板 目前所有自定义组件的属性面板都共用同一个 AttrList 组件。因此弊端很明显,需要在这里写很多 if 语句,因为不同的组件有不同的属性。例如矩形组件有 content 属性,但是图片没有,一个不同的属性就得写一个 if 语句。
幸好,这个问题的解决方案也不难。在本系列的第一篇文章中,有讲解过如何动态渲染自定义组件:
在每个自定义组件的数据结构中都有一个
component
属性,这是该组件在 Vue 中注册的名称。因此,每个自定义组件的属性面板可以和组件本身一样(利用 component
属性),做成动态的:
同时,自定义组件的目录结构也需要做下调整,原来的目录结构为:
- VText.vue
- Picture.vue
...
调整后变为:
- VText
- Attr.vue
- Component.vue
- Picture
- Attr.vue
- Component.vue
现在每一个组件都包含了组件本身和它的属性面板。经过改造后,图片属性面板代码也更加精简了:
水平翻转
垂直翻转
这样一来,组件和对应的属性面板都变成动态的了。以后需要单独给某个自定义组件添加属性就非常方便了。
文章图片
数据来源(接口请求) 有些组件会有动态加载数据的需求,所以特地加了一个
Request
公共属性组件,用于请求数据。当一个自定义组件拥有 request
属性时,就会在属性面板上渲染接口请求的相关内容。至此,属性面板的公共组件已经有两个了:-common
- Request.vue
- CommonAttr.vue
// VText 自定义组件的数据结构
{
component: 'VText',
label: '文字',
propValue: '双击编辑文字',
icon: 'wenben',
request: { // 接口请求
method: 'GET',
data: [],
url: '',
series: false, // 是否定时发送请求
time: 1000, // 定时更新时间
paramType: '', // string object array
requestCount: 0, // 请求次数限制,0 为无限
},
style: { // 通用样式
width: 200,
height: 28,
fontSize: '',
fontWeight: 400,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: '',
},
}
文章图片
从上面的动图可以看出,api 请求的方法参数等都是可以手动修改的。但是怎么控制返回来的数据赋值给组件的某个属性呢?这可以在发出请求的时候把组件的整个数据对象
obj
以及要修改属性的 key
当成参数一起传进去,当数据返回来时,就可以直接使用 obj[key] = data
来修改数据了。// 第二个参数是要修改数据的父对象,第三个参数是修改数据的 key,第四个数据修改数据的类型
this.cancelRequest = request(this.request, this.element, 'propValue', 'string')
组件联动 组件联动:当一个组件触发事件时,另一个组件会收到通知,并且做出相应的操作。
文章图片
上面这个动图的矩形,它分别监听了下面两个按钮的悬浮事件,第一个按钮触发悬浮并广播事件,矩形执行回调向右旋转移动;第二个按钮则相反,向左旋转移动。
【可视化拖拽组件库一些技术要点原理分析(四)】要实现这个功能,首先要给自定义组件加一个新属性
linkage
,用来记录所有要联动的组件:{
// 组件的其他属性...
linkage: {
duration: 0, // 过渡持续时间
data: [ // 组件联动
{
id: '', // 联动的组件 id
label: '', // 联动的组件名称
event: '', // 监听事件
style: [{ key: '', value: '' }], // 监听的事件触发时,需要改变的属性
},
],
}
}
对应的属性面板为:
文章图片
组件联动本质上就是订阅/发布模式的运用,每个组件在渲染时都会遍历它监听的所有组件。
事件监听
从上述代码可以看出:
- 每一个自定义组件初始化时,都会监听
v-click
v-hover
两个事件(目前只有点击、悬浮两个事件) - 事件回调函数触发时会收到一个参数——发出事件的组件 id(譬如多个组件都触发了点击事件,需要根据 id 来判断是否是自己监听的组件)
- 最后再修改对应的属性
从上述代码可以看出,在渲染组件时,每一个组件的最外层都监听了
click
mouseenter
事件,当这些事件触发时,eventBus 就会触发对应的事件( v-click 或 v-hover ),并且把当前的组件 id 作为参数传过去。最后再捊一遍整体逻辑:
- a 组件监听原生事件 click mouseenter
- 用户点击或移动鼠标到组件上触发原生事件 click 或 mouseenter
- 事件回调函数再用 eventBus 触发 v-click 或 v-hover 事件
- 监听了这两个事件的 b 组件收到通知后再修改 b 组件的相关属性(例如上面矩形的 x 坐标和旋转角度)
第一步,抽离 第一步需要把所有的自定义组件出离出来,单独存放。建议使用 monorepo 的方式来存放,所有的组件放在一个仓库里。每一个 package 就是一个组件,可以单独打包。
- node_modules
- packages
- v-text # 一个组件就是一个包
- v-button
- v-table
- package.json
- lerna.json
第二步,打包 建议每个组件都打包成一个 js 文件 ,例如叫 bundle.js。打包好直接调用上传接口放到服务器存起来(发布到 npm 也可以),每个组件都有一个唯一 id。前端每次渲染组件的时,通过这个组件 id 向服务器请求组件资源的 URL。
第三步,动态加载组件 动态加载组件有两种方式:
import()
ctx.translate(width, 0)
这行代码的意思是把图片的 x 坐标往前移动 width 个像素,所以平移后,图片就刚好在画布外面。然后这时使用ctx.scale(-1, 1)
对图片进行水平翻转,就能得到一个水平翻转后的图片了。
文章图片
垂直翻转也是一样的原理,只不过参数不一样:
// 原来水平翻转是 ctx.translate(width, 0) ctx.translate(0, height) // 原来水平翻转是 ctx.scale(-1, 1) ctx.scale(1, -1)
实时组件列表
画布中的每一个组件都是有层级的,但是每个组件的具体层级并不会实时显现出来。因此,就有了这个实时组件列表的功能。
这个功能实现起来并不难,它的原理和画布渲染组件是一样的,只不过这个列表只需要渲染图标和名称。
{{ getComponent(index).label }}
但是有一点要注意,在组件数据的数组里,越靠后的组件层级越高。所以不对数组的数据索引做处理的话,用户看到的场景是这样的(假设添加组件的顺序为文本、按钮、图片):
文章图片
从用户的角度来看,层级最高的图片,在实时列表里排在最后。这跟我们平时的认知不太一样。所以,我们需要对组件数据做个reverse()
翻转一下。譬如文字组件的索引为 0,层级最低,它应该显示在底部。那么每次在实时列表展示时,我们可以通过下面的代码转换一下,得到翻转后的索引,然后再渲染,这样的排序看起来就比较舒服了。
{{ getComponent(index).label }}
文章图片
经过转换后,层级最高的图片在实时列表里排在最上面,完美!
总结 至此,可视化拖拽系列的第四篇文章已经结束了,距离上一篇系列文章的发布时间(2021年02月15日)已经有一年多了。没想到这个项目这么受欢迎,在短短一年的时间里获得了很多网友的认可。所以希望本系列的第四篇文章还是能像之前一样,对大家有帮助,再次感谢!
最后,毛遂自荐一下自己,本人五年+前端,有基础架构和带团队的经验。有没有大佬有北京、天津的前端岗位推荐。如果有,请在评论区留言,或者私信帮忙内推一下,感谢!
本人的社交主页:
- Github
- 知乎
- 掘金
推荐阅读
- react实战系列|react实战系列 —— react 的第一个组件
- unity3d|Character Controller角色控制器组件
- Unity总结|Unity实现玩家角色移动控制——CharacterController组件
- spring|【大型电商项目开发】分布式组件SpringCloud Alibaba简介Nacos&Feign-08
- Flutter|Flutter 日历组件简单实现
- 分布式二级缓存组件实战(Redis+Caffeine实现)
- vue2通用组件一次性注册
- 拓端tecdat|拓端tecdat|R语言复杂网络分析(聚类(社区检测)和可视化)
- 简单谈谈Angular中的独立组件的使用
- React组件应用于Spring|React组件应用于Spring MVC工程