6

我正在为 WordPress 构建一个自定义模板,并且在几个地方我使用了 PHP if else 语句,例如页脚中的 JS 中的以下示例。它工作正常,但我想知道这是否被认为是“不好的做法”,如果是这样,有什么更好的方法来处理它?

<script type="text/javascript">
var $submenu = $('.submenu');
// SUBMENU animation
<?php if ( in_category('Collection') == false ) { ?> // if not a Collection subpage
    $('.menu li a').each(function() { 
        if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
            $(this).mouseenter(function() { 
                $submenu.slideDown(); 
            });
        } else { // else close submenu on hover over other menu links
            $(this).mouseenter(function() { 
                $submenu.slideUp(); 
            });
        }
    });
    $('.nav').mouseleave(function() { // close submenu
        $submenu.slideUp(); 
    });
<?php } else { ?> // If a Collection subpage always show subnav
    $submenu.show();
<?php } ?>
</script>
4

3 回答 3

2

虽然混合 PHP 和 JavaScript 并没有什么真正的问题,但我个人觉得阅读和修改很尴尬,而且移动代码也很棘手。例如,如果您决定将该 JavaScript 导出到外部文件,这有很多好处:

<script src="myjs.js.php"></script>

如果您的 JavaScript 需要知道某些值以便计算in_category('Collection'),因为您必须开始使用 GET 参数(除非您依赖会话变量,这可能会变得非常复杂和不可预测,尤其是通过资产请求),这会变得很笨拙:

<script src="myjs.js.php?random_vars_required=123"></script>

需要注意的另一点是,当 JavaScript 文件根据服务器端逻辑更改其内容时,您必须小心浏览器缓存的内容(为避免此类问题,这基本上意味着您必须更改js 文件的每个可能结果的请求 URL)。IE

<script src="myjs.js.php?collection=true"></script>
<script src="myjs.js.php?collection=false"></script>

另一个缺点是通过将 PHP 与 JS 混合使用,您最终可能会在许多地方复制 PHP 代码,这违反了 DRY 原则。这就是为什么建议的“将数据导出到 javascript 变量”是一个更好的主意的原因。但是,如果可能,最好避免使用全局 js 命名空间中的变量。如果您需要跨多个 JavaScript 文件共享逻辑并且不希望在每个文件的顶部导出变量,那么避免使用全局命名空间可能会很棘手。

另一种可能

如果您要测试的逻辑本质上是纯布尔型的,并且它也以页面分类(或子区域分类)为中心,那么以下是处理您要实现的目标的好方法。这很好,主要是因为它将您的 PHP 和 HTML 放在一起,而您的 JS 是分开的。

以下内容应放置在用于生成外部 HTML 的任何模板中:

<?php

    $classes = array();
    if ( in_category('Collection') ) {
      $classes[] = 'collection';
    }
    $classes = implode(' ', $classes);

?>
<!-- 
  obviously you'd render the rest of the html markup
  I've removed it for simplicity
//-->
<body class="<?php echo $classes; ?>"></body>

然后在你的 JavaScript / jQuery 中:

if ( $('body.collection').length ) {
  /// if collection sub page
}
else {
  /// else do otherwise
}

如果您不想向body元素添加类,则始终可以根据页面的一个版本而不是另一个版本上已经存在的内容来定义布尔检查。虽然我个人喜欢保持清洁,并且只有在我知道 HTML 标记在未来不会发生太大变化时才使用这些检查。

当今世界应该担心的几乎所有浏览器都支持元素上的多个类。所以这意味着即使你有多个想要检查的东西,只要有意义,你可以将这些类放在你的htmlorbody标记上,并使用 jQuery 的 Sizzle 实现来为你找到它们。

于 2013-04-03T22:37:48.340 回答
2

构建 javascript 服务器端可能是我们都做过的事情,尽管不这样做的主要论点 - 即 js 不能(容易)验证(例如 jsLint),也不能(容易)被放入 .js 文件中 - 允许浏览器仅缓存脚本的两个或多个可能版本之一是没有意义的。

您可以考虑将服务器端分支换成客户端分支,这可以说使代码更具可读性,但更重要的是,这是我最终建议的中间步骤(请耐心等待):

var $submenu = $('.submenu');
// SUBMENU animation
var isCollection = <?php echo in_category('Collection') ? 'false' : 'true' ?>;
if ( !isCollection ) { // if not a Collection subpage
    $('.menu li a').each(function() { 
        if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
            $(this).mouseenter(function() {
                $submenu.slideDown(); 
            });
        } else { // else close submenu on hover over other menu links
            $(this).mouseenter(function() {
                $submenu.slideUp(); 
            });
        }
    });
    $('.nav').mouseleave(function() { // close submenu
        $submenu.slideUp();
    });
} else { // If a Collection subpage always show subnav
    $submenu.show();
}

但是,如果布尔值isCollection可以通过其他方式确定(例如,通过查询 DOM 的某些方面,例如data-xxx属性),那么您就是在用煤气做饭。只需要一个版本的 js 脚本;它可以很容易地用 jsLint 进行验证;如果需要,可以移动到 .js 文件中。

当然,您需要data-xxx在服务器端代码的其他地方设置属性(或其他)(完整的解释性注释),这可能是一个缺点,但可能不是一个大问题。

也许不是所有的 js 都适合这种方法,但我认为问题中的例子是。

在我看来,这是一个可行的方法。

于 2013-04-03T23:00:37.777 回答
1

至少它不是伟大代码的标志。有替代方案:

  • 生成一个 JSON 对象并在 JavaScript 中解析它
  • JS文件的动态包含
  • 只需设置条件:

    if(<?= (int)$mybool ?>) {
        doSomething();
    }
    
于 2013-04-03T22:34:48.980 回答