基于svg写了一个涂鸦组件,说项目之前先附上几张效果图:

项目地址:https://github.com/linmingdao/SVGraffiti

效果预览:

功能演示:

由于篇幅问题,本文先总体介绍一下项目的大概情况,重点介绍一下组件间的通信方式。

一、项目说明

该项目是基于webpack@3.x.x构建的多页应用,使用ES6开发,以组件的方式组织代码。 git clone项目后(文末附上该项目github仓库地址),npm i安装相关依赖,npm run dev运行项目,默认会打开应用的首页,也就是上面的效果预览对应的界面。开发过程会单独地为一些功能编写一些测试代码,所以该项目提供了不同的页面对应于不同的功能,比如:

color picker组件测试页:

组件消息通信框架测试页:

svg底层绘制api测试页:

二、组件间通信

1、组件间为了实现最大程度的封装与解耦,不直接进行互相通信,而是通过“消息订阅/发布管理中心”(以下简称“消息中心”)进行间接通信。组件通过声明自己为不同的角色从而拥有对应的通信能力:

  • 组件声明为订阅者(Subscriber)并通过@Topics注解的形式从“消息中心”订阅自己感兴趣的主题消息,对应的消息会通过notify接口告知组件;
  • 组件声明为发布者(Publisher),可以通过Publisher角色注入的publish方法发布主题消息;
  • 组件声明为发布/订阅者(SubScatterer),同时拥有订阅者和发布者的通信能力。

这里以项目中的中间区域的画板组件为例,因为画板组件只是接收Toolbar组件发来的切换绘制能力、清空绘制内容以及Settings组件发来的设置绘制参数信息,所以该组件只是一个消息订阅者角色,编码设计如下:

首先导入对应的角色类:

import Subscriber from '../../supports/pubsub/base/subscriber';
import Topics from '../../supports/pubsub/base/topics';
复制代码

编写对应的组件:

// 通过@Topics的形式订阅感兴趣的消息类型
@Topics(['function', 'resident_function', 'set_preference'])
export default class Sketchpad extends Subscriber {// 构造器constructor(sketchpad) {super();this.sketchpad = sketchpad;// ...}/*** 该接口由【PubSub消息管理中心】负责调用,画板组件在此接口处理接收到的消息类型* 1、处理Toolbar组件发送的 “切换画板绘制状态” ,对应的消息类型为:“function”* 2、处理Toolbar组件发送的 “清空绘制内容” ,对应的消息类型为:“resident_function”* 3、处理Settings组件发送的 “设置画板绘制参数” ,对应的消息类型为:“set_preference”* @param {String} topic 消息主题标识* @param {Object} entity 消息实体对象*/notify(topic, entity) {// 在此处理接收到的消息}
}
复制代码

注:@Topics是静态的,若有些主题是需要运行时订阅也可以调用Subscriber角色提供的subscribe方法动态订阅消息。

2、PubSub(消息订阅/发布管理中心)的实现 既然是底层通用能力就一定要实现的不带任何具体的业务,无论是在命名规范还是编码实现上都要保证它是一个通用模块

PubSub的实现:

/*** 主题订阅发布中心*/
export default class PubSub {// 缓存主题和主题的订阅者列表static topics = {};/*** 发布主题消息* @param {String} topic 主题* @param {*} entity 消息体 */static publish(topic, entity) {if (!PubSub.topics[topic]) return;// 获取该主题的订阅者列表const subscribers = PubSub.topics[topic];// 向所有该主题的订阅者发送主题消息for (let subscriber of subscribers) {subscriber.notify && subscriber.notify(topic, entity);}}/*** 一次登记一个主题* @param {String} topic */static registerTopic(topic) {const topics = PubSub['topics'];!topics[topic] && (topics[topic] = []);}/*** 同时登记多个主题* @param {Array} topics */static registerTopics(topics = []) {topics.forEach(topic => {this.registerTopic(topic);});}/*** 添加主题订阅者* @param {String} topic 主题* @param {Object} subscriber 实现了notify接口的订阅者*/static addSubscriber(topic, subscriber) {const topics = PubSub['topics'];!topics[topic] && (topics[topic] = []);// 将该主题的订阅者登记到对应的主题topics[topic].push(subscriber);}/*** 删除对应的订阅者* @param subscriber */static removeSubscriber(subscriber) {const subs = [];// 遍历所有主题下的订阅者列表,将对应订阅者删除const topics = PubSub.topics;Object.keys(topics).forEach(topicName => {const topic = topics[topicName];for (let i = 0; i < topic.length; ++i) {if (topic[i] === subscriber) {subs.push(topics[topic].splice(i, 1));break;}}});return subs;}
}
复制代码

Subscriber的实现:

import PubSub from '../pubsub';const addSubscribe = (topics = [], context) => {topics.forEach(topic => {PubSub.addSubscriber(topic, context);});
}/*** 主题订阅者*/
export default class Subscriber {constructor() {addSubscribe(this.__proto__.constructor.topics, this);}subscribe(topic) {PubSub.addSubscriber(topic, this);}
}
复制代码

为了方便订阅主题,再提供一个@Topics注解:

import PubSub from '../pubsub';/*** 订阅者主题装饰器* @param {Array} topics*/
export default function Topics(topics) {return target => {target.topics = topics;PubSub.registerTopics(topics);}
}
复制代码

Publisher的实现:

import PubSub from '../pubsub';/*** 主题消息发布者*/
export default class Publisher {publish(topic, entity) {PubSub.publish(topic, entity);}
}
复制代码

SubScatterer的实现:

import PubSub from '../pubsub';
import Subscriber from './subscriber';/*** 主题订阅者 and 主题消息发布者*/
export default class SubScatterer extends Subscriber {publish(topic, entity) {PubSub.publish(topic, entity);}
}
复制代码

本篇介绍了项目的大概情况,重点分析了如何以发布/订阅的形式实现组件间的通信,接下来还会抽时间写几个篇分别介绍“svg底层绘制能力的封装”、“画板不同绘制状态的实现与管理”、“如何开发一个通用的ColorPicker”等等与本项目相关的文章,写得不好求亲喷。

项目地址:https://github.com/linmingdao/SVGraffiti

感兴趣的同学们欢迎star一起交流。

设计一个基于svg的涂鸦组件(一)相关推荐

  1. 设计一个基于GUI的扑克程序

    2019独角兽企业重金招聘Python工程师标准>>> 在本课程教材扑克牌代码的基础上,设计一个基于GUI的扑克程序 a) 可以显示 52 张扑克牌,包括洗牌,发牌在内(2) b) ...

  2. 编程设计一个基于条件风险最小的Bayes分类器

    编程设计一个基于条件风险最小的Bayes分类器: 要求: 混淆矩阵维度可任意设定 先验概率基于训练样本集自动求得 样本属性数量可任意输入设定 朴素贝叶斯求条件风险最小公式: 训练数据集: 代码: im ...

  3. 设计一个基于用户的API限流策略 Rate Limit

    设计一个基于用户的API限流策略 Rate Limit 应用场景 API接口的流量控制策略:缓存.降级.限流.限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的.限流策略 ...

  4. 如何开发一个基于 Vue 的 ui 组件库

    如何开发一个基于 Vue 的 ui 组件库 开发模式 预览 demo 在开发一个 ui 组件库时,肯定需要一边预览 demo,一边修改代码. 常见的解决方案是像开发一般项目一样使用 webpack-d ...

  5. 基于PLC的升降横移立体停车库的设计,设计一个基于西门子S7-200 PLC控制核心的

    基于PLC的升降横移立体停车库的设计,设计一个基于西门子S7-200 PLC控制核心的,三层三列,九个车位的立体停车控制系统. 目录3 1 绪 论4 2 设计要求5 3 硬件设计8 3.1 PLC型号 ...

  6. 从0设计一个基于Redis的锁服务

    作者:温灏,后端研发,专注于Python和Go,对分布式系统感兴趣,本文系作者投稿,有兴趣投稿的同学,请后台回复[投稿] 由于微服务大行其道,服务之间的协调工作变得越来越重要.今天来简单说一下如何搭建 ...

  7. 如何设计一个基于SSM的旅游网站管理系统

    本文介绍一下最近开发的一套旅游网站,有前端页面和后台管理.希望对大家有帮助.本项目是基于Java语言的SSM框架作为后台进行设计,页面采用JSP,前端使用的是JS.CSS.JQUEY.BootStra ...

  8. 设计一个基于flask的高并发高可用的查询ip的http服务

    结构设计 基础架构为flask+gunicorn+负载均衡,负载均衡分为阿里云硬件负载均衡服务和软负载nginx.gunicorn使用supervisor进行管理. 使用nginx软件负载结构图 使用 ...

  9. 录制视频讲解,设计一个基于社交和大数据分析的智能家居系统

    基于社交网络和大数据分析的智能家居系统 摘要 智能家居是在互联网影响下的物联化的产物,本文阐述了一种基于微信和和大数据分析的智能家居的设计方案.为何要用微信?为何要用大数据分析?这两种技术相结合能为智 ...

最新文章

  1. Android:项目关联Library
  2. CLR Via C# 3rd 阅读摘要 -- Chapter 24 – Runtime Serialization
  3. exchange2010使用通配符造成的不停的需要输入密码却访问不了
  4. [BZOJ1502]月下柠檬树(自适应辛普森积分)
  5. mysql 查看锁_SQL-mysql锁等待与死锁
  6. 《Python Cookbook 3rd》笔记(2.14):合并拼接字符串
  7. 论文小综 | 文档级关系抽取方法(下)
  8. mysql查询语句 查询方式
  9. vmware ethx的修改
  10. 深度学习笔记(43) Siamese网络
  11. 开源软件公司易犯的 5 大错误,又该如何避免?
  12. JPDA 架构研究14 - Agent利用环境指针访问VM(对象管理篇)
  13. C++ 模板的全特化与偏特化
  14. php+psr4和自动加载,php自动加载规范 PSR4 (Thinkphp)
  15. 未找到依赖项 ‘org.apache.spark:spark-hive_2.11:2.4.5‘
  16. 代理猎手(Proxy Hunter)教程(详细图文)
  17. 3、FFmpeg 过滤器
  18. 计算机图形学课本pdf,计算机图形学教材.pdf
  19. Cadence 17.2( Allegro PCB ) 使用 Shape Symbol 制作不规则焊盘
  20. 【Ablation Studies 理解】深度学习模型组件的对比实验/性能分析

热门文章

  1. 简述bios在计算机系统中的作用,BIOS的主要作用
  2. php kint调试,PHP调试助手
  3. Java根据模板创建excel文件
  4. Java面试常被问到的题目+解答
  5. android通知栏打开actvity,Android实现点击通知栏后,先启动应用再打开目标Activity...
  6. WAVE SUMMIT平行论坛 :产教融合,人才共育
  7. 你们的竞赛更需要你们的参与
  8. 2021年春季学期-信号与系统-第十一次作业参考答案-第二小题
  9. 基于黄色LED反向电流的光电检测板
  10. BH60绝对位置编码器测试