0

所以我的 PHP 网站生成了如下所示的 DHTML 输出:

<div class="toggle-ctrl" onclick="toggleMenu();">
    click me to toggle menu
</div>
<div id="site-menu">
    <ul>
        <li>opt 1</li>
        <li>opt 2</li>
    </ul>
</div>
<p><a href="#">Link to Myself</a></p>

当然,当点击时,第一个 div 会调用一些 JavaScript 来切换site-menu

function toggleMenu() {
    var navigation_pane  = document.getElementById('site-menu').style;
    if ( navigation_pane.display == 'none' )
        navigation_pane.display = 'block';
    else
        navigation_pane.display = 'none';
}

这一切都很好。它正在点击现在困扰我的链接。单击它(当然)会创建一个新的 http 请求,并且我的 PHP 引擎会再次重新生成该页面。

当 的可见性为 时,就会出现site-menu问题'none'。PHP 引擎不知道菜单被隐藏,所以它再次生成相同的 html,并且浏览器将菜单放回看起来很惊讶的用户面前。

site-menu因此,问题是,在重新生成页面之前,我如何通知 PHP(或 PHP 如何检查) 的可见性状态是什么?

4

5 回答 5

2

因此,问题是,在重新生成页面之前,我如何通知 PHP(或 PHP 如何检查)站点菜单的可见性状态是什么?

它不能。当 HTML 被传送到浏览器时,PHP 已经不在图片中了。让 PHP 意识到这一点的唯一方法是在 URL 中发送一个参数来指示菜单已隐藏,或者设置一个 cookie 并让 cookie 指示对象的可见性。然后 PHP 可以检查该值是否存在,并在呈现 div 时设置它的可见性。

您可以通过多种方式完成此操作,例如:

  • 使用document.cookie在您的 toggleMenu 函数中设置 cookie。
  • 在 toggleMenu 函数中使用 ajax 通知 PHP 并让 PHP 设置 cookie 或会话值
  • 将标志附加到链接,指示来自 toggleMenu 函数的菜单的可见性。
于 2012-04-25T18:43:41.320 回答
2

除了将菜单状态发送到 PHP 脚本之外,至少还有两个选项。

  1. 使用 AJAX 仅加载页面的一部分。如果不重新加载菜单,则不需要重新初始化其样式。在走这条路之前,先检查一下AJAX 是否合适。如果您实施此解决方案,请不要破坏浏览器功能
  2. 现代浏览器支持存储机制。在菜单状态改变时存储菜单状态localStorage,并在页面加载时设置菜单状态。要支持旧版浏览器,您可以创建一个 API,该 API 在可用时使用 Web 存储,而在不可用时使用 cookie(jQuery.Storage 会这样做)。

    菜单.js:

    /* implementation of Storage, Class and addEventListenerTo left as 
       an exercise for the reader.
    */
    var Menu = {
        init: function(id, toggleId) {
            if (! toggleId) {
                toggleId = id + '-toggle';
            }
            var toggler = document.getElementById(toggleId),
                menu = document.getElementById(id);
            menu.toggler = toggler;
            /* addEventListenerTo should call the browser-supplied event subscriber 
               method (e.g. addEventListener or attachEvent)
            */
            addEventListenerTo(toggler, 'click', 
                function(evt) {
                    Menu.toggle(id);
                });
    
            if (! Storage.exists(id+'-open')) {
                Storage.set(id+'-open', true);
            }
    
            if (Storage.get(id+'-open')) {
                Menu.open(id);
            } else {
                Menu.close(id);
            }
        },
        toggle: function(id) {
            var menu = document.getElementById(id);
            Class.toggle(menu, 'open closed');
            if (Class.has(menu, 'open')) {
                menu.toggler.firstChild.nodeValue = 'close menu';
                Storage.set(id + '-open', true);
            } else {
                menu.toggler.firstChild.nodeValue = 'open menu';
                Storage.set(id + '-open', false);
            }
        },
        setState: function (id, toAdd, toRemove) {
            var menu = document.getElementById(id);
            Class.remove(menu, toRemove);
            Class.add(menu, toAdd);
        },
        open: function(id) {
            this.setState(id, 'open', 'closed');
        },
        close: function(id) {
            this.setState(id, 'closed', 'open');
        }
    };
    

    一些CSS文件:

    .closed { display: none; }
    

    页:

    <div id="site-menu-toggle" class="toggle-ctrl">close menu</div>
    <div id="site-menu" class="open">
        <ul>
            <li>opt 1</li>
            <li>opt 2</li>
        </ul>
    </div>
    <p><a href="#">Link to Myself</a></p>
    
    <script type="text/javascript">
    Menu.init('site-menu');
    </script>
    

    您可以在jsFiddle 上使用Menu.js方法的实时版本。使用 jQuery,您可以取消 Menu.js,从而实现更简洁的实现:

    <script type="text/javascript">
    $('#site-menu-toggle').click(function (evt) {
            var $menu = $('#site-menu');
            $menu.toggleClass('open close');
            $.Storage.set('site-menu-state', $menu.attr('class'));
            if ($menu.hasClass('open')) {
                $('#site-menu-toggle').text('close menu');
            } else {
                $('#site-menu-toggle').text('open menu');
            }
        });
    $(function() {
        var state = $.Storage.get('site-menu-state');
        if (! state) {
            $.Storage.set('site-menu-state', $('#site-menu').attr('class'));
        } else {
            $('#site-menu').attr('class', state);
        }
    });
    </script>
    

    有一个 jFiddle 用于 jQuery菜单状态实现,您可以使用它。

由于菜单状态的差异在概念上不会导致不同的资源,因此打开或关闭菜单是否可收藏或受历史影响并不重要。

注意。不要使用文本“ click me ”,它太冗长和多余(还有什么其他操作?应有的功能应该是隐含的。)。相反,您可以使用图形来指示打开/关闭,或者简单地说“打开菜单”/“关闭菜单”。

于 2012-04-25T19:18:37.223 回答
1

除了draw010 的建议:您还可以创建一个带有隐藏输入元素的表单,例如,'menu_status',其值由toggleMenu() 设置。然后,当您单击链接时,使用 javascript 发布或获取表单。然后,根据表单方法,使用$_POST["menu_status"]或使用 php 在服务器端读取值。$_GET["menu_status"]

更新:像这样的东西:

<form name="session_form" action="" method="POST">
    <input type="hidden" name="menu_state" value="block">
</form>

<?php $menu_state = isset($_POST["menu_state"]) ? $_POST["menu_state"] : "block"; ?>

<div id="site-menu" style="display:<?php echo $menu_state; ?>">
<ul>
    <li>opt 1</li>
    <li>opt 2</li>
</ul>
</div>

<p><a href="#" onClick="document.forms.session_form.submit();return false;">Link to Myself</a></p>

function toggleMenu() {
    var navigation_pane  = document.getElementById('site-menu').style;
    if ( navigation_pane.display == 'none' )
        navigation_pane.display = 'block';
    else
        navigation_pane.display = 'none';
    document.forms.session_form.menu_state.value = navigation_pane.display;
}

编辑:使用 jQuery ajax 可能涉及到这样的事情:

<div class="toggle-ctrl">click me to toggle menu</div>

<?php $menu_state = isset($_POST["menu_state"]) ? $_POST["menu_state"] : "block"; ?>

<div id="site-menu" style="display:<?php echo $menu_state; ?>">
<ul>
    <li>opt 1</li>
    <li>opt 2</li>
</ul>
</div>

<p><a href="#" id="go">Link to Myself</a></p>

$("div.toggle-ctrl").click(function(){
    $("#site-menu").toggle();
});

$("#go").click(function(e) {
    e.preventDefault();
    var menu_state = $("#site-menu").css("display");
    $.post("", {menu_state:menu_state}, function (response) {
        $("html").html(response);
    });
});

或者不使用 ajax 或表单,只需将参数附加到链接并在您的 php 中使用 $_GET 而不是 $_POST:

$("#go").click(function(e) {
    e.preventDefault();
    var menu_state = $("#site-menu").css("display");
    document.location.href = "index.php?menu_state=" + menu_state;
});

在我看来,这似乎是最简单的解决方案。

于 2012-04-25T18:49:16.580 回答
1

实际上,您的问题有几种类型的答案。

虽然听起来没有办法做你想做的事,但实际上有很多方法。

饼干

显而易见的。cookie 可以通过 javascript 和 PHP 访问。只要通过 javascript 显示/隐藏菜单时修改 cookie(有出色的 jQuery cookie 插件)。

表单输入

如果您正在提交表单,只需隐藏输入即可保持菜单可见性的值:

<input type="hidden" name="menu-visibility" value="0"/>

同样,您需要 javascript 来更新此输入。

更新页面的相关部分

这是 hip & leet 的新趋势。嗯,实际上,它已经存在了大约 6 年左右。基本上,不要提交任何东西,也不要重新加载页面。通过 AJAX 更新页面中实际需要更新的部分。

本地存储

正如@outis 所提到的,今天的浏览器有一些类似于 cookie 的东西,除了它们自己保存(因此是本地的)。这是一个相当新的功能,老实说,考虑到有更好的方法来完成你需要的东西,我不会相信它。

于 2012-04-25T19:19:18.953 回答
0

I know it's not cool to answer your own question, but another possible solution occurred to me last night, and it only requires 1 new line of code to be written (sort of).

The first part of the solution has already been implicitly suggested by many of you. Modify the JavaScript to write to a cookie:

function toggleMenu() {
    var navigation_pane  = document.getElementById('site-menu').style;
    if ( navigation_pane.display == 'none' )
        navigation_pane.display = 'block';
    else
        navigation_pane.display = 'none';
    document.cookie = "menu_vis=" + navigation_pane.display; // +1 line of code
}

Now, what are the possibilities if your CSS file just so happens to be a PHP file in disguise? my_css.php would look something like this:

<?php
header("Content-type: text/css");
?>
#site-menu {
    display: <?php echo isset($_COOKIE['menu_vis']) ? $_COOKIE['menu_vis'] : 'block'; ?>;  /* line of code modified, but not added! */
}

Tested this morning, and it works.

I find it a neat solution, because it means that I don't have to bend my PHP or HTML design around any presentational concerns.

-- I appreciate that there are more "encompassing" solutions out there. If I was a better JavaScript developer, (or made use of jQuery or the like), I could build more complicated classes which could then be applied more generally to other HTML elements. I may come back to investigate such solutions later, but that's just not where my project is at the moment.

Thank you everyone for all your replies. I wouldn't have found this solution without bouncing these ideas off you guys.

于 2012-04-26T09:21:04.537 回答