在JS中使用PHP if/else是不好的做法



我正在为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>

虽然混合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)。例如

<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标记将来不会有太大变化时,我才会求助于这种检查。

现在几乎所有的浏览器都支持元素上的多个类。所以这意味着即使你有多个东西你想检查,只要它是有意义的,你可以把这些类放在你的htmlbody标签,并使用jQuery的Sizzle实现找到他们为你。

构建javascript服务器端可能是我们都做过的事情,尽管不这样做的主要争论-即js不能(容易地)验证(使用eg)。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都适合这种方法,但我认为问题中的例子将是。

在我看来,在这种情况下,这是一个可行的方法。

至少这不是优秀代码的标志。还有其他选择:

  • 生成一个JSON对象并在JavaScript中解析
  • 动态包含JS文件
  • Just set conditions:

    if(<?= (int)$mybool ?>) {
        doSomething();
    }
    

最新更新