如何检测用户首次登录以及第一次加载特定页面?

时间:2016-12-04 23:48:14

标签: javascript jquery ruby-on-rails ruby-on-rails-5 turbolinks

我想在用户第一次登录时触发一些JS,并且只在第一次加载特定页面时才会触发。

我相信我可以在他们第一次登录时处理,只需查看user.sign_in_count < 2,但我不知道如何仅在第一页加载时指定。

即。我不希望在用户首次登录后触发JS并刷新页面而不注销。

我正在使用Turbolinks和$(document).on('turbolinks:load', function() {触发它。

修改1

所以我要做的就是在许多页面上执行Bootstrap Tour。但我只希望在第一页加载时自动执行该游览。游览本身将引导用户访问我的应用程序中的其他特定页面,但每个页面将在每个页面上具有特定于页面的游览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
  • 假设我将使用Rails跟踪他们已完成的登录次数。所以一旦他们不止一次登录,我就无法触发这个JS。

真正的问题就在于第一次登录,如果他们刷新主页10次,这次巡演将被执行10次。这就是我想要阻止的事情。

我希望这能提供更多清晰度。

7 个答案:

答案 0 :(得分:12)

<强>前言

我的理解是你有:

  1. 包含单个游览的多个页面(每个页面的游览不同)
  2. 检测首次登录帐户的方式(ruby登录计数)
  3. 根据首次登录
  4. 添加script值的功能

    解决方案概述

    下面的解决方案使用localStorage来存储每个游览的标识符的键值对,以及是否已经看到它。页面刷新和会话之间存在localStorage,顾名思义,localStorage对于每个域,设备和浏览器都是唯一的(即Chrome localStorage无法访问firefox&#39 ; s localStorage即使是同一个域,也不能在您的笔记本电脑上使用chrome localStorage访问您手机上的Chrome localStorage,即使是同一个域名也是如此。我提出这一点来说明如果用户先前已登录,则依赖前言3来切换JS标志。

    要开始游览,代码会检查localStorage是否其相应的键值对未设置为true(表示已经&#34;看到&#34;)。如果它确实存在且设置为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 1}}回调,BUG

答案 1 :(得分:6)

您可以尝试使用Javascript的sessionStorage,当用户关闭标签时会将其删除,但会通过刷新生存。只需使用sessionStorage.setItem(key, valuesessionStorage.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>

答案 2 :(得分:4)

使用本地存储:

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

我们使用此解决方案是因为我们的用户没有登录,而且比使用cookie轻一点。如上所述,当用户切换机器或清除缓存时,它不起作用,但是您的登录计数会覆盖这些内容。

答案 3 :(得分:3)

如果用户在cookie中看过游览,您可以存储。你可以维持一个&#34; TrackingCookie&#34;它包含所有用户跟踪信息(例如,tour_shown,promotion_shown等,可通过您的javascript访问) 码。 TrackingCookie代码之后是将所有此类跟踪信息保存在一个cookie中。我称之为 tracking_cookie

可以使用

在服务器端访问Cookie

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即可实现简单的切换行为。以上代码适用于所有首次登录和登出的用户。如果您只想将其用于登录用户,请在服务器端的用户登录上设置标志。

答案 4 :(得分:2)

本地存储不是跨浏览器解决方案。试试这个cross browser SQL implementation使用不同的方法(包括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();
});

答案 5 :(得分:1)

根据您的评论,我认为您希望在数据中跟踪此信息(这实际上是您使用user.sign_in_count > 1检查所做的事情)。我的建议是使用像Redis这样的轻量级键值数据存储。

在此模型中,每次用户访问具有此功能的页面时,都会检查Redis中与该用户关联的“已访问”值。如果它不存在,则触发JS事件并为该用户添加"visited": true给Redis,这将阻止JS在将来触发。

答案 6 :(得分:1)

您将不得不以某种方式与后端进行通信以获得登录计数。无论是在注入变量中,还是在用ajax命中的json路径中,都要执行以下逻辑:

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

会话中的值将保持不变,但是您已配置会话存储,默认情况下存储在Cookie中。