Using HeadlessUI Menu with Vue-Router - vuejs3

I am trying to use a HealdessUI menu component together with vue-router. I could find a way to make this work. It seems, that HeadlessUI only works with Links as a sting. But I need to use something like this this.$router.push({ name: item.href, hash: item.hash }.
My routes are named but I need to give it a hash, so it actually scrolls to the anchor-ID on the site.

router.push(...) is for programmatic navigation but there is also <router-link> for declarative navigation that you can put in your component's template code:
<MenuItem v-slot="{ active }">
<router-link to="{ path: '/', hash: '#about' }">About</router-link>
</MenuItem>
Anchor links can be enabled by setting up scrollBehavior in your router file:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
behavior: 'smooth',
}
}
}
})

Related

How to add transistion animation whenever the route is changed in next.js?

I have 2 links in the home page. I need different transition animation for each of these links.
i.e if i click the link button in the left. The transition should start from the left to right with the route change.
You can use framer-motion and wrap the Linked Layout of the page component.
i.e
import { motion } from 'framer-motion';
<motion.div initial="exit" animate="enter" exit="exit">
<motion.div variants={variants}>
<Layout>
...
</Layout>
</motion.div>
</motion.div>
This will animate the landing page onload.
In a nutshell, don't use Next.js's native <Link> tags, but regular <a> with custom event handlers to navigate your page. The event handlers should apply appropriate CSS class to page component to trigger the animation and redirect once the animation has finished. And since you're using Next.js don't forget to manually prefetch your routes!
Start with a simple <a> tag:
<a onClick={redirectToPageB}>Go to page B</a>`
Handle it with a function adding a CSS class to the page container and change your route after 1 second timeout:
const router = useRouter();
function redirectToPageB() {
document.querySelector('#container').classList.add(styles.transitionRight);
setTimeout(() => {
router.push('/page-b');
}, 1000);
}
And lastly, optimize by prefetching the /page-b route:
useEffect(() => {
router.prefetch('/page-b');
}, []);

Alter background color of NavBar inserted in App.vue from within sibling router-view component

I am trying to change the background and text color of my navbar component depending on what page I am on in order to remove contrasting colors with the current pages background. Effectively wanting a light and dark theme variant for the TopNav component that is triggered by what page we are currently on.
My nav bar and page template is as below:
<template>
<v-app>
<TopNav /> ------> This is the navbar component whos css i want to alter
<v-content>
<router-view></router-view> -----> Depending on what the current page injected is.
</v-content>
<Footer />
</v-app>
</template>
Using <style> tags without the scoped attribute work on changing the navbar background but unfortunately it does not revert back after navigating to another page.
Changing state of a component from a sibling level or child level component is really an anti-pattern.
Your best bet is going to be using a well established pattern to get the functionality you're after.
One way to do this is to bring in Vuex, and place your light/dark mode in the Vuex store (shared application level state management)
Then, you could setup your TopNav component to bind to a value in Vuex state (this.$store.state.darkMode for example)
Then, from anywhere in the application, you could commit a mutation to specify light mode, dark mode, toggle, etc...
Or, if you want it to always be route-specific (kinda sounds like this is the case) then you can setup your route definition something like this:
const routes = [
{
path: '/light-component',
name: 'LightComponent',
component: () => LightComponent,
meta: {
darkMode: false,
},
},
{
path: '/dark-component',
name: 'DarkComponent',
component: () => DarkComponent,
meta: {
darkMode: true,
},
},
];
Then, in any component (your TopNav component for example) you could do something like:
<template>
<div :class="darkModeClass">
...
// inside <script> ...
computed: {
darkModeClass() {
return { dark: !!this.$route.meta?.darkMode };
}
}
...
<style scoped>
.dark {
/* css styles for dark mode */
}
</style>

Vue.js: How to change a class when a user has clicked on a link?

I am trying to add a class to an element depending on whether the user has clicked on a link. There is a similar question here but it is not working as I wanted it to be.
I created a component which has its own internal data object which has the property, isShownNavigation: false. So when a user clicks on the a I change isShownNavigation: true and expect my css class isClicked to be added. Alas that is not happening - isShownNavigation stays false in the component when I displayed it {{isShownNavigation}} but I can see in the console that my method is working when clicked.
I imported my header component to the App. Code is below.
Header Component
<template>
<header class="header">
<a
href="#"
v-bind:class="{isClicked: isShowNavigation}"
v-on:click="showNavigation">
Click
</a>
</header>
</template>
<script>
export default {
name: 'header-component',
methods: {
showNavigation: () => {
this.isShowNavigation = !this.isShowNavigation
}
},
data: () => {
return {
isShowNavigation: false
}
}
}
</script>
Application
<template>
<div id="app">
<header-component></header-component>
</div>
</template>
<script>
import HeaderComponent from './components/Header.vue'
export default {
name: 'app',
components: {
'header-component': HeaderComponent
}
}
</script>
I am using the pwa template from https://github.com/vuejs-templates/pwa.
Thanks.
Don't use fat arrow functions to define your methods, data, computed, etc. When you do, this will not be bound to the Vue. Try
export default {
name: 'header-component',
methods: {
showNavigation(){
this.isShowNavigation = !this.isShowNavigation
}
},
data(){
return {
isShowNavigation: false
}
}
}
See VueJS: why is “this” undefined? In this case, you could also really just get rid of the showNavigation method and set that value directly in your template if you wanted to.
<a
href="#"
v-bind:class="{isClicked: isShowNavigation}"
v-on:click="isShowNavigation = true">
Click
</a>
Finally, if/when you end up with more than one link in your header, you will want to have a clicked property associated with each link, or an active link property instead of one global clicked property.

Vue 2.0 Laravel 5.3 Parent Child relationship with slot

I have a project where when i click on a anchor on parent item-sorting-list a property of child item-card will change so it sort something out based on that property. However the data does not seem to pass to the child. I am wondering if there is anything wrong when i built up the parent child relationship in the meanwhile?
template (item-sorting-list)
<a :name="subcat.name" href="" #click.prevent="getSelectedSubcat(subcat.name)">{{subcat.name}}</a>
methods (item-sorting-list)
methods: {
getSelectedSubcat(subcat){
var vm = this;
vm.selectedSubcat = subcat
}
}
When I click on the subcat.name, it does actually store subcat.name into selectedSubcat (verified from Vue devtool) in the item-sorting-list component. The problem is item-card does not store it even though i put selectedSubcat as props
HTML (does this work as parent child relationship here?)
<item-sorting-list><item-card></item-card></item-sorting-list>
UPDATED item-card
export default {
props:[
'selectedSubcat'
],
data(){
return {
products:[],
}
},
mounted() {
this.getAllProducts()
},
methods: {
getAllProducts(){
var vm = this;
vm.$http.get('/getProducts').then((response)=>{
vm.products = response.data.data.products;
});
}
}
}
from Vue devtool, item-card is included in the item-sorting-list, I would say that means they are parent child relationship? but then when i click something in item-sorting-list and change selectedSubcat, selectedSubcat in item-sorting-list does change but the selectedSubcat in item-card remains undefined. Sorry for my bad English.
UPDATE2
I notice that every example that I found online is that they set selectedSubcat in the new Vue with el="#app" in it instead of any other component (in my case item-sorting-list). Does that matter? I feel like the :selected-subcat="selectedSubcat in
<item-sorting-list>
<item-card :selected-subcat="selectedSubcat"></item-card>
</item-sorting-list>
cannot read the selectedSubcat that I defined in the component item-sorting-list but instead if i set selectedSubcat in the following
const app = new Vue({
el: '#app',
data:{
selectedSubcat:1
}
});
it does read selectedSubcat as 1. So what I would say is that item-card does not consider item-sorting-list as its parent. But why and how can I make it to become item-card's parent? [NOTE: but in the Vue devtool the tree does show that item-sorting-list does consist of item-card, item-card does show after clicking the arrow on the left of item-sorting-list]
In VueJs, you have parent child relation, when you don't register a vue component globally, but you make a component available only in the scope of another instance/component by registering it with the components instance option, like following:
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> will only be available in parent's template
'my-component': Child
}
})
In your case, I dont see selectedSubcat being passed as dynamic props to child component item-card. Dynamic props to data on the parent ensures whenever the data is updated in the parent, it will also flow down to the child:
You probably have to pass it to child like following:
<item-sorting-list>
<item-card :selected-subcat="selectedSubcat"></item-card>
</item-sorting-list>
You also have to add props in your item-list like this:
var itemList = {
props: ["selectedSubcat"]
template: '<div>Yout component!</div>'
}
notice I have converted it to kebab-case, because HTML being case-insensitive, camelCased prop names need to use their kebab-case (hyphen-delimited) equivalents(Documentation).

Meteor Flow Router React: I am passing a component as a prop, and I want to include a prop in that component

See this code:
authenticatedRoutes.route( '/study/:studyId/study_settings', {
name: 'study_settings',
action(params, queryParams) {
console.log(queryParams);
Session.set('studyId', params.studyId);
mount( Default, { yield: <PageContainer pageName='Study Settings' page={<StudySettings />}/> } );
}
});
As you can see the page prop? in the mount function? I am passing <StudySettings /> component
well I want to pass a prop into this component
but when I try <StudySettings queryPage=queryParams.subPage /> I get compile error.
How can I do this?
When you want to pass a prop to a ReactJS Component that is a variable you need to use {} so in your case you need to do something like this
<StudySettings queryPage={ queryParams.subPage } />
Let me know if you have anyother questions!

Resources