好的,所以我甚至不知道我是否正在遵循适当的MVC模式,但我有两个元素用于我的默认页面,我分成两个单独的元素文件,我的顶部导航栏和一个登录窗口。我这样做是为了帮助维护和升级这些元素更容易。每个文件都包含该元素外观和工作所需的html,css和javascript。
然而,当它们变得相互依赖时,问题就出现了。例如,导航栏的脚本标签中包含以下代码段:
$('#login-register-link').on('click', LoginWindow.show);
但LoginWindow.show
在LoginWindow元素中定义,该元素在导航栏后输出,导致未定义的错误。
我如何在逻辑上解决这个问题?我的意思是我知道我可以将这一行放在loginwindow元素中,但这不是正确的编程,因为loginwindow不应该知道什么是使用它。有关打破这些元素以及如何解决依赖性问题的正确方法的任何提示吗?
答案 0 :(得分:2)
首先,不要输出内联JavaScripts。收集您的脚本并将其输出到页面的末尾。
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>
您非常具体地说明应该使用哪个链接来打开登录窗口。什么(例如)我想添加第二个链接? (例如欢迎!要注册此站点,请访问“此”链接。)
在大多数情况下,最好减少HTML中的ID数量,不要依赖它们,除非绝对必要。它是 true ,JavaScript中的“ID”选择器比其他选择器更快,但差异是可以忽略的,除非您的页面非常大。
此外,使用事件委托('冒泡');这样做可以减少附加到您网站的事件监听器数量(速度更快,内存更少), 允许您设置单个监听器>即使是动态添加的内容。
对于您的示例,在“LoginWindow”元素中输出JavaScript,并通过发送“click”事件使登录窗口“可用”到其他元素。但只有如果这些元素有一个 'target-login-window'类;
//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标题并开始设置它们,除非被告知要这样做),但是,这只是一个意见问题:)
答案 1 :(得分:0)
在文档准备就绪后注册事件处理程序总是一个好主意,这在加载所有标记并获取任何链接资源之后发生。例如,使用jQuery,您将执行以下操作:
$(function(){
$('#login-register-link').on('click', LoginWindow.show);
});
这样,您可以确保LoginWindow
已添加到全局命名空间,无论它是在事件处理程序之前还是之后声明。
如果我是你,我可能会看一下像AngularJS这样的JavaScript MVC框架,因为它们有一些很好的UI信令模式可能对你有所帮助。我经历了类似的阶段,你意识到CakePHP约定不能很好地支持JavaScript开发。