Access slot variable or method in Nuxt 3 layout - vue.js

I am wondering if there is a way to get access to <NuxtPage /> or <slot /> variables
I have a layout like this
custom.vue
<div>
<button #click="backButton" />
<NuxtPage ref="loadedPage" />
<!-- or -->
<slot ref="loadedPage" />
</div>
and will like to have the function backButton be used from the page that was rendered.
I tried using defineExpose({backButton}) on the page (say about.vue) and access it inside the custom.vue as
const loadedPage = ref(null)
onMounted(()=>{
console.log(loadedPage.value)
})
but I can not still access it, also using useSlots.default() is not exposing it.
Is it possible to access the backButton function?
The functions are from the pages and I will like to access them in layout, I can create the function there because each page handles the function differently.
Reproduction: https://stackblitz.com/edit/github-qjeqtb?file=layouts/default.vue

Related

How do you create a component with a default Slot and include it in the main layout in Qwik?

Let's say I want to create my own Link.
const Link = ({ href, style }) => {
return <a href={href} class={style}>
<Slot />
</a>
}
Now I want to use this Link in the Menu of my website, and the Menu component is imported inside the main layout.
// main layout
<Menu />
<Slot />
<Footer />
Here, I get this error:
[vite] Internal server error: can not be rendered because one of its ancestor is already a .
This goes against the HTML spec: https://html.spec.whatwg.org/multipage/dom.html#interactive-content
Why does this happen? It's because inside the main layout, we practically included another <Slot /> by including <Menu /> which contains <Link /> components.
So, what do you think we should do here?
If we ask all developers to specify the name of the slot, that's highly inefficient and dirty:
<Link href="/">
<span q:slot='link'>About us</span>
</Link>
This is very ugly and inefficient. I don't have many slots in my Link component. I have one Slot. I should not be specifying a name for it.
What should I do?

VueJS Reusable template parts

I have a component where I have a few blocks that repeat throughout the template.
These blocks may have a conditional or two, and might call some methods in event handlers, but mostly they're pretty simple.
It is really not worth creating an entire, separate component for a few elements, plus passing around data and methods isn't exactly trivial - and it makes the component more difficult to maintain. These blocks won't be used in any other components.
I really need to be able to define a "subcomponent" or "template" inside this component for these blocks.
(I don't think this is possible yet, but that's why you're here)
Has anyone figured out a clean solution for this?
Components can be defined as render functions, and this is especially easy with JSX:
const ComponentA = props => (
<div>
<label>{props.label} <input type="text" /></label>
</div>
)
You could declare multiple subcomponents as render functions (or full component definition objects if needed) in the same file, and reuse them in the component's template. Vue 3's <script setup> block also helps to make this more concise:
<script lang="jsx" setup>
const SubComponentA = (props) => (
<div>
<label>{props.label}</label>
<input type="number" />
</div>
)
const SubComponentB = (props) => (
<div>
<label>{props.label}</label>
<textarea />
</div>
)
</script>
<template>
<SubComponentA label="Label 1" />
<SubComponentB label="Label 2" />
<SubComponentA label="Label 3" />
<SubComponentB label="Label 4" />
</template>
demo

Vue - detect component inside slot

I have this slot inside my tile component. I basically need to detect a specific other component which is supposed to be used inside this slot BUT the slot also supports other html tags not just this specific component. Is there a way to detect a special component e.g. <listitem /> inside the slot?
<div class="tile">
<template v-if="$slots['headline']">
<slot name="headline" />
</template>
</div>
Edit
The basic idea is the following
<tile>
<template #headline>
<listitem />
</template>
</tile>
<tile>
<template #headline>
<h1>Some headline</h1>
</template>
</tile>
I have those two options on how you can utelise this header slot. If there is a just a normal html tag e.g. <h1>, I would like to apply the corresponding css styles. If there is the <listitem /> component I need to apply other styles
As content of the slot is passed to the component as an array of VNode's accessible via this.$slots (in case of scoped-slots it is function returning array of VNode's) you can write a function like this:
methods: {
isListitem() {
return this.$slots.headline && this.$slots.headline[0].tag.endsWith('-listitem')
}
}
Main problem is that $slots is not reactive
Docs:
Please note that slots are not reactive. If you need a component to re-render based on changes to data passed to a slot, we suggest considering a different strategy that relies on a reactive instance option, such as props or data
So I don't recommend doing this and follow the Vue documentation suggestion to use props instead...
Maybe you can use a function to try to get this element by js, something like this:
I am not sure if its will works
function checkElement(){
var listitem = document.querySelector("listitem");
if(listitem) {
// if exist do something
}
}

how to create hyperlink to got to next component from one component in react like a tag does?

****(The main issue Link should work, but it should be encapsulate inside the router. If encapsulated than obviously , it would like nested router. which i dont want. i just want to render register component only when i click the link below)****
return (
<h1>Login Page</h1>
Its the login form, no issue with login form
<form action="">
<button }>Login</button>
</form>
<
**(The main issue is this should work, but it should be encapsulate inside the router. If encapsulated than obviously , it would like nested router. which i dont want. i just want to render register component only when i click the link below)**
<Link to="" component={Register}> Create Account </Link>
</div>
);
Could you try and use Link to declare the path, then use Route inside a switch to give functionality.
<h1>Login Page</h1>
Its the login form, no issue with login form
<form action="">
<button>Login</button>
</form>
<Link to="path/here" component={Register}> Create Account </Link>
<Switch>
<Route path="path/here">
< Register />
</Route>
</Switch>
Of course you will have to import Route and Switch

VUE same component instance at difference route

I am design an Vuejs app which page render based on route.
e.g. for
route = /, Component = Main.vue
<template>
<div>
<toolbar :user="user"></toolbar>
<app-content></app-content>
</div>
</template>
route = /:user, Component = User.vue
<template>
<div>
<toolbar :user="user"></toolbar>
<userHeader></userHeader>
<app-content></app-content>
</div>
</template>
When the page is show, the toolbar component will fetch data from server, the problem is, when the page go from / to /user, the data fetching data X 2 because that are 2 toolbar components in the app itself.
How should resolve this issue ? is that any way to reuse share component instances like toolbar ?
or should i put the design in one whole component instead ? ( use v-if to show hide the additional component)
You should be having <toolbar /> outside of <router-view></router-view>.
So your code should look like:
<div id="app">
<toolbar user="user" />
<router-view />
</div>
With this <toolbar /> won't change even if you change your routes, and will result in data fetching for a single time only.