【问题标题】:How to structure javascript when including another php file包含另一个php文件时如何构造javascript
【发布时间】:2013-03-20 18:26:42
【问题描述】:

我正在尝试构建一个小型 Web 应用程序,但我不清楚如何在页面的不同部分之间进行通信。我将使用我的特定功能来演示我的问题。

我的所有页面都使用通用工具栏。由于此工具栏在多个页面上使用,因此它位于其自己的 PHP 文件中,我将其包含在使用

<?php include("../toolbar.php"); ?>

工具栏包括一个登录按钮。单击后,将打开一个模式登录对话框(在本例中为 Facebook 登录对话框)。当用户登录时,他或她的名字会显示在工具栏中,并且登录按钮被一个“注销”按钮所取代。由于无论用户正在查看哪个页面,此行为都是相同的,因此我创建了一个工具栏.js 文件来显示登录模式并适当地更新用户名/按钮。

但是,在大多数页面上,从工具栏登录或退出也需要更新主页的内容。我不能保证每个包含toolbar.php的页面在登录状态发生变化时都必须做任何事情,但大多数都会做。

同样,反过来也是可能的——某个页面可能在工具栏外有一个“登录”按钮。使用时,工具栏需要更新。

处理这个问题的最佳方法是什么?

当前的实现 - 这可能很糟糕……

在toolbar.js 中,每当用户登录(以及注销的等效项)时,我基本上都会调用一个函数“userSignedIn”。 toolbar.js,它自己实现了这个(它需要更新它的按钮和用户名标签)。

然后,如果主页(我们称之为 mainPage.php)需要任何额外的东西,我将重新使用这个相同的功能来“附加”额外的操作。在加载该页面时,我执行以下操作:

var originalUserSignedIn = userSignedIn;
userSignedIn = function() {
    originalUserSignedIn();
    customUserSignedIn();
}

customUserSignedIn 是 mainPage.js 中的一个函数,我在其中执行其他操作。我还没有实现相反的解决方案(从mainPage.php登录需要更新toolbar.php)。

我猜我来自 Objective-C 背景,我正在尝试类似于在方法实现中调用“超级”的东西。

【问题讨论】:

  • 为什么不使用一个小工具包让您的生活更轻松?另外,我会将所有业务逻辑移动到保证加载的地方。
  • 谢谢。不幸的是,我对工具包或分离业务逻辑知之甚少(一无所知)——愿意提供一些链接吗?

标签: php javascript web-applications architecture


【解决方案1】:

一种方法是在任何其他 javascript 之前初始化一个空数组以保存回调函数和调用它们的符号函数:

var userSignedInCallbacks = [];

var userSignedIn = function() {
    for (var i = 0; i < userSignedInCallbacks.length; i++) {
        userSignedInCallbacks[i]();
    }
}

然后,toolbar 和 main page js 都会将它们适当的回调添加到数组中:

userSignedInCallbacks.push(function() {
    // ...
});

最后,工具栏或主页中的登录操作都将调用userSignedIn()

【讨论】:

  • 这听起来很酷。我仍然习惯于可以像这样使用函数的想法(例如,放置在数组中)。谢谢 - 会试一试并报告。
  • 您甚至可以将回调作为函数的属性,因为函数是对象。例如,您可以使用var userSignedIn = function() { ... }; userSignedIn.callbacks = []。然后你只需引用 userSignedIn.callbacks 来引用数组。
  • 本,一个想法(在你原来的答案上)——这不是把我的两个组件结合得太紧了吗?例如,如果没有工具栏,就无法使用主页,因为它会尝试访问如果工具栏不被使用则不存在的 userSignedInCallbacks 数组?不是破坏交易,而是对您的想法感兴趣。
  • @BenPackard,您不应该将userSignedInCallbacksuserSignedIn 定义放在toolbar.js 中。将它们放在包含在每个页面中的标题组件中(或在每个可能有登录操作的页面中)——那么是否包含工具栏并不重要。
【解决方案2】:

您可以做到这一点的一种方法是使用publisher-subscriber 模式来处理页面中不同模块之间的通信,以便每个模块仅在事件接口上耦合。

我创建了一个非常简单的示例here。它不处理注销过程,但您仍然可以看到事情的结构。

HTML

<div id="toolbar">
    <button class="login">Login</button>
</div>

<div id="another-section">
    <button class="login">Login</button>
</div>

<div id="login-dialog">
     <button class="login">Do login!</button>
</div>

JS

//in EventBus.js
var EventBus = {
    subscribers: {},
    publish: function (eventName) {
        var args = Array.prototype.slice.call(arguments, 1),
            subscribers = this.subscribers[eventName] || [],
            i = 0,
            len = subscribers.length,
            s;

        for (; i < len; i++) {
            s = subscribers[i];

            s.fn.apply(s.scope, args);
        }

    },
    subscribe: function (eventName, fn, scope) {
        var subs = this.subscribers[eventName] = this.subscribers[eventName]  || [];
        subs.push({ fn: fn, scope: scope });
    }
};

//in toolbar.js
function Toolbar(el, eventBus) {
    var $el = this.$el = $(el),
        $loginButton = $('button.login', $el);

    $loginButton.click(function () {
        eventBus.publish('userWantsToLogin');
    });

    eventBus.subscribe('userLoggedIn', function () {
        $loginButton.html('Logout');
        //change button handlers to handle logout...
    });
}

//in another-section.js
function AnotherSection(el, eventBus) {
    var $el = this.$el = $(el),
        $loginButton = $('button.login', $el);

    $loginButton.click(function () {
        eventBus.publish('userWantsToLogin');
    });

    eventBus.subscribe('userLoggedIn', function () {
        $loginButton.html('Logout');
        //change button handlers to handle logout...
    });
}

//in main.js
$(function () {
    var $loginDialog = $('#login-dialog');

    $loginDialog.dialog({ autoOpen: false});

    $('button.login', $loginDialog).click(function () {
        EventBus.publish('userLoggedIn');
    });

    EventBus.subscribe('userWantsToLogin', function () {
        $loginDialog.dialog('open');
    });

    new Toolbar('#toolbar', EventBus);
    new AnotherSection('#another-section', EventBus);
});

【讨论】:

  • 谢谢 plalx。我正在慢慢消化这个,需要吸收的东西很多。
  • 是的,我知道,呵呵,但值得付出努力;) 如果您寻找它,那里有很多库可以帮助您实现这一点。基本上,您的模块通过实现观察者模式的对象触发事件,并且它们监听他们关心的事件。在我的示例中,Toolbar 和 AnotherSection 模块有自己的登录按钮。单击它时,它们会通过EventBus 对象触发事件userWantsToLogin。应用程序侦听此事件并显示对话框,然后触发 userLoggedIn 事件,允许侦听模块更新其状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
相关资源
最近更新 更多