3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Polymerのsingle page app tutorialで動的ページロードをelement化してみました

Last updated at Posted at 2015-05-22

元のネタはこちらのページ
https://www.polymer-project.org/0.5/articles/spa.html

後半に動的にページロードするサンプルが出ます。
原理はcore-ajaxからリクエストを送ってdivタグのidが'article-content'から下部を動的に表示する内容ですが、
サンプルのソースが巣のhtmlで書いているためいざ使う時に他のFWとの絡みがややこしい。
ので、element化してみました。

main-menu.html
<polymer-element name="main-menu" >

<template>

  <!-- Route controller. -->
  <!-- 
  <flatiron-director route="{{route}}" autoHash></flatiron-director>
  -->
  
  <!-- Keyboard nav controller. -->
  <core-a11y-keys id="keys" target="{{parentElement}}"
                  keys="up down left right space space+shift"
                  on-keys-pressed="{{keyHandler}}"></core-a11y-keys>

  <!-- Dynamic content controller -->
  <core-ajax id="ajax" url="{{selectedPage.page.url}}" handleAs="document"
             on-core-response="{{onResponse}}"></core-ajax>

  <core-scaffold id="scaffold">

    <nav>
      <core-toolbar>
        <span>Polymer Tutorial SPA</span>
      </core-toolbar>
      <core-menu id="menu" valueattr="hash"
                 selected="{{route}}"
                 selectedModel="{{selectedPage}}"
                 on-core-select="{{menuItemSelected}}" on-click="{{ajaxLoad}}">
        <template repeat="{{page, i in pages}}">
          <paper-item hash="{{page.hash}}" noink>
            <core-icon icon="label{{route != page.hash ? '-outline' : ''}}"></core-icon>
            <a href="{{page.url}}">{{page.name}}</a>
          </paper-item>
        </template>
      </core-menu>
    </nav>

    <core-toolbar tool flex>
      <div flex>{{selectedPage.page.name}}</div>
      <core-icon-button icon="refresh"></core-icon-button>
      <core-icon-button icon="add"></core-icon-button>
    </core-toolbar>

    <div layout horizontal center-center fit>
      <core-animated-pages id="apages" selected="{{route}}" valueattr="hash"
                           transitions="slide-from-right">
        <template repeat="{{page, i in pages}}">
          <section hash="{{page.hash}}" layout vertical center-center>
            <div style="max-width:100%;">Loading...</div>
          </section>
        </template>
      </core-animated-pages>
    </div>

  </core-scaffold>
  
</template>

<script>
Polymer({
	DEFAULT_ROUTE : 'one',
	pages : [
      {name: 'Shadow DOM 101', hash: 'one', url: '//www.html5rocks.com/en/tutorials/webcomponents/shadowdom/'},
      {name: 'Shadow DOM 201', hash: 'two', url: '//www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/'},
      {name: 'Shadow DOM 301', hash: 'three', url: '//www.html5rocks.com/en/tutorials/webcomponents/shadowdom-301/'},
      {name: 'Custom Elements', hash: 'four', url: '//www.html5rocks.com/en/tutorials/webcomponents/customelements/'}
	],

	created : function() {
		  this.cache = {};
	},
	
    domReady: function() {
		this.ajax = this.shadowRoot.querySelector('#ajax');
		this.scaffold = this.shadowRoot.querySelector('#scaffold');
		this.apages = this.shadowRoot.querySelector('#apages');
		this.keys = this.shadowRoot.querySelector('#keys');
		
		// Allow selecting pages by num keypad. Dynamically add
		// [1, template.pages.length] to key mappings.
		var keysToAdd = Array.apply(null, this.pages).map(function(x, i) {
		  return i + 1;
		}).reduce(function(x, y) {
		  return x + ' ' + y;
		});
		this.keys.keys += ' ' + keysToAdd;
		
		this.route = this.route || this.DEFAULT_ROUTE; // Select initial route.
    },
	
    
    keyHandler : function(e, detail, sender) {
    	  // Select page by num key.
    	  var num = parseInt(detail.key);
    	  if (!isNaN(num) && num <= this.pages.length) {
    	    this.apages.selectIndex(num - 1);
    	    return;
    	  }

    	  switch (detail.key) {
    	    case 'left':
    	    case 'up':
    	      this.apages.selectPrevious();
    	      break;
    	    case 'right':
    	    case 'down':
    	      this.apages.selectNext();
    	      break;
    	    case 'space':
    	      detail.shift ? this.apages.selectPrevious() : this.apages.selectNext();
    	      break;
    	  }
  	},

	menuItemSelected : function(e, detail, sender) {
  	  if (detail.isSelected) {

  	    // Need to wait one rAF so <core-ajax> has it's URL set.
  	    this.async(function() {
  	      if (!this.cache[this.ajax.url]) {
  	        this.ajax.go();
  	      }

  	      this.scaffold.closeDrawer();
  	    });

  	  }
  	},
	       
	ajaxLoad : function(e, detail, sender) {
		e.preventDefault(); // prevent link navigation.
	},

	onResponse : function(e, detail, sender) {
		  var article = detail.response.querySelector('#article-content');

		  article.querySelector('.byline').remove();

		  // Fix up image paths to not be local.
		  [].forEach.call(article.querySelectorAll('img'), function(img) {
		    img.setAttribute('src', img.src);
		  });

		  var html = article.innerHTML;

		  this.cache[this.ajax.url] = html; // Primitive caching by URL.

		  this.injectBoundHTML(html, this.apages.selectedItem.firstElementChild);
	}
	
       
});

</script>
</polymer-element>

ざっくり解説
shadowRootからオブジェクトを読めるタイミングはcreatedではなく、domReadyからであるので初期化もそこから行っています。
なので本当はcreatedは要らない
domReadyにまとめちゃってもかまいません。

公式polymerの記事はよく出来ているけど、サンプルコードで一つ悪いのが
templateの配列要素とcore-animated-pagesのidが同じ名前の"pages"であって紛らわしいですね。
今回はcore-animated-pagesのidをapagesに変えました

flatiron-directorは使うつもりがないのでコメントアウト。
もし使う場合はimportをいれてください。
polymer-elementのnameとかpagesのurlデータとか、titleとかも適宜に修正してください

import.html
<script src="../bower_components/webcomponentsjs/webcomponents.min.js" type="text/javascript"></script>
<link rel="import" href="../bower_components/polymer/polymer.html">

<link rel="import" href="../bower_components/core-a11y-keys/core-a11y-keys.html">
<link rel="import" href="../bower_components/core-ajax/core-ajax.html">
<link rel="import" href="../bower_components/core-animated-pages/core-animated-pages.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/slide-from-right.html">

<link rel="import" href="../bower_components/core-drawer-panel/core-drawer-panel.html">
<link rel="import" href="../bower_components/core-icon/core-icon.html">
<link rel="import" href="../bower_components/core-icon-button/core-icon-button.html">
<link rel="import" href="../bower_components/core-item/core-item.html">
<link rel="import" href="../bower_components/core-menu/core-menu.html">
<link rel="import" href="../bower_components/core-scaffold/core-scaffold.html">
<link rel="import" href="../bower_components/core-toolbar/core-toolbar.html">

<link rel="import" href="../bower_components/font-roboto/roboto.html">

<link rel="import" href="../bower_components/paper-item/paper-item.html">

いざ使う場合は、、たとえばplay frameworkで使うたとすると

index.scala.html
@(title: String)(content: Html)

<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
        <title>@title</title>
        <link rel="import" href="@routes.Assets.at("elements/import.html")">
        <link rel="import" href="@routes.Assets.at("elements/main-menu.html")">
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")" shim-shadowdom>
    </head>

<body unresolved fullbleed>
	<main-menu>main</main-menu>
</body>
</html>

こんな感じですかね。
(上記の2ファイルがpublic/elementsの配下にある場合)

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?