When a user closes a
, hide that
on all

2019-01-25 01:28发布

问题:

I've developed a couple of alert boxes that display on all site pages.

The user is able to close each box separately:

$(document).ready(function() {
  $("#close-alert-box-news").click(function() {
    $("#alert-box-news").hide(800);
  });
  $("#close-alert-box-maintenance").click(function() {
    $("#alert-box-maintenance").hide(800);
  });
});
.alert-box {
  width: 50vw;
  position: relative;
  margin: 20px auto;
  border: 1px solid black;
}
.alert-box-close {
  position: absolute;
  top: -12px;
  right: -12px;
  cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>

<article class="alert-box" id="alert-box-news">
  <h1>News Alerts</h1>
  <p>text text text text text text text text text text text text text text</p>
  <a class="alert-box-close" id="close-alert-box-news">
    <img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
  </a>
</article>

<article class="alert-box" id="alert-box-maintenance">
  <h1>Site Maintenance</h1>
  <p>text text text text text text text text text text text text text text</p>
  <a class="alert-box-close" id="close-alert-box-maintenance">
    <img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
  </a>
</article>

jsFiddle

Now I need to make sure that the box the user closes (could be one, could be both), doesn't re-appear as he/she browses the site, or reloads a page.

I'm thinking I could set a PHP cookie to expire in 24 hours. But most of the related posts on this site recommend a JavaScript cookie. Unfortunately, my efforts to implement a JavaScript solution haven't worked (the boxes re-appear after being closed). I've tried various methods, as outlined here:

  • Set cookie to hide div when button is clicked
  • Set cookie when my div is hidden
  • jQuery Cookie hide/show div
  • Hide div 24hr cookie javascript?

What would be a simple method to hide each box, sitewide, for 24 hours?

I'm open to jQuery, plain JavaScript, PHP, cookies, sessions or something else.

回答1:

Use localStorage().

Local storage is per origin (per domain and protocol)

  • On click of DIV close, you can get the current time-stamp
  • Add number of hours (24) to that time-stamp
  • Store that value in localStorage as localStorage.setItem('desiredTime', time)
  • Check current time-stamp with that stored time-stamp localStorage.getItem('desiredTime'), based on that show/hide

jQuery

$(document).ready(function(){
        //Get current time
        var currentTime = new Date().getTime();
        //Add hours function
        Date.prototype.addHours = function(h) {    
           this.setTime(this.getTime() + (h*60*60*1000)); 
           return this;   
        }
        //Get time after 24 hours
        var after24 = new Date().addHours(10).getTime();
        //Hide div click
        $('.hide24').click(function(){
            //Hide div
            $(this).hide();
            //Set desired time till you want to hide that div
            localStorage.setItem('desiredTime', after24); 
        });
        //If desired time >= currentTime, based on that HIDE / SHOW
        if(localStorage.getItem('desiredTime') >= currentTime)
        {
            $('.hide24').hide();
        }
        else
        {
            $('.hide24').show();
        }
});

HTML

<div>DIV-1</div>
<div class='hide24'>DIV-2</div>

Things to note

  • You can use $.cookie as well, but that's an older approach now.
  • <div> with class hide24 will be hidden only.
  • Make sure that you put this code in general JavaScript, which loads on every HTTP request of your website.
  • For localStorage, you should have HTML5 browsers.

Web Storage HTML5

Hope this helps.



回答2:

Following on @Loading.. answer:

the alert boxes always re-appear briefly on reload before disappearing. Any ideas?


Why is this?

The functions inside $(document).ready() will execute until the entire DOM is loaded. That's why the alerts are rendered, then as soon as the function runs, it hides them.


Solution:

You can initially hide your alerts with a class just to take advantage that the browser won't render the content until the CSSOM has been built.

The class we are using is just setting the property display: none;.

.hidden {
  display: none;
}

This will of course cause redraw in the browser. (see notes)

Your logic is already showing the alert with

    if (localStorage.getItem('desiredTime') >= currentTime) {
      $('#alert-box-news').hide();
    } else {
      $('#alert-box-news').show();
    }

Because using .show() will add an inline-style display: block; it will have a higher specificity than the .hidden class, showing the alert.


jsFiddle


Notes:

  • Using display: none; will push the content below the alert up or down. You can use other methods if you like, like visibility: hidden; or transform which is not in the scope of this answer.

EDIT:

An illustration will be presented below doing the following steps:

  • Demo counter increased to 20 seconds for testing.
  • We click to dismiss the alert and trigger the localStorage function, setting the desiredTime key.
  • After the key has been set, we refresh the browser and hit run several times to see if the key is working.
  • Finally, just to check that the key is indeed being set, we go to:

    DevTools (F12) -> Application Tab -> Local Storage -> jsFiddle shell.

  • Run is hit one more time, after the countdown has finished, showing the alert again.

Illustration:


We might need further details to solve the issue with this approach if it is not working live.



回答3:

As far as I understand your question, hiding the alerts for 24 hours (and then subsequently showing them all again after a day) will be a bad user experience.

I assume you're loading these alerts from some sort of database. If so, the proper answer would be to store a status there. Whether it be a status column or a deleted_at timestamp, the implementations are endless.

Either way, I would store alert state in the database and filter your data when pulling accordingly.

Thus in your view you would have (assuming php here):

<?php

<?php if(!empty($newlyFilteredAlerts)): ?>
    <article class="alert-box" id="alert-box-news">
        <h1>News Alerts</h1>
        <?php foreach(newlyFilteredAlerts as $alert): ?>
            <p><?= $alert ?></p>
        <?php endforeach;?
        <a class="alert-box-close" id="close-alert-box-news">
          <img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt=""  >
        </a>
    </article>
<?php endif; ?>

Then you would accordingly want to add some sort of endpoint to alter that database status:

$(document).ready(function() {
    $("#close-alert-box-news").click(function() {
        $.post({
            url: '/alerts',
            type: 'DELETE',
            success: function () {
                $("#alert-box-news").hide(800);                    
            },
        });
    });
});

NOTE: This answer is meant to point you in the right direction, not write your code