iT邦幫忙

0

[js] 點擊指定區域以外隱藏指定區域

假定navclick時顯示nav的選項,在click其他非nav區域時隱藏nav,目前看的大多是綁定bodydocument直接綁上click,在判定他是不是nav,不是就隱藏nav,像是這個,但感覺這樣每次click變得都會啟動bodyclick事件去判定,似乎不太好?有更好的解嗎?

5
fillano
iT邦超人 1 級 ‧ 2019-01-15 11:54:42
最佳解答

沒有更好的解。

而且並沒有好與不好,因為DOM的事件機制,原本就是會通過所有有註冊事件的相關節點。

DOM的事件分成兩個capturing跟bubbling兩個phase,例如:
http://jsfiddle.net/fillano/6aLd2zye/5/

點一下test按鈕,你會看到事件經過跟按鈕相關的所有節點,只要他有註冊同一個事件。capturing phase會由外層往內傳播(body->div->button),bubbling phase會由內往外層傳播(button->div->body)。

要影響這個過程,e.cancelBubble=true可以停止bubbling,e.stopPropagation()可以停止整個過程,包含capturing phase。要停止事件的預設動作,則使用e.preventDefault(),例如在拖拉時防止選取文字。

把事件綁在父節點上的做法,叫做delegation,他對於有許多子節點需要處理同樣事件的案例很有幫助,因為不這樣做,你就得一個一個綁上去。要綁在所有非nav節點比較容易,還是綁在body然後判斷不是nav比較容易?

0
Joe
iT邦新手 4 級 ‧ 2019-01-14 18:05:26
var isClosed = false;
$(document).ready(function () {
    var trigger = $('.hamburger'),
        pageContent = $('.page-content');

    pageContent.on("click", function (e) {
        var $target = $(e.target);
        var webHamburgerBtn = $('#Web_Hamburger_Btn');
        var menuPageSideBar = $('#menuPage-sideBar');

        if (menuPageSideBar !== $target && menuPageSideBar.has($target).length === 0 && webHamburgerBtn !== $target && webHamburgerBtn.has($target).length === 0) {
            if (isClosed === true) {
                hamburger_cross();
                $('.wrapper').toggleClass('toggled');
            }
        }
    });

    trigger.click(function () {
        hamburger_cross();
    });

    function hamburger_cross() {
        if (isClosed === true) {
            trigger.removeClass('is-open');
            trigger.addClass('is-closed');
            isClosed = false;
        } else {
            trigger.removeClass('is-closed');
            trigger.addClass('is-open');
            isClosed = true;
        }
    }

    $('[data-toggle="offcanvas"]').click(function () {
        $('.wrapper').toggleClass('toggled');
    });
});
Zaku iT邦新手 4 級 ‧ 2019-01-15 09:38:38 檢舉

感謝大大,不過pageContent跟body也差不多?幾乎有活動就會一直被觸發吧,依樣會一直判斷

0
youarefat
iT邦新手 5 級 ‧ 2019-01-15 09:57:08
$().on("focusout",handler);
或
$().focusout(...);

參考:https://api.jquery.com/focusout/

1
bizpro
iT邦大師 1 級 ‧ 2019-01-15 10:01:46

使用stopPropagation()停止往上散播事件:
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
例如:

$(document).bind('click', function(e) {  
  var e = e || window.event; //瀏覽器兼容性 
  e.stopPropagation();
  ....
bizpro iT邦大師 1 級 ‧ 2019-01-15 13:14:48 檢舉

另外, 就是e.preventDefault();和用程式碼判斷要處理的事件, 放過其他不相干的事件.

Zaku iT邦新手 4 級 ‧ 2019-01-23 14:50:41 檢舉

感謝大大,但看來還是避免不了要綁定整個區域$(document).bind('click'),還是所有click都會跑入判斷。不過好像不是很懂stopPropagation()的作用

0
浩瀚星空
iT邦高手 1 級 ‧ 2019-01-15 14:00:18

其實你想要的大約知道。只是很難辦到。

畢竟click事件,也是需要有一個元件來做判發的。
所以大多數很少人會去做點其它地方觸發。

就如msgbox雖然也是有點其它地方就關閉。但它的原理則是會在觸發視窗的同時,覆蓋一個透明或半透明的元件在全畫面上。方便處理點其它地方的事件。

上面的寫法,其實不外乎如下的做法

1.欄所有的click事件。
2.建立body的click事件。
3.建立document元件click事件

但無論任何方式,一個目標是無法避免的。就是你一定要達到點任意地方就要觸發。
如果無論如何都不能去避免這件事的話。建議還是乖乖的在body或是用dom的click事件處理吧。

1
froce
iT邦高手 1 級 ‧ 2019-01-15 16:10:43

有一種做法,就是把 nav 包在全螢幕的 wraper 裡。
展開 wraper 的時候,nav會一起展開。
也就是modal的作法。
https://getbootstrap.com/docs/4.1/components/modal/#live-demo

算是僅達成你想要的效果,但是轉個彎的作法。
真的要都如你所表達的話,就請參閱 fillano等寫的。

我要發表回答

立即登入回答