自定义事件和Ajax友好的页面就绪检查

不久前,我构建了一个Chrome扩展程序,该扩展程序允许用户从Trello导出列表。 您可以在此处查看简短的系列文章。 不过,该扩展还有一些改进的余地。

例如,检查开发板是否已更改–考虑到所有Trello都是ajaxy,并且通过无法检测到的pushstate更改URL并非一件容易的事。 我们还希望它支持打开多个Trello选项卡,因此仅检查URL不会这样做。 如果我们能以某种方式确保缓慢的页面加载不会影响“页面就绪”状态,那也将是一件好事–在原始扩展中,由于Trello的“过分拥挤性”,页面在内容加载之前已经“就绪” –甚至通过Ajax加载板的区域,因此,将事件附加到Trello UI的核心DOM元素也不容易。

为此,为了使我将来为Trello开发扩展变得更加轻松,我决定构建TrelloUI库,该库将为我解决这个特定问题。 TrelloUI库将在将来扩展为具有其他功能,但是现在,让我们构建“就绪检查器”。

我们正在建设

我们将构建一个可从我们的Chrome扩展程序(或Firefox插件,如果您愿意的话)中调用的帮助程序库,该库允许我们将事件侦听器附加到事件trelloui-boardreadydocument对象上。 触发该事件后,我们将知道开发板已加载,并且可以将事件附加到开发板UI元素上。 最后,我们将通过为其他用例添加更多事件来改进它,以便我们可以广播将来想要的任何事件。

天线桅杆标志

我们将在Chrome扩展程序中将该库作为内容脚本进行测试。 您可以在全新版本的ChromeSkel_a (即开即用的骨架Chrome扩展程序)上或在上一个系列中构建的Trello Helper版本上进行测试

您只需要一个编辑器和一个激活了开发人员模式的Chrome(转到chrome:extensions并选中“开发人员模式”框)即可。

建立图书馆

让我们开始构建。 通过激活Chrome的开发模式并设置测试项目来准备环境。

内容脚本

Trello的客户端库需要jQuery,因此我们将其包含在我们的项目中。 下载最新副本 (最好是2+版本),并将其作为内容脚本包含在内。 创建一个名为trelloui.js的文件和另一个名为main.js的文件,然后也将它们包括在内。 您的内容脚本块应如下所示:

"content_scripts": [
        {
            "matches": ["https://trello.com/b/*"],
            "js": [
                "lib/jquery-2.1.1.min.js",
                "lib/TrelloUI/trelloui.js",
                "scripts/main.js"
            ],
            "run_at": "document_idle"
        }

您可以选择所需的文件夹结构–我喜欢将“库”放入“ lib”中,但这并不重要。

自举

trelloui.js ,我们首先创建一个新的“类”。

var TrelloUI = function () {};

这只是一个我们将使用一些方法属性扩展的功能。

检查结束状态

首先,让我们考虑一下结束状态– trelloui-boardready事件trelloui-boardready会被触发? 我们需要一种方法来检查电路板是否已加载并可见,然后通过事件让文档知道它是否发生了。 但是,我们需要确保一旦面板出现就停止检查,否则我们将一直运行一个间隔检查程序。 将以下内容添加到trelloui.js

TrelloUI.prototype._checkState = function () {
    return $('#board').hasClass('trelloui-boardready');
};

简单–我们添加了一个功能,用于检查board元素是否具有给定的类。 我们可以在事件触发后添加此类。 我们待会再做。 但是,一次检查该类并不会给我们带来太大的好处–我们需要继续检查是否要确保扩展功能在页面重新加载和面板更改后仍然存在。 让我们将以上内容更改为:

var TrelloUI = function () {
    setInterval(this._checkState.bind(this), 1000);
};

TrelloUI.prototype._checkState = function () {
    if (!$('#board').hasClass('trelloui-boardready')) {
        this._registerEvents();
    }
};

这利用了“构造函数”,在主代码中调用new TrelloUI ,我们使TrelloUI自动设置间隔来检查body元素是否包含我们每秒想要的类。 如果没有,我们调用_registerEvents (我们尚未编写的函数)来添加该类并在_registerEvents出现后立即调度该事件。

请注意,我们使用的是this._checkState.bind(this)而不是this._checkState因为在setInterval期间 this分离

建立一个新事件

您可以在有关创建自定义事件的详细阅读了这篇文章 。 在我们的示例中,我们将仅使用最基本的设置。 将构造函数更改为此:

var TrelloUI = function () {
    var eventDefaults = {
        bubbles: true,
        cancelable: true
    };

    this.possibleEvents = {
        boardEvent: new Event('trelloui-boardready', eventDefaults)
    };

    setInterval(this._checkState.bind(this), 1000);
};

我们使用eventDefaults设置了以后可能要定义的任何其他事件的默认值,因此我们不必重复自己。 气泡是指事件从触发其的元素到父元素的气泡。 如果用户愿意,可取消意味着可以使用event.stopPropagation将其停止。 这些标志目前对我们几乎没有任何意义,但它们是很好的默认设置。 然后,我们定义了一个内部possibleEvents它包含所有可能的事件我们的小实验可以调度的属性。

选项和构造函数

我们提到过以后可能要实现其他事件,因此,请确保它很容易实现:

var TrelloUI = function (options) {
    this._defaultOptions = {
        dispatchBoardReady: false
    };
    this.options = jQuery.extend({}, this._defaultOptions, options);

    var eventDefaults = {
        bubbles: true,
        cancelable: true
    };

    this.possibleEvents = {
        boardEvent: new Event('trelloui-boardready', eventDefaults)
    };

    setInterval(this._checkState.bind(this), 1000);
};

在这里,我们希望TrelloUI在董事会准备就绪时分派一个事件,但是我们考虑到了将来实现其他事件的潜在愿望。 但是默认情况下检查所有事件将占用大量资源。 (嗯,不是真的-实际上,除最弱的计算机外,所有计算机都可以成功处理所有这些,即使我们正在处理数百个计算机,但是当我看到网页和扩展程序占用2GB以上的RAM只是为了空闲时,我都会回避将资源视为理所当然。)

为了简单地合并设置和传递的选项,我们使用jQuery的extend

此设置使我们可以执行以下操作以使用TrelloUI:

var tui = new TrelloUI({
        dispatchBoardReady: true
    });

在这里,我们告诉TrelloUI实例化并密切注意可能触发boardReady事件的可能性。 如果我们不提供此选项,则构造函数中的默认值将阻止其尝试保存资源。

事件触发

火箭

最后,让我们构建事件触发功能。

TrelloUI.prototype._registerEvents = function () {

    var current = this;

    if (this.options.dispatchBoardReady) {
        var boardInterval = setInterval(function () {
            var board = $('#board');
            if (board && !$(board).hasClass(current.possibleEvents.boardEvent.type)) {
                document.dispatchEvent(current.possibleEvents.boardEvent);
                $(board).addClass(current.possibleEvents.boardEvent.type);
                clearInterval(boardInterval);
            }
        }, 100);
    }
};

让我们分解一下。 首先,我们别名this为一个局部变量,所以我们可以很容易地在下面封闭内使用。 然后,每100毫秒定义一个时间间隔,如果存在,则首先抓住该板元件。 如果是这样,并且如果正文仍然没有我们想要的类,则我们调度事件,添加类,并清除间隔。 否则,间隔会重复。

最后,让我们改进_checkState ,使其忽略该选项是否设置为false的检查:

TrelloUI.prototype._checkState = function () {
    if (this.options.dispatchBoardReady) {
        if (!$('#board').hasClass(this.possibleEvents.boardEvent.type)) {
            this._registerEvents();
        }
    }
};

其他活动

如果现在将以下内容添加到main.js脚本中,则应该可以将其加载到Chrome中,并在控制台中看到“板已准备就绪”:

var tui = new TrelloUI({
        dispatchBoardReady: true
    }
);

document.addEventListener('trelloui-boardready', function() {
    console.log("Board is ready!");
});

但是……对于我们从上一个系列开始的扩展而言,这仍然是不够的。 在那里,我们与列表进行交互。 并列出加载的板子。 显然,我们需要一个listsReady事件。

首先,我们在选项和可能的事件列表中添加一个新事件:

var TrelloUI = function (options) {
    this._defaultOptions = {
        dispatchBoardReady: false,
        dispatchListsReady: false
    };
    this.options = jQuery.extend({}, this._defaultOptions, options);

    var eventDefaults = {
        bubbles: true,
        cancelable: true
    };

    this.possibleEvents = {
        boardEvent: new Event('trelloui-boardready', eventDefaults),
        listsEvent: new Event('trelloui-listsready', eventDefaults)
    };

    setInterval(this._checkState.bind(this), 1000);
};

然后,我们通过添加以下代码块来更新_registerEvents

if (this.options.dispatchListsReady) {
        var listsInterval = setInterval(function() {
            var lists = $('.list');
            if (lists.length > 0 && !$(lists[0]).hasClass(current.possibleEvents.listsEvent.type)) {
                document.dispatchEvent(current.possibleEvents.listsEvent);
                $(lists[0]).addClass(current.possibleEvents.listsEvent.type);
                clearInterval(listsInterval);
            }
        }, 100);
    }

如果有列表,并且第一个列表还没有指示准备就绪的类,请调度事件并将该类添加到第一个列表。

最后,让我们通过添加一个新块_checkState再次调整_checkState

if (this.options.dispatchListsReady) {
        var lists = $('lists');
        if (!lists.length || !$(lists[0]).hasClass(this.possibleEvents.listsEvent.type)) {
            this._registerEvents();
        }
    }

实作

现在实现这些事件就像在主脚本中声明以下内容一样简单:

var tui = new TrelloUI({
        dispatchBoardReady: true,
        dispatchListsReady: true
    }
);

document.addEventListener('trelloui-boardready', function() {
    console.log("Board is ready!");
});
document.addEventListener('trelloui-listsready', function() {
    console.log("Lists are ready!");
});

每次您现在更换板子时,应将板子和清单准备就绪的情况通知您。 添加您的逻辑来代替console.log语句,并进行一些魔术!

结论

在这个简短的教程中,我们建立了一个简单的库来与Trello的UI进行交互–触发各种“就绪”事件的帮助程序,可以帮助我们检测何时“相邻”部分完成了加载,因此我们可以与它们进行正确的交互。

我们仍然可以做很多工作来改善这个“库” –例如,删除jQuery依赖关系,或者将_checkState_registerEvents相似的代码提取到可以在它们之间共享的代码中。 不过,就目前而言,它完全可以满足我们的需求-让我们知道Trello UI何时可以进行调整! 想要帮助吗? 欢迎在Github仓库上请求拉取!

From: https://www.sitepoint.com/custom-events-ajax-friendly-page-ready-checks/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值