摘要:基于寫了一個(gè)涂鴉組件,說項(xiàng)目之前先附上幾張效果圖項(xiàng)目地址由于篇幅問題,本文先總體介紹一下項(xiàng)目的大概情況,重點(diǎn)介紹一下組件間的通信方式。一項(xiàng)目說明該項(xiàng)目是基于構(gòu)建的多頁應(yīng)用,使用開發(fā),以組件的方式組織代碼。
基于svg寫了一個(gè)涂鴉組件,說項(xiàng)目之前先附上幾張效果圖:
項(xiàng)目地址:SVGraffiti
由于篇幅問題,本文先總體介紹一下項(xiàng)目的大概情況,重點(diǎn)介紹一下組件間的通信方式。
一、項(xiàng)目說明
該項(xiàng)目是基于[email protected]構(gòu)建的多頁應(yīng)用,使用ES6開發(fā),以組件的方式組織代碼。
git clone項(xiàng)目后(文末附上該項(xiàng)目github倉庫地址),npm i安裝相關(guān)依賴,npm run dev運(yùn)行項(xiàng)目,默認(rèn)會(huì)打開應(yīng)用的首頁,也就是上面的效果預(yù)覽對(duì)應(yīng)的界面。開發(fā)過程會(huì)多帶帶地為一些功能編寫一些測(cè)試代碼,所以該項(xiàng)目提供了不同的頁面對(duì)應(yīng)于不同的功能,比如:
color picker組件測(cè)試頁:
組件消息通信框架測(cè)試頁:
svg底層繪制api測(cè)試頁:
二、組件間通信
1、組件間為了實(shí)現(xiàn)最大程度的封裝與解耦,不直接進(jìn)行互相通信,而是通過“消息訂閱/發(fā)布管理中心”(以下簡稱“消息中心”)進(jìn)行間接通信。組件通過聲明自己為不同的角色從而擁有對(duì)應(yīng)的通信能力:
組件聲明為訂閱者(Subscriber)并通過@Topics注解的形式從“消息中心”訂閱自己感興趣的主題消息,對(duì)應(yīng)的消息會(huì)通過notify接口告知組件;
組件聲明為發(fā)布者(Publisher),可以通過Publisher角色注入的publish方法發(fā)布主題消息;
組件聲明為發(fā)布/訂閱者(SubScatterer),同時(shí)擁有訂閱者和發(fā)布者的通信能力。
這里以項(xiàng)目中的中間區(qū)域的畫板組件為例,因?yàn)楫嫲褰M件只是接收Toolbar組件發(fā)來的切換繪制能力、清空繪制內(nèi)容以及Settings組件發(fā)來的設(shè)置繪制參數(shù)信息,所以該組件只是一個(gè)消息訂閱者角色,編碼設(shè)計(jì)如下:
首先導(dǎo)入對(duì)應(yīng)的角色類:
import Subscriber from "../../supports/pubsub/base/subscriber"; import Topics from "../../supports/pubsub/base/topics";
編寫對(duì)應(yīng)的組件:
// 通過@Topics的形式訂閱感興趣的消息類型 @Topics(["function", "resident_function", "set_preference"]) export default class Sketchpad extends Subscriber { // 構(gòu)造器 constructor(sketchpad) { super(); this.sketchpad = sketchpad; // ... } /** * 該接口由【PubSub消息管理中心】負(fù)責(zé)調(diào)用,畫板組件在此接口處理接收到的消息類型 * 1、處理Toolbar組件發(fā)送的 “切換畫板繪制狀態(tài)” ,對(duì)應(yīng)的消息類型為:“function” * 2、處理Toolbar組件發(fā)送的 “清空繪制內(nèi)容” ,對(duì)應(yīng)的消息類型為:“resident_function” * 3、處理Settings組件發(fā)送的 “設(shè)置畫板繪制參數(shù)” ,對(duì)應(yīng)的消息類型為:“set_preference” * @param {String} topic 消息主題標(biāo)識(shí) * @param {Object} entity 消息實(shí)體對(duì)象 */ notify(topic, entity) { // 在此處理接收到的消息 } }
注:@Topics是靜態(tài)的,若有些主題是需要運(yùn)行時(shí)訂閱也可以調(diào)用Subscriber角色提供的subscribe方法動(dòng)態(tài)訂閱消息。
2、PubSub(消息訂閱/發(fā)布管理中心)的實(shí)現(xiàn)
既然是底層通用能力就一定要實(shí)現(xiàn)的不帶任何具體的業(yè)務(wù),無論是在命名規(guī)范還是編碼實(shí)現(xiàn)上都要保證它是一個(gè)通用模塊
PubSub的實(shí)現(xiàn):
/** * 主題訂閱發(fā)布中心 */ export default class PubSub { // 緩存主題和主題的訂閱者列表 static topics = {}; /** * 發(fā)布主題消息 * @param {String} topic 主題 * @param {*} entity 消息體 */ static publish(topic, entity) { if (!PubSub.topics[topic]) return; // 獲取該主題的訂閱者列表 const subscribers = PubSub.topics[topic]; // 向所有該主題的訂閱者發(fā)送主題消息 for (let subscriber of subscribers) { subscriber.notify && subscriber.notify(topic, entity); } } /** * 一次登記一個(gè)主題 * @param {String} topic */ static registerTopic(topic) { const topics = PubSub["topics"]; !topics[topic] && (topics[topic] = []); } /** * 同時(shí)登記多個(gè)主題 * @param {Array} topics */ static registerTopics(topics = []) { topics.forEach(topic => { this.registerTopic(topic); }); } /** * 添加主題訂閱者 * @param {String} topic 主題 * @param {Object} subscriber 實(shí)現(xiàn)了notify接口的訂閱者 */ static addSubscriber(topic, subscriber) { const topics = PubSub["topics"]; !topics[topic] && (topics[topic] = []); // 將該主題的訂閱者登記到對(duì)應(yīng)的主題 topics[topic].push(subscriber); } /** * 刪除對(duì)應(yīng)的訂閱者 * @param subscriber */ static removeSubscriber(subscriber) { const subs = []; // 遍歷所有主題下的訂閱者列表,將對(duì)應(yīng)訂閱者刪除 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的實(shí)現(xiàn):
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); } }
為了方便訂閱主題,再提供一個(gè)@Topics注解:
import PubSub from "../pubsub"; /** * 訂閱者主題裝飾器 * @param {Array} topics */ export default function Topics(topics) { return target => { target.topics = topics; PubSub.registerTopics(topics); } }
Publisher的實(shí)現(xiàn):
import PubSub from "../pubsub"; /** * 主題消息發(fā)布者 */ export default class Publisher { publish(topic, entity) { PubSub.publish(topic, entity); } }
SubScatterer的實(shí)現(xiàn):
import PubSub from "../pubsub"; import Subscriber from "./subscriber"; /** * 主題訂閱者 and 主題消息發(fā)布者 */ export default class SubScatterer extends Subscriber { publish(topic, entity) { PubSub.publish(topic, entity); } }
本篇介紹了項(xiàng)目的大概情況,重點(diǎn)分析了如何以發(fā)布/訂閱的形式實(shí)現(xiàn)組件間的通信,接下來還會(huì)抽時(shí)間寫幾個(gè)篇分別介紹“svg底層繪制能力的封裝”、“畫板不同繪制狀態(tài)的實(shí)現(xiàn)與管理”、“如何開發(fā)一個(gè)通用的ColorPicker”等等與本項(xiàng)目相關(guān)的文章,寫得不好求親噴。
項(xiàng)目github地址:SVGraffiti
感興趣的同學(xué)們歡迎star一起交流。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94972.html
摘要:方案背景需求需要對(duì)圖片進(jìn)行標(biāo)注,導(dǎo)出圖片。對(duì)應(yīng)方案用實(shí)現(xiàn)涂鴉圓形矩形的繪制,最終生成圖片編碼用于上傳大量圖片批量上傳很耗時(shí)間,為了提高用戶體驗(yàn),改為只實(shí)現(xiàn)圓形矩形繪制,最終保存成坐標(biāo),下次顯示時(shí)根據(jù)坐標(biāo)再繪制。 方案背景 需求 需要對(duì)圖片進(jìn)行標(biāo)注,導(dǎo)出圖片。 需要標(biāo)注N多圖片最后同時(shí)保存。 需要根據(jù)多邊形區(qū)域數(shù)據(jù)(區(qū)域、顏色、名稱)標(biāo)注。 對(duì)應(yīng)方案 用canvas實(shí)現(xiàn)涂鴉、圓形、...
摘要:使用庫讀寫環(huán)境光照度傳感器本文將教大家如何快速使用庫讀取光照度數(shù)據(jù)。五實(shí)驗(yàn)樣機(jī)測(cè)試展示通過之前配置好的面板,通過涂鴉智能進(jìn)行配網(wǎng)實(shí)時(shí)采集光照度傳感器的數(shù)據(jù)。 使用STM32 HAL庫讀寫環(huán)境光照度傳感器(BH1750) 本文將教大家如何快速使用STM32HAL庫讀取光照度數(shù)據(jù)。 實(shí)現(xiàn)功能:通...
閱讀 594·2021-11-22 14:45
閱讀 3086·2021-10-15 09:41
閱讀 1585·2021-10-11 10:58
閱讀 2807·2021-09-04 16:45
閱讀 2622·2021-09-03 10:45
閱讀 3252·2019-08-30 15:53
閱讀 1234·2019-08-29 12:28
閱讀 2146·2019-08-29 12:14