我正在尝试在我的web应用程序中分离html和jQuery事件处理程序。这是我的上下文:我的网络应用程序适用于带有 ajax 加载内容的选项卡。每个选项卡内容都由唯一 ID 标识。在每个选项卡中,我都有一个表格。两个或多个标签页内容可以相同(例如,在 Chrome 中,同一个网站可以在两个标签页中加载)。在选项卡中,每个表行都可以通过单击 jQuery 初始化按钮进行编辑。
这是一个简化的示例,它目前是如何工作的:
智能模板
<div id="tabContent_{$uniqueId}">
<table>
{foreach $operations as $op}
<tr><td><button id="buttonEditOperation_${op}" /></td></tr>
{/foreach}
</table>
</div>
<script>
$('#tabContent_{$uniqueId} [id^="buttonEditOperation_"]')
.click( function() { alert('CLICK !'); })
.button(blabla);
</script>
当我加载具有相同内容的新选项卡时,由于选择器#tabContent_{$uniqueId}
仅初始化此新内容中的按钮
我想创建一个javascript文件来分离JS和我的SMARTY模板,但我不知道如何仅选择新加载选项卡的内容。我想要这样的东西:
智能模板
<script type="text/javascript" src="./js/buttonInit.js"></script>
<div id="tabContent_{$uniqueId}">
<table>
{foreach $operations as $op}
<tr><td><button id="buttonEditOperation_${op}" /></td></tr>
{/foreach}
</table>
</div>
JS 文件
<script>
$('#tabContent_?????? [id^="buttonEditOperation_"]') // HERE IS MY PROBLEM
.click( function() { alert('CLICK !'); })
.button(blabla);
</script>
我有一些想法(HTML5数据属性,初始化函数,全局变量等),但我想知道这个问题的最佳解决方案。
感谢您的反馈!
HTML和Javascript分开是一个好主意,但生成Javascript文件对于实现这一目标来说可能是矫枉过正的,而且维护起来也比应有的困难得多。
我发现的最好的方法是向 Smarty 添加简单的插件函数,以允许您生成与"小部件"相关的所有 HTML 和 Javascript,这些小部件在您的站点中多次出现。
这些插件函数应:
- 为小部件生成所有 HTML,这样您就不必在不同的 Smarty 模板之间重复 HTML。
- 生成小部件所需的所有Javascript,这样你就不必在Smarty模板中编写Javascript(这几乎总是一个坏主意 - 你应该只调用函数)。
- 将 Javascript 的生成与页面中的实际输出分开,以允许您控制 Javascript 的实际放置位置。
用于向 Smarty 添加函数的 PHP 代码
$GLOBALS['pageJavascript'] = array();
$smarty->registerPlugin("function", "addButton", "addButtonSmarty");
$smarty->registerPlugin("function", "displayPageJavascript", "displayPageJavascript");
//Outputs the HTML for a button, generates the associated Javascript and either
//outputs that Javascript or saves it for later.
function addButtonSmarty($params, &$smarty){
if(isset($params['operation']) == FALSE){
return "operation not set.";
}
if(isset($params['tabID']) == FALSE){
return "tabID not set.";
}
$tabID = $params['tabID']
$operation = $params['operation'];
$uniqueID = "buttonEditOperation_".$operation;
addButtonJavascript($tabID, $operation);
echo "<button id='buttonEditOperation_".$operation."' />";
}
function addButtonJavascript($tabID, $operation){
$javascript = "
$('#tabContent_".$tabID." [id^='"buttonEditOperation_".$operation."'"]')
.click( function() { alert('CLICK !'); })
.button(blabla);";
if(FALSE){
//You can just add the Javascript directly to the web page, however in this case
//it may throw an error if the user clicks on something before jQuery is
//fully loaded.
echo "<script type="text/javascript">";
echo $javascript;
echo "</script>";
}
else{
//Much better is to save the Javascript to be included later.
$GLOBALS['pageJavascript'][] = $javascript;
}
}
function displayPageJavascript(){
echo "<script type="text/javascript">";
foreach($GLOBALS['pageJavascript'] as $pageJavascript){
echo $pageJavascript;
echo "'n";
}
echo "</script>";
}
无论在哪里添加按钮,而不是直接添加按钮,请执行以下操作: {addButton tabID=$uniqueId operation=$op}
因此,您的 Smarty 模板如下所示:
聪明的模板
<script type="text/javascript" src="./js/buttonInit.js"></script>
<div id="tabContent_{$uniqueId}">
<table>
{foreach $operations as $op}
<tr><td>{addButton tabID=$uniqueId operation=$op}</td></tr>
{/foreach}
</table>
</div>
...
...
...
<!-- bottom of smarty template -->
{displayPageJavascript}
在有人跳进来说用PHP编写HTML和Javascript是丑陋的,不应该这样做之前 - 我完全同意!
然而,在这种情况下,在 Smarty 中将小部件编写为插件的好处超过了丑陋:
- 它使用于操作小部件的 Javascript 位于小部件的 HTML 的几行内,这使得编写和调试该小部件比将它们放在单独的文件中要容易得多。
- 在智能模板中隐藏小部件的实现,意味着您可以在一个地方更改一次它的实现,并确保该小部件的每次使用都会更新。
- 它使代码更加可靠,因为模板编辑器不必记住为他们添加的任何小部件单独添加 Javascript,因此在编辑模板时的错误会少得多。
请参阅下面我找到的最佳解决方案!如果我做错了什么,请随时告诉我......
智能模板
<script type="text/javascript" src="./js/object.Module.js"></script>
<script type="text/javascript" src="./js/object.Operation.js"></script>
<div id="tabContent_{$uniqueId}">
<table>
{foreach $operations as $op}
<tr><td>
<button id="buttonEditOperation_${op}" />
<span class="tooltip" title="Tooltip content">Show tooltip</span>
</td></tr>
{/foreach}
</table>
</div>
<script>
// Create a new object "Operation" which inherit from "Module"
var currentModule_{$uniqueId} = new Operation( {$uniqueId} );
// Use a method from main object "Module"
currentModule_{$uniqueId}.init_tooltips();
// Use a method from specific object "Operation"
currentModule_{$uniqueId}.init_buttonEditOperation('CLICK !');
</script>
主JS文件:"对象。模块.js"
var Module = function(_uniqueId) {
// Store the value of this in a different variable because jQuery
// override it when handling events
// (http://stackoverflow.com/questions/10596727/this-keyword-overriden-in-javascript-class-when-handling-jquery-events)
var self = this;
/* ========================================= */
/* PRIVATE ATTRIBUTE */
/* ========================================= */
// Initialized w/ arguments values when creating "object"
// (e.g. : var myVar = new Module("35d98q452e");
self.uniqueId = _uniqueId; // e.g. : "35d98q452e"
/* ========================================= */
/* PUBLIC METHODS */
/* ========================================= */
/*-------------------------------------
/* ---> Initialize tooltips */
self.constructor.prototype.init_tooltips = function() {
$( "#tabContent_" + self.uniqueId + " .tooltip" ).each(function(index) {
$(this).tooltip();
});
}
};
模块"操作"特定JS文件"对象。操作.js"
var Operation = function(_uniqueId) {
var self = this;
/* ========================================= */
/* INHERIT FROM PARENT OBJECT "Module" */
/* ========================================= */
Module.call(self, _uniqueId);
/* ========================================= */
/* PUBLIC METHODS */
/* ========================================= */
/*-------------------------------------
/* ---> Initialize button "Edit operation" */
self.init_buttonEditOperation = function(_msg) {
$('#tabContent_' + self.uniqueId + ' [id^="buttonEditOperation_"]')
.click( function() { alert(_msg); })
.button(blabla);
}
};