国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

設計一個基于svg的涂鴉組件(一)

cartoon / 3241人閱讀

摘要:基于寫了一個涂鴉組件,說項目之前先附上幾張效果圖項目地址由于篇幅問題,本文先總體介紹一下項目的大概情況,重點介紹一下組件間的通信方式。一項目說明該項目是基于構建的多頁應用,使用開發,以組件的方式組織代碼。

基于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 < 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”等等與本項目相關的文章,寫得不好求親噴。

項目github地址:SVGraffiti

感興趣的同學們歡迎star一起交流。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94972.html

相關文章

  • vue組件:canvas實現圖片涂鴉功能

    摘要:方案背景需求需要對圖片進行標注,導出圖片。對應方案用實現涂鴉圓形矩形的繪制,最終生成圖片編碼用于上傳大量圖片批量上傳很耗時間,為了提高用戶體驗,改為只實現圓形矩形繪制,最終保存成坐標,下次顯示時根據坐標再繪制。 方案背景 需求 需要對圖片進行標注,導出圖片。 需要標注N多圖片最后同時保存。 需要根據多邊形區域數據(區域、顏色、名稱)標注。 對應方案 用canvas實現涂鴉、圓形、...

    roland_reed 評論0 收藏0
  • STM32CubeMX學習教程之硬件I2C讀取光照度

    摘要:使用庫讀寫環境光照度傳感器本文將教大家如何快速使用庫讀取光照度數據。五實驗樣機測試展示通過之前配置好的面板,通過涂鴉智能進行配網實時采集光照度傳感器的數據。 使用STM32 HAL庫讀寫環境光照度傳感器(BH1750) 本文將教大家如何快速使用STM32HAL庫讀取光照度數據。 實現功能:通...

    tinylcy 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<