Ну один из самых часто используемых вариантов - это использование template'ов. Такой подход используется во многих популярных фреймворках( например в Angular js).
В чём основной смысл:
1. Есть блок, который является контейнером для темплейтом.
<div class='container'></div>
2. Есть сами темлейты, которые и представляют те самые страницы.
templates/template-1.html
<div class='template-1>
<h3>template header</h3>
<div class='template-body>
template 1 body
</div>
</div>
templates/template-1.html
<div class='template-2>
<h3>another template header</h3>
<div class='template-body>
template 2 body
</div>
</div>
3. Есть компонент-роутер, который связывает как правило текущий url и показываемый template.
var routes = [
{
template: 'templates/template-1.html',
url: '/template1'
},
{
template: 'templates/template-2.html',
url: '/template2'
}
];
function matchRoute() {
var path = window.location.pathname;
var matchedRoutes = routes.filter(function(route) {
return route.url === path;
});
if (matchedRoutes.length === 0) {
console.log('No route found');
}
else {
var route = matchedRoutes[0];
// здесь мы должны загрузить template при помощи Ajax
// и вставить его в контейнер
}
}
Функция matchRoute вешается на событие изменения window.location
Это самый базовый пример того, как работает роутинг для SPA. Есть много различных решений, реализующих такой подход, я лишь описал принцип. Если будут вопросы - спрашивайте.