When to use <router-link> vs <a> - vue.js

Should I always be using <router-link> over <a> even if I am linking to something like a social media page outside the app?

<router-link> is intended for in-app links (e.g., to a page within your app). Use <a> for external links.

Router link : if we use router link the page will not reload but with <a> link the navigation occured through page refresh.

‘vue-router’ is a separate package to Vue and is installed by ‘webpack’.
Routes are set up in router/index.js
Import to Router from vue-router which is in node_modules.
import Router from 'vue-router'
... new Router...
creates an instance of Router which is an object with a property ‘routes’ which is an array of object. Each of those objects is a route with properties for ‘path’, ‘name’ which is what it is called and ‘component’, the component that is called when the route is used.
{
path: '/about',
name: 'About',
component: About
}
We need to import the component and we use the # which brings the path to the root of the project which is the ‘src’ directory.
import About from '#/components/About'
The component gets loaded into the root component App.vue using,
<router-view/>
and where that tag is in the App.vue. This would allow us to place a navbar, header and footer for example around this About component. So that when you go to …/about only the about component in the page changes and the whole page doesn’t refresh.
Next create a NavBar component and place it in the App.vue template.
This will work,
About
however in vue it should be done like this,
<router-link to="/about>About</router-link>
When <router-link> is rendered to the browser it becomes <a> so in the css we still reference it as ‘a’ not as ‘router-link’.
We can data bind using the ‘to’ attribute in <router-link>like this,
:to={ name: 'About'}
where ‘name’ is the property in the ‘routes’ array of object in the main.js routes. This makes the route dynamic.
Using this data bind to change to ‘/about’ to something else such as ‘abt’ you only need to change,
path: 'abt',
in the routes array of objects.

Related

What is RouterView in Vue.js?

When I do the Vue quickstart and it creates a HelloWorld application, I see that App.vue line 20 contains this line:
<RouterView />
I can't find any documentation for RouterView. It seems odd that a quickstart / tutorial would include an undocumented tag. I do see router-view, is that the same thing?
The RouterView or router-view component is used to display the component or template that corresponds to the current route.
Source: vue-router.d.ts
/**
* Component to display the current route the user is at.
*/
export declare const RouterView: new () => {
$props: AllowedComponentProps & ComponentCustomProps & VNodeProps & RouterViewProps;
$slots: {
default: (arg: {
Component: VNode;
route: RouteLocationNormalizedLoaded;
}) => VNode[];
};
};
Here is a webpage detailing how to use the RouterView component: How to Use Vue Router's router-view Component
After doing some of my own experimenting, I created a vue app (with Vue Router), I found that my components were not being displayed even if I was at the specified route. After adding the RouterView component to my App.vue template, I was able to see the view that was specified by the route.
Edit:
I'd suggest looking through the following tutorial:
Create your own Vue.js Router. After I created my own router I can now understand why this component is present. The component will render the component that the route specifies, therefore, when the route changes the component rendered will change.
From Vue docs for Component Registration > Name Casing:
When defining a component with PascalCase, you can use either case when referencing its custom element. That means both <my-component-name> and <MyComponentName> are acceptable. Note, however, that only kebab-case names are valid directly in the DOM (i.e. non-string templates).
So <RouterView /> is the same as <router-view />.

How can I prevent vue-router from replacing the content loaded into one <router-view> when I load content into another <router-view>?

My Vue app contains two main router-views: one inside of a modal, allowing content to be loaded inside said modal, and another inside the main page. I differentiate between them using the name attribute. Here is a piece of code in the routes.js file which would load content into the modal, for example.
export default ({
mode: 'history',
routes: [
{
path: '/classComp/create',
components: {
modalView: createClass
}
}
]
})
Essentially, my issue is that, when I load content into the router, the content in the router-view for the main page disappears. I understand that most people use the children attribute to address this, but that is not feasible in this case. For instance, the user can press a router-link button in the sidebar to load the form to create classes into the modal. The ability to press this button is thus unrelated to what is loaded or not loaded into the main page, so creating a children attribute is not feasible.
In short, how can I get vue-router to load content into the modal's router-view without wiping the content of the mainbox's router-view?
**EDIT: **Someone suggested to use keep-alive for this, but I could not get this to work. Is this a viable suggestion, and, if so, how would I go about it?
Thinking over your use-case again, I don't think nested routes it the way to go.
Unless you really want to have a route that points to your modal, you can use something like portal-vue to push the modal into another view.
If you are using vue 3, it comes with a component that accomplishes something similar: Teleport
EDIT - continuing our conversation from the comments
As I understand it, portal allows you to insert HTML into two separate locations at once from a single route; my issue is that I need to have 2 routes loaded simultaneously.
You're right, portal won't really allow you to change that. The problem is that vue-router does not have native support for simultaneously loading two routes (unless one is a child of the other). A couple things you could try:
Add a modal nested route (route.children). This would allow you to use <router-view name="modal"> and not navigate away from the parent view. I don't think this makes a lot of sense though. You could do it programmatically using router.addRoutes
Have two routers and two vue apps. I don't believe that vue-router has native support for loading two routes at the same time (unless one is a child of the other). You could however have a separate vue instance just for your modal code. This might introduce complexities based on the design of your app though. A quick example:
const appRouter = new VueRouter({ ... })
const modalRouter = new VueRouter({ mode: 'abstract', ... })
Vue.prototype.$modalRouter = modalRouter
const mainApp = new Vue({ router: appRouter })
mainApp.mount('#app')
....
App.vue
-------
<template>
<div id="app">
<router-view></router-view>
<div id="modal-app" v-pre>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
mounted() {
const modalApp = new Vue({ router: this.$modalRouter })
modalApp.mount('#modal-app')
}
}
</script>
You could call this.$modalRouter.push anywhere in your app to update the route for it.
Both of those solutions seem a bit hacky to me. The easiest way to do this is probably not to use vue-router at all. With portal-vue you could mount content into your modal from anywhere in the app. You can even do it programmatically with Wormhole.open().

Is it component definition in vue? How do I find whether it is a component by looking at the code?

When I search for something I came across this post
Here, something, I believe it is component, is defined as below.
export default {
name: 'app',
methods: {
testFunction: function (event) {
console.log('test clicked')
}
},
components: {
Test
}
}
As per the documentation, I came across this
import BaseButton from './BaseButton.vue'
import BaseIcon from './BaseIcon.vue'
import BaseInput from './BaseInput.vue'
export default {
components: {
BaseButton,
BaseIcon,
BaseInput
}
}
I really not sure, whether app is a component which contains Test. Is it the component definition in export? How do we understand that is a component from vue code?
Is it only by the below ways?
Vue.component
components in Vue instance
Not sure - the export default way?
I understand that I sound different because it is Javascript. Could someone help me with this?
There are conventionally, three different types of components in Vue JS.
Root Component
View Component
Normal Component
In a conventional structure the Root component is named 'app' and is passed to the Vue instance when initializing the App for the first time. This component can not be imported and reused inside other components as it will cause a recursive effect. For example this App.vue file is a Root component. It is used inside this main.js file and passed to the Vue instance using new Vue.
The View components are dynamically added or removed from the Root component based on the route. They are written and act as normal component and are only used for Vue router component property. For example the Home and Comments components inside this Router index file are known as View components. They are passed inside the route objects as components inside individual routes. When the app navigates to that particular route, the <router-view> template inside the App.vue file gets replace with the template of the corresponding View component.
Normal components can be used anywhere and are imported by other components. They can be imported inside the View components as well as the Root components. For example, in root component App.vue we see the component Navbar is used. In View component Comments.vue the Replies component is used.
All these components are identical in declaration and behavior but differ in usage.

Vue Keep-Alive - Component App Header won't stay alive during route changes

I defined the main page of my vue app to look like this:
<div class="wrapper">
<keep-alive>
<app-header></app-header>
</keep-alive>
<router-view></router-view>
</div>
<script>
import appHeader from '../components/Header';
export default {
components: {
appHeader
}
/* etc... */
}
My app UI is basically starting from this component, with many different routes and sub-routes paths to show many pages, but in all pages (components) I want to show the app-header at the top of the page.
The problem is that I noticed recently, with every button clicked (that changes vue-router's route to another page), the app-header gets recreated (the created() lifecycle hook function is called)
I really don't understand why, since I added keep-alive, shouldn't it be rendered once?
Please help me figure this out, I am stuck, I literally researched the entire internet about it.
Please note! I don't want the routes to stay alive, only the app header itself
Here are links to view more of my code, which could might help you understand better:
1) App.vue (Pastebin)
2) Dashboard.vue (Pastebin)
3) Router files (Pastebin)
Please note that at main.js of Vue I import the router and put it first parameter in an object like "new Vue({router, store, vuetify, render: h => h(App)}).$mount('#app');". "App" is an import of App.vue posted, and vuetify is a plugin you all probably know already. Please let me know if you need anything else, I really appreciate your help!!
Thanks in advance
<keep-alive> is for saving the state of dynamic components i.e <component :is="myComponent">
Use <router-link to="/myroute"> or $router.push('/myroute') to move between routes and the non dynamic components outside the router-view will maintain their state.
Here's a simple demo: https://jsfiddle.net/ellisdod/uzj8317m/

Vue router not firing if only slug changes

For some reason, in my Vue app I am having issues with the router when the linked page is only changing the slug. For example
I have the following links
<router-link :to="{ path: '/tag/tag2' }">Tag 2</router-link>
<router-link :to="{ path: '/tag/tag3' }">Tag 3</router-link>
<router-link :to="{ path: '/category/cat1' }">Category 1</router-link>
which are processed by router
{
path: '/tag/:slug',
name: 'Tag',
component: () => import('./views/tag')
}
inside views/tag.vue when it loads it does an axios request to get all the tags. Same functionality for category etc
Lets say the current URL is http://test.com/tag/tag1
If you click on the link for Tag 2 the URL will change, but nothing else happens. No axios calls etc.
If I click on Tag 3 the URL will change, but nothing else happens. No axios calls etc.
If I click on Category 1 then the url changes, page loads up the category view and fires off its axis request.
Why does it have issues if only the slug is changing?
I believe your axios calls are located in one of component's lifecycle hooks (i.e. beforeCreate). The problem is that Vue Router tries to reuse components wherever it is possible. In your case, going from /tag/tag1 to /tag/tag2, the only thing that changes is parameter so it's still the same component and the router does not recreate it again.
There are two solutions:
Put the axios calls to beforeRouteUpdate hook meaning they will be fired every time route in the component changes.
Add key attribute to router-view, which will make the router to recreate every component.
<router-view :key="$route.fullPath"></router-view>
Source: A post from a member of the core team of Vue'js