Nuxt.JS Create Custom UI Material Components - vue.js

In Nuxt.JS, I want to create some custom UI Materials/Components for my application (NOT A WHOLE LIBRARY LIKE VUETIFY).
This is my current approach:
Minimal Example
~components/Materials/m-button.vue
<template>
<button>
<!-- ???? -->
</button>
</template>
And later I want to use this Material like this:
<m-button>
Button Test
</m-button>
Currently, this isn't working.
I have also tried replacing the <!-- ???? --> with <Nuxt /> & <nuxt-child /> but, as expected, the page gets placed in there (index.vue e.g.), instead of the text Button Test in this example.
Can I somehow get the DOM-"children"?
Do I need to create a plugin? If yes, how?
Couldn't find anything so far, not even with Vue.js.

Use <slot> for this:
<template>
<button>
<slot/>
</button>
</template>
demo

Related

How to move a Vue component around without loosing its state

I have a Vue3 wrapper component that implements a magnification feature in a dashboard. It displays an inner Vue component in two different ways. One is inline and the other is in a full-page pop-up for magnification. The gist of the template (I'm using Vuetify) is:
<template>
<v-card>
<!-- normal location -->
<component v-if="!full_page" :is="innerComponent" />
<!-- magnified full-page version -->
<v-dialog v-if="full_page">
<v-card>
<component :is="innerComponent" />
</v-card>
</v-dialog>
</v-card>
</template>
The above works in general, except that there are two different components in play. This means that if the non-magnified component has internal state then that is lost when switching to the magnified version. I see threee options:
guarantee that all state, even transient one, is maintained external to the component
reach into the component to clone state
ensure Vue moves the component from one spot in the DOM to the other
My question is whether the third option is possible?
With Vue 3 you can use Teleport component to move a component around.
You can do like that:
<div id="div1"></div>
<div id="div2"></div>
<Teleport :to="position ? '#div1' : '#div2'">
<YourComponent/>
</Teleport>
An important note is that
The teleport to target must be already in the DOM when the
component is mounted.
So you need some extra work to make it work with your own code.
Live demo

Is there a way to enable/disable draggable functionality with Vue.Draggable?

I have a scenario where the wrapped elements should only be draggable upon meeting certain conditions. I handled it in the HTML like this:
<draggable v-if='somePassingConditions'>
<my-component></my-component>
</draggable>
<my-component v-else></my-component>
I'm trying to not put the if-else condition in the template. Is there a way to enable or disable the drag functionality with Vue.Draggable? Thanks
Try this:
<draggable :disabled='somePassingConditions'>
<my-component></my-component>
</draggable>
Here is an example from draggable offical repo: https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/simple.vue
Also this link may be helpful: https://sortablejs.github.io/vue.draggable.next/#/simple

Nuxt: how to display a top level component inside of multiple routed pages without reloading it?

I started a new job and I need to build a website with nuxt. A typical website would look like this in a nuxt layout file:
<NavMenu />
<Nuxt /> - my different routed pages
<Footer />
Whenever I change a page <Nuxt /> displays another page, but <NavMenu /> stays as is.
But the website I am building now needs a particular design. Imagine each page looking like this:
(NB: this is purely a design/layout description, not actual vue components)
<HeroImage /> - different for each page, belongs to that specific page
<NavMenu /> - always the same, belongs to the general layout
<MyPageContent /> - content belongs to specific page
The hero image is almost full screen. If you're wondering why the <NavMenu /> is tucked after a fullscreen hero image, it is because when you scroll, the NavMenu is scrolled into view, and whenever it reaches the top of the page, it stays sticky. Here's an example of such sticky navbar: https://codepen.io/bencasalino/pen/MOLQKM
I want to display the NavMenu after the HeroImage. My problem is figuring out how to display a top level component inside of multiple routed pages without reloading it. I can't put the NavMenu inside of individual pages, because if I change the page, that would destroy it and create a brand new NavMenu every time. Also, I can't put HeroImage outside of the <Nuxt /> component because it belongs to its own specific page (the image is different for every page).
I thought I could solve this problem with <teleport>, which allows to move an element to another position in the DOM with a css selector. I would have done something like this:
<teleport to="somewhere_after_the_hero_image" >
<NavMenu />
</teleport>
<Nuxt /> - my different pages
<Footer />
// Pages would look like this
<HeroImage />
<div class="somewhere_after_the_hero_image"></div>
<PageContent />
The problem is that Nuxt doesn't allow it yet because it runs on Vue 2, and <teleport> is a recent feature from Vue3. What would be the most logical way to create this layout? Many thanks in advance !
I didn't find the perfect answer, but one way of doing it might be using the vue store to pass (img url) data from the page created in <Nuxt /> to my HeroImage component.
In the end, I took another approach: my HeroImage is created inside of the Nuxt component, below the menu, and then I used Javascript to put everything into place.

Is there a way to write a quick function with vue's #click?

I was wondering if it is possible to write something like below;
<buttton #click="function(){alert('Yoohooo')}"></button>
Without having to write a method in the Vue instance every time I want to use #click for something as small as that.
It is impossible because Vue trying to add more attributes to DOM and DOM's events in its way with custom attributes and its annotations, methods should be write in methods and so on. As you know HTML is displayed by browsers by tag name, Vue also does that by new rules, more syntax but basically it does not allow write javascript function as tag's attributes
You can use the window-plugin
https://www.npmjs.com/package/window-plugin
<button #click='$window.alert("You clicked a button.")'>Click Me</button>
<button #click='$window.console.log("A button was clicked.")'>Click Me</button>
<button #click='$window.open("https://www.quickchords.org/", "_blank"))'>Click Me</button>
<h1 :v-text='$document.title' />

Vue-js and different layouts

how would one layout the router-views, if you have, lets say 3 different layout to use for you app (e.g. layout for customers, layout for employer and admin-interface).
At the moment i implemented the customer "view" like:
<template>
<div id="app">
<HeaderBar/>
<Navigation></Navigation>
<router-view></router-view>
</div>
</template>
inside the App.vue file. I could use something like:
<div id="app">
<router-view name="header">
<HeaderBar/>
<Navigation></Navigation>
</router-view>
<router-view></router-view>
</div>
</template>
and load different headers for those "subroutes" but this seem's to be odd.
Also what, if i'd like to use an other index.html?
I'm using webpack for this app.
Or would you suggest to create different apps for this?
Many thanks
rene
You could try using dynamic components.
Basically you change which component is being rendered depending on your route.
So it would probably be something like this:
<component v-bind:is="headerComponent"></component>
and then your app can contain heeaderComponent property in data object that has a default value and gets changed when you click on a route that should use different header. Rinse and repeat for the footer.
As for the last question, I think you should only use one app. As it is possible to do and everything is still connected. I'm not sure but I don't know how would you, if need be, communicate between different instances of Vue.