作者:琼小海 | 来源:互联网 | 2023-09-11 12:45
基於svg寫了一個塗鴉組件,說項目之前先附上幾張結果圖:項目地點:SVGraffiti由於篇幅題目,本文先整體引見一下項目的也許狀況,重點引見一下組件間的通訊體式格局。一、項目申明
基於svg寫了一個塗鴉組件,說項目之前先附上幾張結果圖:
項目地點: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 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”等等與本項目相干的文章,寫得不好求親噴。
項目github地點:SVGraffiti
感興趣的同學們迎接star一同交換。