Created
June 16, 2017 22:17
-
-
Save JBreit/3ac62ed5dc8c8f634751d4d1cc8f3b1b to your computer and use it in GitHub Desktop.
Vanilla JS Fetch, History API SPA Experiment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en-us"> | |
<head> | |
<base href="/"> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta name="description" content=""> | |
<meta name="author" content="Jason Breitigan"> | |
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="assets/img/apple-touch-icon-57x57.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/img/apple-touch-icon-114x114.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="assets/img/apple-touch-icon-72x72.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/img/apple-touch-icon-144x144.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="assets/img/apple-touch-icon-60x60.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="assets/img/apple-touch-icon-120x120.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="assets/img/apple-touch-icon-76x76.png" /> | |
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="assets/img/apple-touch-icon-152x152.png" /> | |
<link rel="icon" type="image/png" href="assets/img/favicon-196x196.png" sizes="196x196" /> | |
<link rel="icon" type="image/png" href="assets/img/favicon-96x96.png" sizes="96x96" /> | |
<link rel="icon" type="image/png" href="assets/img/favicon-32x32.png" sizes="32x32" /> | |
<link rel="icon" type="image/png" href="assets/img/favicon-16x16.png" sizes="16x16" /> | |
<link rel="icon" type="image/png" href="assets/img/favicon-128.png" sizes="128x128" /> | |
<meta name="application-name" content=" "/> | |
<meta name="msapplication-TileColor" content="#FFFFFF" /> | |
<meta name="msapplication-TileImage" content="assets/img/mstile-144x144.png" /> | |
<meta name="msapplication-square70x70logo" content="assets/img/mstile-70x70.png" /> | |
<meta name="msapplication-square150x150logo" content="assets/img/mstile-150x150.png" /> | |
<meta name="msapplication-wide310x150logo" content="assets/img/mstile-310x150.png" /> | |
<meta name="msapplication-square310x310logo" content="assets/img/mstile-310x310.png" /> | |
<link rel="icon" href="assets/img/favicon.ico"> | |
<title>Dev Environment</title> | |
<link rel="stylesheet" type="text/css" href="lib/vendor/normalize.css/normalize.css" /> | |
<link rel="stylesheet" type="text/css" href="lib/vendor/Font-Awesome/css/font-awesome.min.css" /> | |
<link rel="stylesheet" type="text/css" href="assets/css/main.css"> | |
</head> | |
<body> | |
<div id="app-root" role="app"> | |
<header id="masthead"> | |
<a href="/">Todo App</a> | |
</header> | |
<nav id="app-router" role="router"> | |
<a href="#!/" class="route">Home</a> | |
<a href="#!/list" class="route">List</a> | |
</nav> | |
<main role="main"> | |
<div role="page"> | |
<h1 id="title"></h1> | |
<section id="content"></section> | |
</div> | |
</main> | |
<footer></footer> | |
<script src="dist/bundle.js"></script> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* global window document fetch history */ | |
const links = document.querySelectorAll('.route'); | |
const titleElement = document.getElementById('title'); | |
const contentElement = document.getElementById('content'); | |
const defaultRoute = ''; | |
const handleError = (err) => { | |
return console.error(err); | |
}; | |
const update = (model) => { | |
if (model) { | |
document.title = model.title; | |
titleElement.innerHTML = model.title; | |
contentElement.innerHTML = model.content; | |
} | |
}; | |
if (window.fetch) { | |
const fetchData = () => { | |
return fetch('/data.json') | |
.then((response) => { | |
if (response.status === 200) { | |
if (response.headers.get('Content-Type') === 'application/json') { | |
return response.json(); | |
} | |
} | |
}) | |
.catch(err => handleError); | |
}; | |
const handleClickEvent = (event) => { | |
event.preventDefault(); | |
const attributes = event.target.attributes[0]; | |
console.log(event); | |
const pathname = attributes.value.substring(3) || 'index'; | |
const uri = attributes.value; | |
fetchData() | |
.then((data) => { | |
const state = data.routes[uri.substring(3) || 'index']; | |
update(state); | |
history.pushState(state, state.title, uri); | |
}) | |
.catch(err => handleError); | |
}; | |
links.forEach(link => link.addEventListener('click', handleClickEvent, false)); | |
window.addEventListener('popstate', event => update(event.state), false); | |
window.addEventListener('load', (event) => { | |
if (document.location.pathname === '/') { | |
fetchData() | |
.then((data) => { | |
console.log(data); | |
const state = data.routes['index']; | |
update(state); | |
history.replaceState(state, state.title, '/'); | |
}) | |
.catch(err => handleError); | |
} | |
}, false); | |
} else { | |
console.log('fetch api not supported in legacy browsers IE <= 10'); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
box-sizing: border-box; | |
-webkit-box-sizing: border-box; | |
-moz-box-sizing: border-box; | |
} | |
:root { | |
font-size: 16px; | |
} | |
html, | |
body { | |
height: 100%; | |
width: 100%; | |
overflow: hidden; | |
} | |
body { | |
background: #fff; | |
margin: 0 auto; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment