vue.js - Organize big single page application with multiple views
Asked Answered
S

4

35

I'm playing with new MVVM framework - Vue.js (http://vuejs.org/).

It was really nice in simple examples and demos but now I'm trying to create big SPA with multiple views and I'm realizing that the best pattern how to do it is not described in framework's docs.

The main problem is that I don't know how to handle views on different routes.

For example, I'm using Director (https://github.com/flatiron/director) for routing but how can I change views?

var booksCtrl = function () {
   var booksViewModel = new Vue({
       el: '#books'
       data: { ... }
       ready: function () {
          // hide previous ViewModel and display this one??
       }
   });
};

var editBookCtrl = function (id) { 
   var editBookViewModel = new Vue({
       el: '#editBook'
       data: { ... }
       ready: function () {
          // hide previous ViewModel and display this one??
       }
   });
};

var routes = {
    '/books': booksCtrl,
    '/books/:id/edit': editBookCtrl
};

var router = new Router(routes);
router.init();

Do I need to create separate Vue.js ViewModels and just display:block / display:none them like in this example?

What would be the right way in your opinion? Thanks!

Semeiology answered 16/3, 2014 at 16:16 Comment(0)
T
29

Nested subviews can be resolved by using v-view and v-ref.

html

<div id="main">
    <div v-view="currentView" v-ref="view"></div>
</div>
<ul>
    <li><a href="#/">top</a></li>
    <li><a href="#/nest/view1">nest/view1</a></li>
    <li><a href="#/nest/view2">nest/view2</a></li>
</ul>

<script id="top" type="x-template">
    <div>top view</div>
</script>

<script id="nest" type="x-template">
    <div>
        <span>nest view</span>
        <div v-view="subview"></div>
    </div>
</script>

javascript

Vue.component('top', Vue.extend({
    template: "#top",
}));

Vue.component('nest', Vue.extend({
    template: '#nest',
    components: {
        view1: Vue.extend({
            template: '<span>this is subview 1</span>',
        }),
        view2: Vue.extend({
            template: '<span>this is subview 2</span>',
        }),
    },
    data: {
        subview: "view1",
    },
}));

var main = new Vue({
    el: "#main",
    data: {
        currentView: "top",
    },
});

var router = new Router({
    '/':        function() { main.currentView = 'top' },
    '/nest/:view': function(view) {
        main.currentView = 'nest';
        main.$.view.subview = view;
    },
});
router.init();

jsfiddle: http://jsfiddle.net/koba04/WgSK9/1/

Tifanie answered 18/4, 2014 at 11:29 Comment(0)
S
16

The officially recommended way to use routing in vuejs applications is to use vue-router :

Quoting from the documentation :

vue-router is the official router for Vue.js. It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze. Features include:

  • Nested route/view mapping
  • Modular, component-based router configuration
  • Route params, query, wildcards
  • View transition effects powered by Vue.js' transition system
  • Fine-grained navigation control
  • Links with automatic active CSS classes
  • HTML5 history mode or hash mode, with auto-fallback in IE9
  • Restore scroll position when going back in history mode

The well-written documentation elaborates further on Modular, component-based router configuration, including examples on handling nested routes.

A router-view outlet is made available into which the route configuration can specify which component to render. These components can contain embedded router-view outlets allowing component oriented nested route management.

Example from the docs:

<div id="app">
  <router-view></router-view>
</div>

router.map({
  '/foo': {
    component: Foo,
    // add a subRoutes map under /foo
    subRoutes: {
      '/bar': {
        // Bar will be rendered inside Foo's <router-view>
        // when /foo/bar is matched
        component: Bar
      },
      '/baz': {
        // Same for Baz, but only when /foo/baz is matched
        component: Baz
      }
    }
  }
})
Singh answered 17/10, 2015 at 23:9 Comment(1)
I think this is outdated. subRoutes is now an Array children: router.vuejs.org/en/essentials/nested-routes.htmlSingleaction
T
4

You might be able to use v-view and component?

like this.

javascript

Vue.component('top', Vue.extend({ 
    template: "<div>top view</div>", 
})); 

Vue.component('other', Vue.extend({ 
    template: "<div>other view</div>", 
})); 

var main = new Vue({ 
    el: "#main", 
    data: { 
        currentView: "top", 
    }, 
}); 
var router = new Router({ 
    '/':        function() { main.currentView = 'top' }, 
    '/other':   function() { main.currentView = 'other' }, 
}); 
router.init(); 

html

<div id="main">
    <div v-view="currentView"></div>
</div>
Tifanie answered 18/4, 2014 at 1:15 Comment(1)
btw what about nested subviews?Semeiology
P
1

You could use Named Views if you don't want to nest them.

html

  <router-view class="view one"></router-view>
  <router-view class="view two" name="a"></router-view>
  <router-view class="view three" name="b"></router-view>

javascript

const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }

const router = new VueRouter({
  mode: 'history',
  routes: [
    { 
      path: '/',
      // a single route can define multiple named components
      // which will be rendered into <router-view>s with corresponding names.
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    },
    {
      path: '/other',
      components: {
        default: Baz,
        a: Bar,
        b: Foo
      }
    }
  ]
})

jsfiddle: https://jsfiddle.net/posva/6du90epg/

The fiddle is from the doc: https://router.vuejs.org/en/essentials/named-views.html

Percy answered 12/1, 2017 at 7:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.