【问题标题】:Polymer core-menu double event聚合物芯-菜单双事件
【发布时间】:2014-07-22 11:15:27
【问题描述】:

我正在为我的网络应用程序使用Polymer,我目前在页面链接方面遇到了一些问题。这是我第一个使用所有 ajax/javascript 制作的网站,因此我还没有大量使用 javascript 的历史功能。

无论如何,我在左侧边栏中有一个主菜单。当其中之一被按下时,它应该更改浏览器的 url 并将其放入浏览器的历史记录中。为此,我有以下代码:

Polymer('my-app', {
    mainMenu: function(){
        this.$.mainPages.selected = this.$.mainMenu.selected;
        console.log("Pusing state " + this.$.mainMenu.selected);
        history.pushState(null , "title", this.$.mainMenu.selected);
    }
});

现在的问题是它被调用了两次,所以如果你点击一次 pushState 会被调用两次。不用说这不好。

我在这里做了一个示例代码:click me

在此示例代码中,您可以看到在按下几个菜单项后,首先会触发两次事件。我还注意到,当按下返回按钮时,更新页面似乎也会重新触发 pushState

简而言之,我的第一个担心是按下core-menu 中的元素的事件,mainMenu 函数被调用了两次。 第二个担忧是我在返回时会拒绝状态,我认为这也应该被阻止。

更新代码:

Polymer('my-app', {
    ready: function(){
        var link = document.URL.split("/");
        this.$.mainMenu.selected = link[link.length-1];
        console.log("ready with link: "+link[link.length-1]);
        window.onpopstate = function(){
            var link = document.URL.split("/");
            console.log("Calling onpopstate. New link is: "+link[link.length-1]);
            this.$.mainMenu.selected = link[link.length-1];
            this.$.mainPages.selected = this.$.mainMenu.selected;
        }
    },
    nav: function(){
        this.$.drawerPanel.togglePanel();
    },
    back: function(){
        window.history.back();
    },
    mainMenu: function(){
        console.log("Pusing state " + this.$.mainMenu.selected);
        this.$.mainPages.selected = this.$.mainMenu.selected;
        history.pushState(null , "title", this.$.mainMenu.selected);
    }
}

【问题讨论】:

    标签: javascript browser-history polymer


    【解决方案1】:

    使用数据绑定会好得多。这里的想法是让您的元素模型驱动,模型-视图-呈现器 (MVP) 模式。模型由元素中的属性组成,视图由模板描述,演示者在脚本中。数据绑定允许我们将视图与逻辑松散耦合。

    让我们决定当前页面将由一个名为page 的属性控制。

    然后我们可以将我们的 UI 设置为由 page 属性驱动:

      <core-menu selected="{{page}}" valueattr="id">
         ...
      </core-menu>
      <core-animated-pages class="main" selected="{{page}}" valueattr="id" transitions="slide-from-right"> 
    

    这很好,因为我们已将 UI 与代码分离。代码从不直接与core-animated-pagescore-menu 对话(注意我删除了ids)。我们不听任何事件。这样我们就可以随意更改 UI 而无需修改脚本。

    现在,我们希望 page 最初由 URL 选择,因此我们将以这种方式初始化它,或者默认为“home”。我们还想将page 同步到后台事件,所以我们将监听 `onpopstate'。

       ready: function() {
          // scrape the initial page off the window location
          this.page = location.hash.slice(1) || 'home';
          // listen for 'back' events
          addEventListener('popstate', this.popstate.bind(this));
       },
       popstate: function(event) {
         // comes here whether we went 'back' from code or UI
         this.poppedPage = this.page = event.state;
       }
    

    我们会跟踪poppedPage,以便区分前后方向。我们只想在前进的时候推动一个新的状态。

    现在我们需要将页面反映到历史中,所以我们需要在页面发生变化时推送状态。如上所述,一个警告是,如果我们继续前进,我们只需要推动状态。

        pageChanged: function() {
          // if the selected page changes, push a state (unless we are going backward)
          if (this.poppedPage !== this.page) {
            history.pushState(this.page, "Title", '#' + this.page);
          }
        }
    

    这里全部放在一起:

    http://jsbin.com/luwitudu/9/edit

    【讨论】:

    • 我必须说,这是一个非常巧妙的解决方案。也是location.has.splice(1) 的粉丝,但我的网站的深度达到了三层,我不太确定是否可以使用主题标签清楚地做到这一点。也不知道changed watchers,以后也会派上用场的!
    • 在旁注中——知道是否有可能获得所选页面的label-attribute?最好在标题和页面标题中显示标签而不是 id(例如 Home 而不是 home)。目前我只显示{{page}},所以打印了id。
    • {{pageItem.label}}

    【解决方案2】:

    您会收到两个事件,一个用于取消选择当前选定的项目,一个用于取消选择新的选定项目。检查传递给回调函数的事件对象:

    mainMenu: function(e) {
      console.log(e.detail.isSelected);
      console.log(e.detail.item);
    }
    

    但是,如果您使用on-core-activate,您的回调只会在用户点击菜单项时调用一次(当您以编程方式更改菜单选择时不会调用它。)这可以防止在您更改时不需要的窗口历史推送程序中的菜单选择。

    然后您应该设置一个window.onpopstate 回调,您可以在其中选择(上一个)菜单项。如果您在back() 函数中调用document.URL,它将返回当前URL,而不是window.history.back() 设置的新URL。而是只从这个函数的历史中弹出。

    这应该可行:

    <core-menu ... on-core-activate="{{mainMenu}}">
    
    Polymer("my-app", {
      ready: function() {
        var self = this;
        this.$.mainMenu.selected = "home";
        history.pushState(null, "Title", this.$.mainMenu.selected);
        window.onpopstate = function() {
          var link = document.URL.split("/");
          self.$.mainMenu.selected = link[link.length-1];
          self.$.mainPages.selected = self.$.mainMenu.selected;
        };
      },
      mainMenu: function() {
        this.$.mainPages.selected = this.$.mainMenu.selected;
        history.pushState(null, "Title", this.$.mainMenu.selected);
      },
      back: function() {
        window.history.back();
      }
    });
    

    【讨论】:

    • 请注意,core-activate 会在每次单击项目时触发,即使已被选中。
    猜你喜欢
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多