Applying v-transition to vue.js(v 1.0.1) router-view - vue.js

I'm building a single page application, using vue.js and vue-router.. right now the links work, but I want to add transition using v-transition.
but according to the documentation
What’s more important though, is that non-flow-control directives, non-prop attributes and transitions on the component element will be ignored, because there is no root element to bind them to - vue.js components
<router-view class="bounce" v-transition="bounce" transition-mode="out-in"></router-view>
so technically the v-transition in the router-view tag will be ignored because it is a Fragment instance..
so any idea where I can put the v-transition to apply transitions on route change?

Define at least one route node in your component:
<router-view class="bounce">
<div v-transition="bounce" transition-mode="out-in">
</div>
</router-view>
Vue need one element to insert in the DOM if you want to apply transition, or v-show.

Related

Vue component communication between header component and components in the router-view

Im facing a problem for my VUE app, Im using the vue Router to navigate to my component
In my Header component I use router-link to navigate to a Home component
The problem is :
In my Header component I would like a checkBox (a boolean variable) that change the content of my Home component (rendered in the router-view) like a v-if that would check the boolean variable in the Header
Here is my App.vue template I was trying to solve the problem through emits but Im Kinda stuck for passing data inside a component (inside the router-view)
<template>
<div class="content">
<HeaderComponent #eventCheckBox="handleCheckBox" />
<router-view />
<FooterComponent />
</div>
Do you guys have already faced this issue, is there a way to do it the classic way or should I try plugins like Portal or Teleport ?
Portal and Teleport are the same, just a different name (teleport in Vue3, being the official name).
As of the rest of the question, this explains it very well: https://stackoverflow.com/a/49702934/8816585
Mainly, you need to see if you need to use a store like Pinia (recommended one) and Vuex. Most of the time, you could use a parent/child relationship. Here is another article explaining when you would need something like that: https://markus.oberlehner.net/blog/should-i-store-this-data-in-vuex/#alternatives-to-storing-data-in-vuex
In Vue3, you could even not use a store and rely solely on the singleton pattern + composables (again, a lot of articles are available for that one).
TLDR: use your Vue devtools and inspect the state flowing.
If you need more, reach for more powerful tools.

When exactly are keys useful in Vue?

I still don't quite get the use of keys even after reading through the docs but I understand that it has to do with keeping each item unique. I've been solely adding a key when using a v-for and only to the outer most parent (not the children of the v-for. Are there any other situations when keys should be used?
<div v-for="(person,index) in people" :key="index>
<div class="name-label>
<img :src="person.img/>
<div> {{ person.name }} </div>
</div>
</div>
The key directive alongside v-for, is used to uniquely identify each parent element rendered on the v-for operation.
The same happens in Reactjs:
{elements.map((value, index) => {
return <li key={index}>{value}</li>
})}
The key directive in Vuejs is also used to force Vuejs to re-render an element that contains it every time :key receives a new value.
As #firmino-changani indicated, other uses of key is if you want Vue to force a re-render or replacement of an element or component. See key special attribute documentation:
It can also be used to force replacement of an element/component
instead of reusing it. This can be useful when you want to:
Properly trigger lifecycle hooks of a component
Trigger transitions For example:
<transition>
<span :key="text">{{ text }}</span>
</transition>
When text changes, the <span> will always be replaced instead of patched, so a transition will be triggered.
Another example, lets say you have a dialog popup to add new data and another component that needs updating once the new data was entered via the popup. This second component might have logic inside lifecycle hooks like onMounted etc. Using a :key you can force re-rending this component once the dialog popup is saved e.g.
<template>
<page>
<add-data-popup #save="myKey++" />
<show-data :key"myKey" />
</page>
</template>
From the vueJs docs around Keys:
The key special attribute is primarily used as a hint for Vue’s virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list.
To simply put it, if a div is rendered via a For-loop the div will be identical to each other div. When a user clicks on one of these Div's and you instantiate a #click function, how will vueJs know what differentiates each of these divs? How will vue know how to reorder these div's in the correct order if you remove a middle div?
VueJs uses the key to know how to reorder the DOM when an action is taken on one of these objects in your For loop.
Here is an article fully explaining about vueJs keys, and more details on the VueJS reactivity engine which is good to know about: https://www.telerik.com/blogs/in-vue-when-do-i-actually-need-the-key-attribute-and-why

I want to change Vue components with media Queries

In my App.vue I've set my template like this
<app-header></app-header>
<router-view></router-view>
<app-footer ></app-footer>
app-header sets a header component to every other component of my project (so I don't have to repeat myself). app-footer does the same, but with a common footer for all of my components.
This works perfect with my Desktop web, but for Mobile I would like to change the header component to a new-header.vuecomponent, and I would like to get rid of the Footer when using a mobile device so it doesn't use screenspace.
How can I achieve this? I tried to use app-footer {display: none;} in a media query at App.Vue but its not working.
You do not want to use CSS to hide. The beauty of Vue is that in the case of mobile, the code will not even be generated at all.
Use a v-if directive, and add an isMobile property to your data, computed, store, etc. Or call a method to get it.
<app-footer v-if='!isMobile'></app-footer>
For the header, there are 2 ways. Using a component element with v-bind:is to swap in the correct one, or using v-if and v-else
<app-header v-if='!isMobile'></app-header>
<app-header-mobile v-else></app-header-mobile>
Here is the official link to the Vue dynamic component approach.
https://v2.vuejs.org/v2/guide/components-dynamic-async.html.
It would look like this:
<component v-bind:is="currentHeaderComponent"></component>
In this case, you would set currentHeaderComponent based on your conditions.
If you insist on CSS and media queries for the footer, set the component id or class, and that in your CSS
Component
<app-header id='app-header'></app-header>
<router-view></router-view>
<app-footer id='app-footer'></app-footer>
CSS
#app-footer {display: none;}

How to get the parent template component in Vue

I know in vue, I can use this.$parent to get the upper component in the vdom tree. But I'm expecting something different: to get the component that rendered the current component.
For instance, I have a component (named comp-container) with template:
<template>
<comp-a>
<comp-b></comp-b>
</comp-a>
</template>
And in comp-b the $parent would be an instance of comp-a not comp-container which I'm expecting.
My current aproach is traversing up with the $parent attribute until I find comp-b exists in $options.components. This method is working for now but seems quite ugly and breaks if comp-b is a globaly registered component. Is there an official way to do this?
Passing the parent template component via props as <comp-b :container="this"></comp-b> may do the job, but it's too verbose to be liked.
I'm not sure about the exact use case, but basically if there are slots involved (which I almost assume, because otherwise $parent will work fine), you can find the rendering component at:
this.$slots.default[0].context;
Basically, the context property of a slot is the rendering context (rendering component - i.e. the component who's template the component was rendered in).
Only tested with Vue 2

vuejs template conditional root element

I'm making a generic vue button component.
In some cases it would be a router-link while in other cases it would be a normal anchor tag.
So basically looking for something like this.
<template>
<router-link v-if="useRouter" :to="link"></router-link>
<a v-else :href="link"></a>
</template
But a vuejs component template must have exactly one root element.
Besides making two seperate vue components or wrapping my button in an element. I can't think of any other solution.
Is there a better way to solve this?