JavaScript - 使用后退按钮关闭弹出窗口

7
我有一个自定义的弹窗功能。我希望浏览器的返回按钮可以关闭此弹窗。
我的理想情况是在URL栏中不显示井号。
我尝试在我的showPopup()函数中放置window.history.pushState('forward', null, ''),然后执行以下操作:
$(window).on('popstate', function () {
    closePopup();
});

这种方法确实可行,但问题在于当我手动关闭弹出窗口时,我必须按两次后退按钮才能导航回上一页(显然是因为打开弹出窗口时添加了浏览器历史记录条目)。

有什么更好的方法吗?能否在不添加浏览器历史记录条目的情况下完成?本质上,我试图复制移动应用程序的行为。在移动应用程序中按返回按钮通常会关闭所有打开的模态或上下文菜单。

$('.popup-link').click(function() {
    showPopup();
});

$('.popup-close').click(function() {
    hidePopup();
});

function showPopup() {
    $('.popup').addClass('active');
}

function hidePopup() {
    $('.popup').removeClass('active');
}
.popup {
  background-color: #ccc;
  width: 300px;
  height: 300px;
  display: none;
}

.popup.active {
    display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="popup-link">Click</button>

<div class="popup">
    <button class="popup-close">x</button>
    <!-- popup content here -->
</div>


1
改变标准行为会给用户带来糟糕的体验。你为什么要这样做呢? - Adrian Brand
5
您可以认为这种“标准行为”是糟糕的用户体验,因为很多用户(尤其是移动应用程序用户)现在习惯于按返回键来关闭弹出窗口和提示框。 - MAX POWER
你会在争论一个不正确的观点。 - Adrian Brand
你所说的“手动关闭弹出窗口”是指使用类为popup-closeclose按钮来关闭弹出窗口吗? - pouyan
1
即使您的问题已经不存在或以其他方式得到解决,您也应该跟进所发布的答案。 - Munim Munna
显示剩余2条评论
8个回答

13

如果您无法覆盖浏览器后退按钮的行为,那么不添加浏览器历史记录条目就无法完成该操作,请参见在我的AJAX应用程序中拦截调用后退按钮:我不希望它执行任何操作

Sujumayas的答案是一个不错的选择,但您应该引入一些额外的变量以避免在打开多个弹出窗口时(例如单击多次按钮)出现历史记录问题。

以下是一些可能的示例代码:

let popupOpen = false;

$(".popup-link").click(function() {
    showPopup();
});

$(".popup-close").click(function() {
    window.history.back();
});

function showPopup() {
    if (popupOpen) {
        window.history.back();
    }
    popupOpen = true;
    window.history.pushState("forward", null, "");
    $(".popup").addClass("active");
}

function hidePopup() {
    popupOpen = false;
    $(".popup").removeClass("active");
}

$(window).on("popstate", function() {
    hidePopup();
});

此外请注意,您可能会在Opera Mini浏览器上遇到问题:https://caniuse.com/#search=history


@GSTAR 我认为这就是你要找的。 - Munim Munna

5
尽管我不建议您覆盖常规的浏览器历史记录管理(后退按钮),以便随心所欲地使用它...
我认为您在示例中唯一忽略的事情是关闭按钮不应该单独关闭模态框,而是执行一个后退按钮事件(最终将关闭模态框)。
只需进行这个简单的修复,它就能按照您所希望的工作。

请查看此处的帖子:https://ux.stackexchange.com/questions/100866/should-opening-a-modal-box-change-the-browser-history - user1031742

1
我已经在做类似的事情,并且它可以很好地与浏览器后退按钮和按下Android后退按钮一起使用。我也没有在URL栏中显示井号。
这是一个桩代码(我尝试将其应用到您的场景):
function freezeHistory() {
  window.history.pushState({}, window.document.title, window.location.href);
}

function goBack() {
  /*
    Custom history back actions: close panel, close popup, close drop-down menu
  */
  var popupOpen = $(".popup.active").length > 0;
  if(popupOpen) {
    hidePopup();
    return false;
  }
  window.history.back();
  return true;
}

function showPopup() {
  $('.popup').addClass('active');
  freezeHistory();
}

function hidePopup() {
  $('.popup').removeClass('active');
}

$(window).on("popstate", function(e) {
  /* 
     Browsers tend to handle the popstate event differently on page load. 
     Chrome (prior to v34) and Safari always emit a popstate event on page load, 
     but Firefox doesn’t.
  */
  goBack();
})

如果这对您来说无法直接使用,那是因为我认为您可能需要更清楚地说明如何管理页面历史记录。如果现在无法按照您的期望工作,请随时添加更多细节到您的问题中,但无论如何,我坚信您已经理解了这个想法,并且能够将其应用于您的Web应用程序场景中。

0

如果有人使用任何版本的Bootstrap,您可以使用此代码

let popupOpen = false;

//show
$(".popup-link").on('click',(function() {
        showPopup();
    })
);

// hide
$(".popup-close").on('click',(function() {
        window.history.back();
    })
);

// on click back button
$(window).on("popstate", function() {
      if (popupOpen) {
        hidePopup();
    }
});

// for bootstrap, if clicked outside the modal or close somehow
$(window).on('hidden.bs.modal', function(e) {
    // Make sure is open and the same modal
    if (e.target.id=='exampleModal' && popupOpen) {
        popupOpen = false;
        window.history.back();
    }
});

function showPopup() {
    // if open back 
    if (popupOpen) {
        window.history.back();
    }
    popupOpen = true;
    
    // push the browser history
    window.history.pushState("forward", null, "#popup");

    // you have to  use the id
    $("#exampleModal").modal('show');
}

function hidePopup() {
    popupOpen = false
    // you have to  use the id to close the modal
    $("#exampleModal").modal('hide');
}

0

你可以在popstate事件中添加window.history.go(-2)。这将使你回到两次,也就是你在模态框之前的原始页面,pushState会向你的历史记录对象中添加一个条目。

或者,你可以使用history.back(2) 使用window.location.href返回并重新加载前两页


0

打开弹出窗口,尝试使用浏览器历史按钮前进和后退

$(document).ready(function () {
    // manage popup state
    var poped = false;
    $('.popup-link').click(function () {
        // prevent unwanted state changtes
        if(!poped){
            showPopup();
        }
    });

    $('.popup-close').click(function () {
        // prevent unwanted state changtes
        if(poped){
            hidePopup();
        }
    });

    function showPopup() {
        poped = true;
        $('.popup').addClass('active');
        // push a new state. Also note that this does not trigger onpopstate
        window.history.pushState({'poped': poped}, null, '');
    }

    function hidePopup() {
        poped = false;
        // go back to previous state. Also note that this does not trigger onpopstate
        history.back();
        $('.popup').removeClass('active');
    }
});

// triggers when browser history is changed via browser
window.onpopstate = function(event) {
    // show/hide popup based on poped state
    if(event.state && event.state.poped){
        $('.popup').addClass('active');
    } else {
        $('.popup').removeClass('active');
    }
};
.popup {
            background-color: #ccc;
            width: 300px;
            height: 300px;
            display: none;
        }

        .popup.active {
            display: block;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="popup-link">Click</button>

<div class="popup">
    <button class="popup-close">x</button>
    <!-- popup content here -->
</div>


0
在关闭弹出窗口时,只需运行window.history.back()即可。
$('.popup-close').click(function() {
    hidePopup();
    window.history.back();
});

0

您有两个选项来实现这个:

选项1:使用window.beforeunload事件。参考

$('.popup-link').click(function() {
  showPopup();
  $(window).on("beforeunload", hidePopup);
});

$('.popup-close').click(hidePopup);

function hidePopup() {
  $(window).off("beforeunload", hidePopup);
  $('.popup').removeClass('active');
}

演示


选项2:使用HTML5历史记录API。参考资料

$('.popup-link').click(function() {
  showPopup();
  window.history.pushState('popup-open', null, '');
  $(window).on('popstate', hidePopup);
});

$('.popup-close').click(function() {
  if(history.state == 'popup-open')  {
    window.history.back();
  }
  hidePopup();
});

function hidePopup() {
    $(window).off('popstate', hidePopup);
    $('.popup').removeClass('active');
}

演示


编辑:sujumayas的想法也很不错。 演示

此外,我建议仅在必要时注册popstate / beforeunload事件,并在不再需要它们时注销它们,以避免开销。


选项1在控制台中生成“未捕获的RangeError:超过最大调用堆栈大小”的错误,因为它包含了“$(window).off("beforeunload", hidePopup);”这段代码。 - user874737

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接