framework7io / framework7-vue

Deprecated! Build full featured iOS & Android apps using Framework7 & Vue
http://framework7.io/vue/
MIT License
674 stars 154 forks source link

about built-in router #38

Closed evolutionjay closed 6 years ago

evolutionjay commented 7 years ago

I suggest replacing the built-in "router" with "vue-router"

bencompton commented 7 years ago

I initially took that approach with Framework7 React and tried to make it as pure of a React framework as possible and use react-router, which is similar in a lot of ways to vue-router. Basically, with the complexity of the page animation in Framework7, it proved extremely difficult to make it work correctly with react-router, so I ended up doing routing the same as the Vue version. I suspect supporting vue-router would be a large undertaking as well.

Out of curiosity, what features of vue-router do you feel are currently missing from F7 Vue?

In my mind, the most important missing feature is nested routes. I'm working on converting over a rather large app using an older version of F7 React to the newer (not yet stable) version. The app currently uses react-router and has nested routes. I'm not entirely sure yet how to work around the lack of nested routes, but I haven't spent much time on it yet either. I'm hoping there is an easy way to work around it or that adding nested routing support won't be difficult, but we'll see.

kael777 commented 7 years ago

i think built in router is from the web version and not that easy to remove,use vue-router with f7 and disable built in router is also ok for me right now...

bencompton commented 7 years ago

I've been thinking some more about nested routes as I've been converting over my app to use the new version of Framework7 React that is automatically generated from Framework7 Vue. For my app, it mainly requires nested routes for pages that have tabs, and I'm at a point where I can't really go much further without addressing this problem.

I've been thinking about how to accomplish nested routes in Framework7, and it occurred to me that the flexibility of having an unlimited number of nested routes that libraries like vue-router and react-router provide is overkill for Framework7 apps, and really mobile apps in general. The purpose of nested routes is to address scenarios where there are sub-screens within a particular screen that need to be tied to a URL path under the main screen's URL path. Mobile app UX designs typically have a pretty constrained set of options for navigation, so I think we could get away with also having a simpler solution for Framework7 than full-on nested routes.

Here are the main UI components I can think of that result in a screen within a screen that people might want to tie to a URL:

I've started working on a little prototype for Framework7 Vue to address the tabs first, but if this works out, other components could come afterwards.

Okay, so the Framework7 Vue kitchen sink currently has a route that looks like this:

export default [    
   ...
   {
      path: '/tabs/',
      component: Tabs
   },
   ...
];

Currently, the only option is to specify what is rendered within each tab inline, but imagine if that could be done in a route like this instead (this is just experimental syntax, so feel free to suggest improvements):

export default [{
  path: '/tabs/',
  component: Tabs,
  tabs: [{
    path: '/',
    tab: '#tab1',
    component: Tab1Content
  }, {
    path: '/tab-2/',
    tab: '#tab2'
  }, {
    path: '/tab-3/',
    tab: '#tab3'        
    routes: [{
      path: '/',
      component: Tab3Content
    }, {
      path: '/tab3-alternate-content/',
      component: Tab3AlternateContent
    }]
  }]
}];

Here are what the results of these routes would be:

Url Result
/tabs/tab-1/ Go to the tabs page and show the first tab (with the Tab1Content component rendered within it)
/tabs/ Go to the tabs page and show the first tab
/tabs/tab-2/ Go to the tabs page and show tab 2 with whatever content that was specified inline (since no component was specified)
/tabs/tab-3/ Go to the tabs page and show tab 3 with Tab3Content
/tabs/tab-3/tab-3-alternate-content/ Go to the tabs page and show tab 3 with Tab3AlternateContent

Here is what the Vue code would look like:


//tabs-page.vue

...
...
...

<f7-buttons>
  <f7-button href="/tabs/tab-1/">Tab 1</f7-button>
  <f7-button href="/tabs/tab-2/">Tab 2</f7-button>
  <f7-button href="/tabs/tab-3/">Tab 3</f7-button>
</f7-buttons>

...
...
... 

<f7-tabs>
  <f7-tab tab-id="tab1" />      
  <f7-tab tab-id="tab2" />      
  <f7-tab tab-id="tab3" />        
</f7-tabs>

//some-other-page.vue

...
...
...

<f7-list-item title="Tab 3 Alternate Content" link="/tabs/tab-3/tab-3-alternate-content/" />

This same type of syntax could be available for other components as well, for example being able to define modals, accordions, etc. in the routes just like tabs.

I am interested in any feedback anyone has. @nolimits4web, I would especially like to hear your thoughts before I spend too much more time working on a pull request.

Edit

I should also add that being able to use routes to link top-level components to URLs is also important for implementing state management libraries like VueX and Redux.

The app I've been converting over uses Redux and all navigation is accomplished through actions, so I've also been working on Framework7 Redux, which will have code that can be re-used in Framework7 VueX. The goal of doing navigation from actions and reducers is to better separate concerns and allow components can be as dumb and re-usable as possible. When using Framework7 Redux (or Framework7 VueX), the tab buttons would have not have an href and instead would have a click handler that ultimately calls an action to actually do the navigation:

store.dispatch(navigateTo('/tabs/tab-1/'));

Doing all navigation from actions requires that all screen changes are all handled by the router.

In addition to better support for navigation driven by Redux and VueX, this will also pave the way to allow F7 Router to support changing the browser URL and navigating to the correct place for that URL, and also possibly rendering on the server.

bbalan commented 7 years ago

One of the important features of vue-router in my app is component props. When I compose a route this way: /user-component/:userid, the matched component will receive userid as a prop. I don't think that is possible with Framework7's built in router.

More importantly, the built-in router doesn't seem to use history states. In a browser, the Back button does nothing. Android devices also have Back buttons, and presumably those would also do nothing. Please correct me if I am wrong.

I am new to Framework7 and I'm not sure how easy it is to decouple its router from the rest of the code, but I think it would be a good idea.

bencompton commented 7 years ago

@bbalan - as you may have already seen in the kitchen sink, it is currently possible to access those parameter values from a component via this.$route.params.

$route, is available in every component instance, so it isn't necessarily difficult to access right now, but I would agree with you that passing this data in via props would be great. My main motivation is that in the React version, $route is not currently available from every component since it isn't as easy in React to make data available on every component instance (except via Context...yuck!).

If you're interested in trying your hand at a PR, I would think it would be relatively simple to implement by passing in router params as props when route page components get instantiated and also when route tab components get instantiated.

nolimits4web commented 7 years ago

@bencompton @bbalan good finding, i've just added this feature and now route params are passed as props

@bbalan as for history state, just add pushState: true to framework7 parameters

bencompton commented 7 years ago

@nolimits4web - awesome!

bbalan commented 7 years ago

@nolimits4web Thank you!

fayland commented 7 years ago

is there 'Navigation Guards' as http://router.vuejs.org/en/advanced/navigation-guards.html

it would be useful for auth part for example I can restrict some routes for user-login only.

how to archive it with builtin router?

Thanks

bencompton commented 7 years ago

@fayland - Framework7 supports passing a preroute parameter that should achieve pretty much what you're asking:

var app = new Vue({
    // Root Element
    el: '#app',
    // Framework7 Parameters
    framework7: {
      root: '#app', //Should be same as app el
      animateNavBackIcon: true,
      routes: Routes,
      preroute: function (view, options) {
        //TODO: Determine whether logged in or not
        let loggedIn = false;

        if (options.url === '/account-details/' && !loggedIn) {
          view.router.loadPage('/login/');

          return false;
        }

        return true;
      }
    }
   ...
});
red010182 commented 7 years ago

Is it possible to use framework7's route to pass javascript object as props?

auzadventure commented 7 years ago

@red010182 Yes I'm interested as well to pass js objects as props using the built in router

codingfriend1 commented 7 years ago

Could preroute work with resolving or rejecting a promise?

bencompton commented 7 years ago

@codingfriend1, async routing isn't currently supported to my knowledge, but you could probably do some horrible hack where you fire off your async logic, return false from pre-route and then issue another route change once your promise resolves. However, you'd need some condition that causes pre-route to return true on that second route change or else you'd end up with a stack overflow.

Seems you would be better served doing your async logic outside of routes.

dts commented 7 years ago

Unless I'm misunderstanding what nested routes means to you, according to the docs, nested routes are supported out-of-the-box by Vue-Router (https://router.vuejs.org/en/essentials/nested-routes.html). Keeping as much of the standard vue ecosystem would be huge for me at least.

clockworked247 commented 7 years ago

+1 to pass javascript object as props @red010182 @auzadventure

Use case: I've got a list of items I render with v-for, rendering details in a list. I add an @click each one to render its details page. Passing the actual object found when I iterate over the array with v-for would be really convenient.

Example:

<div v-for="item in items">
    <f7-link @click="$f7.mainView.router.load({ url: 'item/' + item.id, params: item })">item.name</f7-link>
</div>

Of course, as currently implemented, this gets overwritten by the route definition of item/:id, returning just the param "id".

It would be great if the options includes a param object, that the passed object would take precedence or at minimum be merged with the passed object. Other alternative is to create a separate option just for this operation, i.e. "props".

Right now I'm looking at the headache of getting my data into some usable format for use by my child template and finding this quite difficult to do. I'm sure I'll get it eventually, but passing a object seems much more usable.

LorrainInfinity commented 7 years ago

Any news about this? Right now all I've been able to do is add an @click event on the link which "saves" the clicked item in vuex. It's not the best but it works. Indeed it'd be really great to get it working with a "props" attribute or something directly in the link !

marcelo-rebello commented 6 years ago

Is there a way to access the Vuex store inside a pre-router? I'm trying to implement an auth mechanism like kindergarder-vue, but the framework7 router seens to limited. Is there a way to use vue-router with framework7? Thanks

nolimits4web commented 6 years ago

Issue is closed because of outdated/irrelevant/not actual

If this issue is still actual and reproducible for latest version of Framework7 & Framework7-Vue, please create new issue and fill the issue template correctly: