Как определить первый раз, когда пользователь входит в систему и при первой загрузке определенной страницы?

Я хотел бы вызвать некоторые JS только при первом входе пользователя в систему и только при первой загрузке определенной страницы.

Я считаю, что могу справиться с первым разом, когда они входят в систему, просто проверив user.sign_in_count < 2, но я не знаю, как указать только на первой странице загрузки.

т. е. я не хочу, чтобы JS запускался после входа пользователя в систему в первый раз и обновляет страницу без выхода из системы.

Я через Turbolinks и $(document).on('turbolinks:load', function() { в вызвать его.

изменить 1

Так что я пытаюсь сделать, это выполнить Ушко Тур на нескольких страницах. Но я хочу, чтобы этот тур был автоматически выполнен при загрузке первой страницы. Сам тур приведет пользователя к другим конкретным страницам в моем приложении, но каждая из этих страниц будет иметь конкретную страницу JS на каждой странице.

прямо сейчас, в моем HTML у меня есть что-то вроде этого:

<script type="text/javascript">
  $(document).on('turbolinks:load', function() {
      var tour = new Tour({
        storage: false,
        backdrop: true,
        onStart: function(){
        $('body').addClass('is-touring');
        },
        onEnd: function(){
        $('body').removeClass('is-touring');
        },
        steps: [
        {
          element: "#navbar-logo",
          title: "Go Home",
          content: "All throughout the app, you can click our logo to get back to the main page."
        },
        {
          element: "input#top-search",
          title: "Search",
          content: "Here you can search for players by their name, school, positions & bib color (that they wore in our tournament)"
        }
      ]});

      // Initialize the tour
      tour.init();

      // Start the tour
      tour.start();
  });
</script>

Так что все я действительно хочу сделать следующее:

  • не бомбардировать пользователя с выполнением нового тура, при первом входе в систему, всякий раз, когда они перезагружают страницу.
  • позвольте им иметь возможность вручную выполнить тур на более поздний срок, если они хотят, простым нажатием на ссылку.
  • я не хочу хранить что-либо в своей БД, если мне не нужно-поэтому предпочтительно это должен быть подход на основе файлов cookie или localStorage
  • предположим, что я буду использовать рельсы для отслеживания количество входа они сделали. Поэтому, как только они регистрируются более одного раза, я не могу вызвать этот JS.

реальная проблема только в этом первом входе, если они обновляют главную страницу 10 раз, этот тур выполняется 10 раз. Это то, что я пытаюсь остановить.

Я надеюсь, что это дает больше ясности.

8 ответов


предисловие

насколько я понимаю, у вас есть:

  1. несколько страниц, которые содержат один тур (Тур каждой странице разные)
  2. способ обнаружения первого входа в учетную запись (ruby login count)
  3. возможность добавлять script значение, основанное на первом signin

Обзор Решения

Решение ниже использует localStorage для хранения пары ключевых значений идентификатор каждого тура и, если он был замечен или нет. localStorage сохраняется между обновлениями страницы и сеансами, как следует из названия,localStorage является уникальным для каждого домена, устройства и браузера (т. е. в Chrome localStorage не удается получить доступ к firefox localStorage даже для того же домена, и chrome не может localStorage на вашем ноутбуке доступ к chrome localStorage на вашем мобильном телефоне даже для того же домена). Я поднимаю это, чтобы проиллюстрировать зависимость от предисловия 3 для переключения флага JS, если пользователь вошел в систему ранее.

для начала тура, проверяет код localStorage если соответствующая пара значений ключа не установлена в true (представляя, что был "замечен"). Если он существует и имеет значение true, тур не запускается, иначе он запускается. Когда каждый тур начинается, используя его onStart метод, мы обновляем / добавляем идентификатор тура в localStorage и установите его значение в true.

ручное выполнение тура может быть выполнено путем ручного вызова тура start метод, если вы хотите только тур текущей страницы для выполнения, в противном случае вы можете очистить все localStorage связанные с туром и отправить пользователя обратно на первую страницу/если вы находитесь на первой странице, снова просто позвоните start метод.

JSFiddle (HTML на основе другого вопроса, который вы задали относительно гастролей)

HTML-код (это может быть любой элемент с id="tourAgain" атрибут для следующего код для работы.

<button class="btn btn-sm btn-default" id="tourAgain">Take Tour Again</button>

JS

var isFirstLogin = true; // this value is populated by ruby based upon first login
var userID = 12345; // this value is populated by ruby based upon current_user.id, change this value to reset localStorage if isFirstLogin is true
// jquery on ready function
$(function() {
    var $els = {};  // storage for our jQuery elements
    var tour; // variable that will become our tour
    var tourLocalStorage = JSON.parse(localStorage.getItem('myTour')) || {};

    function activate(){
        populateEls();
        setupTour();
        $els.tourAgain.on('click', tourAgain);
        // only check check if we should start the tour if this is the first time we've logged in
        if(isFirstLogin){
            // if we have a stored userID and its different from the one passed to us from ruby
            if(typeof tourLocalStorage.userID !== "undefined" && tourLocalStorage.userID !== userID){
                // reset the localStorage
                localStorage.removeItem('myTour');
                tourLocalStorage = {};
            }else if(typeof tourLocalStorage.userID === "undefined"){ // if we dont have a userID set, set it and save it to localStorage
                tourLocalStorage.userID = userID;
                localStorage.setItem('myTour', JSON.stringify(tourLocalStorage));
            }
            checkShouldStartTour();
        }
    }

    // helper function that creates a cache of our jQuery elements for faster lookup and less DOM traversal
    function populateEls(){
        $els.body = $('body');
        $els.document = $(document);
        $els.tourAgain = $('#tourAgain');
    }

    // creates and initialises a new tour
    function setupTour(){
        tour = new Tour({
            name: 'homepage', // unique identifier for each tour (used as key in localStorage)
            storage: false,
            backdrop: true,
            onStart: function() {
                tourHasBeenSeen(this.name);
                $els.body.addClass('is-touring');
            },
            onEnd: function() {
                console.log('ending tour');
                $els.body.removeClass('is-touring');
            },
            steps: [{
                element: "div.navbar-header img.navbar-brand",
                title: "Go Home",
                content: "Go home to the main page."
            }, {
                element: "div.navbar-header input#top-search",
                title: "Search",
                content: "Here you can search for players by their name, school, positions & bib color (that they wore in our tournament)"
            }, {
                element: "span.num-players",
                title: "Number of Players",
                content: "This is the number of players that are in our database for this Tournament"
            }, {
                element: '#page-wrapper div.contact-box.profile-24',
                title: "Player Info",
                content: "Here we have a quick snapshot of the player stats"
            }]
        });
        // Initialize the tour
        tour.init();
    }

    // function that checks if the current tour has already been taken, and starts it if not
    function checkShouldStartTour(){
        var tourName = tour._options.name;
        if(typeof tourLocalStorage[tourName] !== "undefined" && tourLocalStorage[tourName] === true){
            // if we have detected that the tour has already been taken, short circuit
            console.log('tour detected as having started previously');
            return;
        }else{
            console.log('tour starting');
            tour.start();
        }
    }

    // updates localStorage with the current tour's name to have a true value
    function tourHasBeenSeen(key){
        tourLocalStorage[key] = true;
        localStorage.setItem('myTour', JSON.stringify(tourLocalStorage));
    }

    function tourAgain(){
        // if you want to tour multiple pages again, clear our localStorage 
        localStorage.removeItem('myTour');
        // and if this is the first part of the tour, just continue below otherwise, send the user to the first page instead of using the function below
        // if you just want to tour this page again just do the following line
        tour.start();
    }

    activate();
});

PS. причина, по которой мы не используем onEnd, чтобы вызвать tourHasBeenSeen функция заключается в том, что в настоящее время существует ошибка с bootstrap tour, где, если элемент последнего шага не существует, тур заканчивается без запуска onEnd обратного вызова, ошибка.


вы можете попробовать использовать Javascript sessionStorage, который удаляется, когда пользователь закрывает вкладку, но выживает через обновления. Просто используйте sessionStorage.setItem(key, value и sessionStorage.getItem(key). Запомните это sessionStorage можно хранить только строки!


Используя ваш код:
<script type="text/javascript">
  $(document).on('turbolinks:load', function() {
      var tour = new Tour({
        storage: false,
        backdrop: true,
        onStart: function(){
        $('body').addClass('is-touring');
        },
        onEnd: function(){
        $('body').removeClass('is-touring');
        },
        steps: [
        {
          element: "#navbar-logo",
          title: "Go Home",
          content: "All throughout the app, you can click our logo to get back to the main page."
        },
        {
          element: "input#top-search",
          title: "Search",
          content: "Here you can search for players by their name, school, positions & bib color (that they wore in our tournament)"
        }
      ]});
      if(sessionStorage.getItem("loggedIn") !== "yes"){//Remember that sessionStorage can only store strings!
        //Initialize the tour
        tour.init();
        // Start the tour
        tour.start();
      }
      else{
        //Set item "loggedIn" in sessionStorage to "yes"
        sessionStorage.putItem("loggedIn", "yes");
      }
      var goBackToTour = function(e){
        //You can also make a "fake" link, so that it looks like a link, but is not, and you don't have to put the following line:
        e.preventDefault();
        tour.init();
        tour.start();
      };
      document.getElementById("goBackToTourLink").addEventListener("click", goBackToTour);
  });
  //On the logout
  var logout = function(){
    sessionStorage.setItem("loggedIn", "no");
  };
</script>

для использования локального хранилища:

  if (typeof(Storage) !== "undefined") {
    var takenTour = localStorage.getItem("takenTour");
    if (!takenTour) {
      localStorage.setItem("takenTour", true);
      // Take the tour
    }
  }

мы используем это решение, потому что наши пользователи не войти, и это немного легче, чем, Используя cookies. Как упоминалось выше, он не работает, когда пользователи переключают машины или очищают кэш, но у вас есть это, покрытое вашим количеством входа.


вы можете хранить, если пользователь видел тур или нет в файле cookie. Вы можете поддерживать "TrackingCookie", который имеет всю информацию отслеживания пользователей (например. tour_shown, promotion_shown и т. д., к которым обращается ваш javascript код. Следующий код TrackingCookie должен поддерживать всю такую информацию отслеживания в одном файле cookie. Я называю это tracking_cookie.

cookies могут быть доступны на стороне сервера используя

cookies[:tracking_cookie]

tracking_cookie.js

var TrackingCookie = (function() {
  function TrackingCookie() {
    this.name = 'tracking_cookie';
    this.expires = new Date(new Date().setYear(new Date().getFullYear() + 1));
  }

  TrackingCookie.prototype.set = function(name, value) {
    var data={};
    if(!this.readFromStore()) {
      data = this.readFromStore();
    }
    data[name] = value;
    return this.writeToStore(data);
  };

  TrackingCookie.prototype.set_if_unset = function(name, value) {
    if (!this.get(name)) {
      return this.set(name, value);
    }
  };

  TrackingCookie.prototype.get = function(name) {
    return this.readFromStore()[name];
  };

  TrackingCookie.prototype.writeToStore = function(data) {
    return $.cookie(this.name, JSON.stringify(data), {
      path: '/',
      expires: this.expires
    });
  };

  TrackingCookie.prototype.readFromStore = function() {
    return $.parseJSON($.cookie(this.name));
  };

  return TrackingCookie;

})();

в HTML -

<script type="text/javascript">
  $(document).on('turbolinks:load', function() {
    //Instantiate the cookie
    var tracking_cookie = new TrackingCookie();
    //Cookie value not set means, it is a new user.
    if(!tracking_cookie.get("tour_shown")){
      //Set the value to be true.
      tracking_cookie.set("tour_shown",true)
      var tour = new Tour({
        storage: false,
        backdrop: true,
        onStart: function(){
        $('body').addClass('is-touring');
        },
        onEnd: function(){
        $('body').removeClass('is-touring');
        },
        steps: [
        {
          element: "#navbar-logo",
          title: "Go Home",
          content: "All throughout the app, you can click our logo to get back to the main page."
        },
        {
          element: "input#top-search",
          title: "Search",
          content: "Here you can search for players by their name, school, positions & bib color (that they wore in our tournament)"
        }
      ]});

      // Initialize the tour
      tour.init();

      // Start the tour
      tour.start();
    };

  });
</script>

класс cookie является многословным. Вы можете просто использовать $.cookie для достижения простого переключения поведения. Вышеуказанный код работает для всех пользователей в первый раз, вошедших в систему, а также вышедших из системы. Если вы просто хотите, чтобы он был зарегистрирован, установите флаг для входа пользователя на стороне сервера.


локальное хранилище не является кросс-браузерным решением. Попробуйте это кросс-браузерная реализация SQL который использует различные методы (включая localstorage) для хранения "баз данных" на жестком диске пользователей на неопределенный срок.

var visited;
jSQL.load(function(){
  // create a table
  jSQL.query("create table if not exists visits (time date)").execute();

  // check if the user visited
  visited = jSQL.query("select * from visits").execute().fetchAll("ASSOC").length;

  // update the table so we know they visited already next time
  jSQL.query("insert into visits values (?)").execute([new Date()]);

  jSQL.persist();
});

Это должно работать, если то, что вы хотите сделать ворота страницу своей жизни. Если необходимо предотвратить повторное выполнение в течение более длительных периодов, рассмотрите localStorage.

var triggered;
$(document).on('turbolinks:load', function() {
if (triggered === undefined) {
            triggered = "yes";
...code...
}}

основываясь на вашем комментарии, я думаю, вы захотите отслеживать это в своих данных (что фактически то, что вы делаете с user.sign_in_count > 1 Регистрация). Моя рекомендация заключалась бы в использовании легкого хранилища данных с ключом, такого как Redis.

в этой модели каждый раз, когда пользователь посещает страницу с этой функцией, вы проверяете значение "посетил", связанное с этим пользователем в Redis. Если он не существует, вы запускаете событие JS и добавляете "visited": true для Redis для этого пользователя, что предотвратит JS от запуска в будущем.


вам придется как-то связаться с бэкэндом, чтобы получить счетчик входа. Либо в введенной переменной, либо как маршрут json, который вы нажмете с помощью ajax, выполните логику:

if !session[:seen_tour] && current_user.sign_in_count == 1
  @show_tour = true
  session[:seen_tour] = true
else
  @show_tour = false
end

respond_to do |format|
  format.html {}
  format.json { render json: {show_tour: @show_tour } }
end

значения в сеансе будут сохраняться, однако вы настроили хранилище сеансов, которое по умолчанию хранится в файлах cookies.