Where views come from
A view can be more than a string: a function that builds it from data, a URL, an object with hooks, or a component from your framework.
Each tile says where its view comes from, and each view shows it again at the top. Both fish open the same function with different props; Opening hours is fetched from another file. Add a fish: the shop repaints when you come back.
The code
const basket = []
const fishes = { Clownfish: 'clownfish', 'Blue tang': 'tang' }
const app = new Zumly({
mount: '.canvas',
initialView: 'shop',
views: {
// A function: paints from state, and again each time you come back
shop: ({ target, onActivate }) => {
target.className = 'z-view shop'
const paint = () => {
target.innerHTML = `
<h1>Fish shop</h1>
<p>Basket: ${basket.join(', ') || 'empty'}</p>
<div class="row">
<div class="zoom-me tile clownfish" data-to="fish" data-name="Clownfish">Clownfish<small>function + props</small></div>
<div class="zoom-me tile tang" data-to="fish" data-name="Blue tang">Blue tang<small>function + props</small></div>
<div class="zoom-me tile hours" data-to="hours">Opening hours<small>URL</small></div>
</div>`
}
paint()
onActivate(paint)
},
// One function for both fish: the trigger's data-* arrive as props
fish: ({ target, props }) => {
target.className = `z-view card ${fishes[props.name]}`
target.dataset.title = props.name
target.innerHTML = `
<span class="source">fish({ props: { name: '${props.name}' } })</span>
<h2>${props.name}</h2>
<button>Add to basket</button>`
target.querySelector('button').onclick = () => {
basket.push(props.name)
app.zoomOut()
}
},
// A URL: fetched the first time, then cached
hours: 'hours.html'
},
lateralNav: false
})
app.init()
hours.html
<div class="z-view card hours" data-title="Opening hours">
<span class="source">fetched from hours.html</span>
<h2>Opening hours</h2>
<p>Every day, 9 to 18.</p>
</div>
How it works
- A function view receives a context.
targetis a fresh element that becomes the view: give it your classes and fill it.propsholds the trigger'sdata-*attributes, sodata-name="Clownfish"arrives asprops.name. - Views behind the current one are not rendered again. Keep state outside the view and repaint in
onActivate, which runs each time the view becomes current again. - A URL view is fetched the first time it is needed and then cached.
hours.htmlis just a fragment with onez-viewroot. onCleanup(fn)runs once when the view is discarded: unmount components and stop timers there.
| Source | Example |
|---|---|
| HTML string | '<div class="z-view">…</div>' |
| URL | 'views/detail.html' |
| Function | ({ target, props, onActivate, onCleanup }) => { … } |
| Object | { title: 'Detail', render (ctx) { … }, mounted (node) { … } } |
| Element | document.querySelector('#template') (cloned) |
With a framework
Mount a component into target and unmount it in onCleanup. This is React; the guides show the same for the others.
dashboard: ({ target, props, onCleanup }) => {
const root = createRoot(target)
onCleanup(() => root.unmount())
root.render(<Dashboard id={props.id} />)
}
React · Vue · Svelte · Angular · Orbit CSS
URL views are inserted as HTML and their <script> tags do not run. Put behaviour in a function view, and sanitize HTML that comes from elsewhere.