0

好的,所以我什至不知道我是否为此遵循了正确的 MVC 模式,但是我的默认页面有 2 个元素,我将它们分成 2 个单独的元素文件、我的顶部导航栏和一个登录窗口。我这样做是为了帮助更轻松地维护和升级这些元素。每个文件都包含该元素看起来和正常工作所必需的 html、css 和 javascript。

然而,当它们相互依赖时,问题就出现了。例如,导航栏的脚本标签中有这个片段:

$('#login-register-link').on('click', LoginWindow.show);

但是LoginWindow.show在LoginWindow元素中定义,在导航栏后输出,导致未定义错误。

我该如何从逻辑上解决这个问题?我的意思是我知道我可以将这一行放在 loginwindow 元素中,但这是不正确的编程,因为 loginwindow 不应该知道使用它的任何内容。关于打破这些元素的正确方法以及如何解决依赖问题的任何提示?

4

2 回答 2

2

不要在整个页面中输出内联脚本块

首先,不要输出内联 JavaScript。收集您的脚本并在页面末尾输出它们。

CakePHP 提供了“缓冲”脚本的选项,并通过 JsHelper 一次性输出它们;

// Append the script to the JS-buffer
$this->Js->buffer('$("#login-register-link").on("click", LoginWindow.show);');

// At the end of your layout, output all collected scripts;
echo $this->Js->writeBuffer();

哪些输出;

<script>
    $(document).ready(function(){
        $("#login-register-link").on("click", LoginWindow.show);
    }
</script>

如果没有必要,不要依赖“ID”,使用事件委托

您非常明确应该使用哪个链接来打开登录窗口。如果我想添加第二个链接怎么办(例如)?(例如欢迎!要注册此站点,请访问“此”链接。)

在大多数情况下,最好减少 HTML 中的 ID 数量并且不要依赖它们,除非绝对必要。确实,JavaScript 中的“ID”选择器比其他选择器更快,但差异可以忽略不计,除非您的页面非常大。

事件委托(冒泡)

此外,利用事件委托(“冒泡​​”);这样做可以减少附加到您的站点的事件侦听器的数量(速度更快,内存消耗更少),并且允许您设置一个即使对于动态添加的内容也有效的侦听器。

对于您的示例,在“登录窗口”元素中输出 JavaScript,并通过发送“点击”事件使登录窗口对其他元素“可用”。但前提是这些元素具有“目标登录窗口”类;

//The links
<a href='/register' class='some classes and target-login-window'>Register here!</a>
<a href='/register' class='target-login-window'>Or use this link!</a>

//The script
//Note that the listener is attached to the <body> of your HTML
//but will only respond to clicks on an element that has a 'target-login-window'
//class.

//I picked the body here, but it's best practice to pick a 'wrapper' element
//on your page (e.g. an element that contains the relevant content)

$('body').on('click', '.target-login-window', LoginWindow.show); 

或者,使用 HTML5 的“数据”属性来指定链接的意图;

//The links
<a href='/register' data-target="login-window">Register here!</a>
<a href='/register' data-target="login-window">Or use this link!</a>

//The script
$('body').on('click', '[data-target="login-window"]', LoginWindow.show); 

一些额外的想法

初始化侦听器也可以移动到您的“LoginWindow”JavaScript 类。例如,这将使维护和从您的页面中删除该代码变得更容易;

LoginWindow.init = function (options) {
    // other initialization stuff
    // ....

    this.initListeners();
};

loginWindow.initListeners = function() {
    $('body').on('click', '[data-target="login-window"]', this.show); 
};

在您的页面上;

$this->Js->buffer('LoginWindow.init();');

有些人可能会提出,即使这部分代码 ( LoginWindow.init();) 也应该移动到外部 .js 文件中。

就个人而言,我并不总是喜欢这种方法。在大多数情况下,IMO 外部 JavaScript 文件应该是“被动的”,直到它们从页面主动初始化。

在我看来,页面本身应该始终处于控制之中(例如;javascript 不应该在我的页面上找到所有 h3 标题并开始设置它们的样式,除非被告知这样做),但同样,这只是一个问题观点 :)

于 2013-04-26T10:22:54.120 回答
0

一旦您的文档准备就绪,注册事件处理程序总是一个好主意,这发生在加载所有标记并获取任何链接资源之后。例如,使用 jQuery,您将执行以下操作:

$(function(){
    $('#login-register-link').on('click', LoginWindow.show);
});

这样,您可以确保LoginWindow已将其添加到全局命名空间,无论它是在事件处理程序之前还是之后声明的。

如果我是你,我可能会考虑像AngularJS这样的 JavaScript MVC 框架,因为它们有一些很好的 UI 信号模式可能会对你有所帮助。我经历了与您类似的阶段,您意识到 CakePHP 约定不能很好地支持 JavaScript 开发。

于 2013-04-26T10:18:49.857 回答