聚合物2 - 每次通过铁页/铁选择器显示元素时执行操作

时间:2017-09-06 21:37:30

标签: dom ecmascript-6 polymer polymer-2.x dom-events

我正在尝试创建一个注销页面,即使该元素已经连接到DOM之后也能正常工作。当您获得登录,然后注销,然后再次登录,并尝试退出时,就会发生这种情况。

例如,shell有

<iron-selector selected="[[page]]" attr-for-selected="name">
  <a name="logout" href="[[rootPath]]logout">
    <paper-icon-button icon="my-icons:sign-out" title="Logout" hidden$="[[!loggedIn]]"></paper-icon-button>
  </a>
  <a name="login" href="[[rootPath]]login">
    <paper-icon-button icon="my-icons:sign-in" title="Login" hidden$="[[loggedIn]]"></paper-icon-button>
  </a>
</iron-selector>

<<SNIP>>

<iron-pages selected="[[page]]" attr-for-selected="name" fallback-selection="view404" role="main">
  <my-search name="search"></my-search>
  <my-login name="login"></my-login>
  <my-logout name="logout"></my-logout>
  <my-view404 name="view404"></my-view404>
</iron-pages>

我还有一个关于shell中页面更改的观察者:

static get observers() {
  return [
    '_routePageChanged(routeData.page)',
  ];
}

_routePageChanged(page) {
  this.loggedIn = MyApp._computeLogin();
  if (this.loggedIn) {
    this.page = page || 'search';
  } else {
    window.history.pushState({}, 'Login', '/login');
    window.dispatchEvent(new CustomEvent('location-changed'));
    sessionStorage.clear();
    this.page = 'login';
  }
}

这很有效,因为当我点击要注销的图标时,它会很好地附加my-logout元素并执行ready()connectedCallback()中的内容。

my-logout

ready() {
  super.ready();
  this._performLogout();
}

问题出现在没有刷新浏览器并导致DOM刷新的情况下,您重新登录并尝试再次注销。由于DOM从未清除过,my-logout仍然附加,因此ready()connectedCallback()都不会被激活。

我已经找到了解决这个问题的方法,但感觉非常糟糕。基本上,我可以在选择图标时为要执行this._performLogout();的元素添加一个事件监听器:

ready() {
  super.ready();
  this._performLogout();

  document.addEventListener('iron-select', (event) => {
    if (event.detail.item === this) {
      this._performLogout();
    }
  });
}

就像我说的,它有效,但我不喜欢有一个全局事件监听器,而且我必须在第一次元素附加时调用logout函数我必须监听,因为监听器不是直到元件第一次连接后才有效。

1 个答案:

答案 0 :(得分:1)

似乎没有“一刀切”的解决方案。中心问题是,“你想让父母告诉孩子,还是让孩子听父母的话?”。我在问题中提出的“答案”如果你想听父母,但因为我不喜欢全局事件监听器的想法,下面是如何使用<iron-pages>告诉一个子元素,它已被选中进行查看。

我们将selected-attribute属性添加到<iron-pages>

<iron-pages selected="[[page]]" attr-for-selected="name" selected-attribute="selected" fallback-selection="view404" role="main">
  <my-search name="search"></my-search>
  <my-login name="login"></my-login>
  <my-logout name="logout"></my-logout>
  <my-view404 name="view404"></my-view404>
</iron-pages>

是的,考虑到attr-for-selected属性,这看起来有点令人困惑。 attr-for-selected说:“我应该使用my selected属性的值将这些子元素与哪个属性匹配?”所以当我点击

<iron-selector selected="[[page]]" attr-for-selected="name">
  <a name="logout" href="[[rootPath]]logout"><paper-icon-button icon="my-icons:sign-out" title="Logout" hidden$="[[!loggedIn]]"></paper-icon-button></a>
</iron-selector>

它会在内部将<my-logout>设置为所选元素并显示它。 selected-attribute="selected"做的是在子元素上设置属性。如果您查看浏览器JS控制台,您将看到该元素现在看起来像

<my-login name="login"></my-logout>
<my-logout name="login" class="iron-selected" selected></my-logout>

我们可以在检查更改的<my-logout>元素中定义一个观察者

static get properties() {
  return {
    // Other properties
    selected: {
      type: Boolean,
      value: false,
      observer: '_selectedChanged',
    },
  };
}

_selectedChanged(selected) {
  if (selected) {
    this._performLogout();
  }
}

if语句是这样的,我们只在显示时触发逻辑,而不是在我们离开时。这样做的一个优点是我们不关心元素是否已经附加到DOM。当<iron-selector>/<iron-pages>第一次选择<my-logout>时,属性设置,元素附加,观察者触发,观察者看到selected现在是true(而不是定义的false)并运行逻辑。