VueJs Transition Not working as Dynamic component - vue.js

Goal:
Use dynamic components to create custom reusable transition components for Vue V3.
vue2-transitions npm package uses the same method as below and it does not work with v3, So I decided to make a simple one for myself.
CustomTransition.Vue
<component
:is="group ? 'transition-group' : 'transition'"
enter-active-class="fadeInDown"
leave-active-class="fadeOutUp"
>
<slot></slot>
</component>
SomeOtherComponent.vue
<div>
<custom-transition>
<span v-if="show">This does not work.</span>
</custom-transition>
</div>
This does not work, I have no clue why. The <transition> element is rendered like this.
<transition
enter-active-class="fadeInDown"
leave-active-class="fadeOutUp"
>
<span>This does not work.</span>
</transition>
But,
When I rewrite the CustomComponent.vue like this.
<transition
enter-active-class="fadeInDown"
leave-active-class="fadeOutUp"
>
<slot></slot>
</transition>
It is working perfectly fine.
Edit
I've Added a JSFiddle, in case someone wants to try something out.

Finally found the solution from vue community.
link to working jsfiddle
For this component to work:
<component
:is="group ? 'transition-group' : 'transition'"
enter-active-class="fadeInDown"
leave-active-class="fadeOutUp"
>
<slot></slot>
</component>
Import the Transition and TransitionGroup components explicitly in the component and register them.
import { Transition, TransitionGroup } from 'vue'
export default {
components: {
Transition,
TransitionGroup,
},
data() {
return { show: false };
}
}
link to github issue in vue-next repo.

Related

Nuxt Local import component

I want to use vue2-editor (and some other packages) in my project, but use them local inside component or two. I followed this thread How to use plugin in only one component using Nuxt.js? but the solution doesn't help me, I see the following error
[Vue warn]: Failed to mount component: template or render function not defined.
Please suggest what I am missing?
Template:
<template>
<div>
<client-only>
<vue-editor v-model="newIdea.description" />
</client-only>
</div>
</template>
Components:
components: {
[process.client && 'VueEditor']: () => import('vue2-editor')
}
Is this somehow related that I should import {VueEditor} from 'vue2-editor' and not directly 'vue2-editor'?
I also tried to add .default but it didn't help.
Bottom line that import {VueEditor} from 'vue2-editor' is working and [process.client && 'VueEditor']: () => import('vue2-editor') is not (all the rest code is same, so definitely something wrong with the second import, but what? Or maybe I missed something?)

How to access and make reactive the :class and :style changes in Vue component

I have a Vue wrapper for Select2 component that I wrote a while ago. The wrapper is able to access the bind:class and bind:style attributes to pass along to the Select2 library, like so:
this.$vnode.data.staticClass // a string value of class="" attribut
this.$vnode.data.class // an Object passed in via bind:class="{}" attribute
this.$vnode.data.style // same as above but for style
this.$vnode.data.staticStyle
Now I would really like to be able to detect changes to these, so that I could pass them along to Select2 innards.
How can this be done?
This is one variant for a functional wrapper around Select2:
<template functional>
<component
:is="injections.components.Select2"
:ref="data.ref"
class="any_desired_static_classes"
:class="[
data.class,
data.staticClass,
]"
:style="[
data.style,
data.staticStyle,
]"
v-bind="data.attrs"
v-on="listeners"
>
<slot />
</component>
</template>
<script>
import Select2 from 'select2';
export default
{
name: 'SelectWrapper',
inject:
{
// workaround since functional components are stateless and can not register components in the normal way
components:
{
default:
{
Select2
}
}
}
};
</script>

What is the best way to use Vuetify skeleton on Nuxt

I'm kinda new to Vue, Nuxt, and Vuetify and their aspects. I'm working on a Nuxt project with Vuetify and wanna use its skeleton loader but it's kinda messy. right now I use this pattern
template:
<v-skeleton-loader :loading="isLoading" type"card">
<mycomponent />
</v-skeleton-loader>
script
import skeleton from '#plugins/mixins/skeleton.js
export default {
mixins:[skeleton]
}
skeleton.js
export default{
data(){
return{
loading: null
}
},
computed:{
isLoading(){
return this.loading
}
},
created(){
this.loading = true
},
mounted(){
this.loading = false
}
}
when I first used it it was working perfectly. i had a static page and each of its components had their own skeleton and every time i loaded the page it would show their skeleton until they were loaded.
BUT.... as I started using this pattern on different pages i found out that it has many flaws!!
it only shows the skeleton when the page is refreshed!
won't show when I add components or data to the page! for example, an Axios call to get the product
it won't work when changing between routes
and so on ...
So, my question is, What's the best and most practical way to use the skeleton loader! i had a page with a v-for loop through a component and the component had its own skeleton in its template. it only show skeleton on refresh!
like this:
<div v-for="i in 10" :key="i">
<mycomp />
</div>
mycomp:
<v-skeleton-loader :loading="isLoading" type"card">
// components html codes
</v-skeleton-loader>
I would you suggest to create skeleton component. And in main component most of apps do this stuff, where the amount of skeleton is fixed or limited by pagination:
<template v-if="loading">
<skeleton v-for="i in 10" :key="i" />
</template>
<template v-else>
<div v-for="item in items" :key="item.id">
{{ item }}
</div>
</template>

Nested single file components - vue.js with electron-forge

I am trying electron for the first time and I am blown away by it. I have hit a wall, though, when trying to use single file vue.js components using electron-forge. My problem is the following:
I create a project using the vue.js template and run it. Works and looks great. I have a single file page with an index file that looks like this:
<div id="test"></div>
</body>
<script>
import Vue from 'vue';
import Test from './test';
const app = new Vue(Test).$mount('#test');
app.text = "Electron Forge with Vue.js!";
</script>
So far, so good. It imports Test, which is a single file component and renders it.
Now, I would like to have other single file components nested in this main component. For example, I would like to have the following, in my app file called test.vue
<template>
<h2>Hello from {{text}}</h2>
</template>
<script>
import About from './About.vue'
export default {
components: {
appAbout: About,
},
data () {
return {
text: 'Electron'
}
}
}
</script>
Again, so far so good. I can run the app with no errors so the component is being imported.
Here comes my problem: if I now try to render the component using <appAbout></appAbout>, as I have done before in web apps with vue.js, I get the following error.
It basically says that I am not using a single root element in my component, which is really strange because my component looks like this:
<template lang="html">
<div>Hello from component</div>
</template>
<script>
export default {
}
</script>
<style lang="css">
</style>
I am stuck. Can someone please help?
So I have tried a few different things with no success, like using or even as the component names.
I also have tried these two ways of starting the vue:
The way you get with electron-forge
const app = new Vue(App).$mount('#app')
and the way I learned
new Vue({el: '#app', render: h => h(App)})
Nothing seems to work...
Define your component like this :
export default {
components: {
'app-about': About
}
}
Then use it in template like this (with kebab-case) :
<app-about></app-about>
About your compiling template error you need to wrap everything in test.vue in a root element :
<template>
<div>
<h2>Hello from {{text}}</h2>
<app-about></app-about>
</div>
</template>

Template are always fragment

I'm using Vue and Brunch in a small project, today I decide to add Vueify to make my components more concise.
But they are always seen has fragment instance so they are not rendered.
<template lang="pug">
div.sticker-container.sticker-xs-container.nav-top-sticker-animate#btn-about(v-bind:href="link")
span.sticker.sticker-xs.sticker-dark
span.sticker-txt.sticker-xs-txt(v-html="locales.btns.open")
span.sticker.sticker-xs.sticker-over.sticker-over-xs.sticker-light(v-show="opened")
span.sticker-txt.sticker-xs-txt.sticker-light-txt(v-html="locales.btns.close")
</template>
<script>
export default {
data(){
return {
disabled: false,
link: '#'
}
}
}
</script>
To use Vueify I simply add Vue-brunch to my project and I call this vue component like this:
import bar from './foo/bar'
Vue.component('sticker-bar', bar)
So, what i'm doing wrong ?
Try adding a surrounding div within your template. Like so:
<template>
<div>
<content></content>
</div>
</template>
Most times this will solve the fragment instance error.
For more detailed info: https://vuejs.org/guide/components.html#Fragment-Instance
I hope it helps!