How to replace a navbar with a search div when scrolling down in VueJS3? - vue.js

I am new to vuejs, I am trying to make my search component to replace my fixed-top navbar when the searchdiv hit the top of the screen while scrolling down, and when I scroll up, the navbar will only appear when the user is on top. I have seen this kind of functionaliy like google search. please see:
This is the normal view:
This is the scrolled view:
and this is mine:
Here is my code:
created() {
window.addEventListener('scroll', this.handleScroll);
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
},
mounted() {
console.log("HomeLandingComponent mounted");
},
methods: {
handleScroll() {
let scrollY = window.scrollY
if (scrollY > this.startY) {
this.navbar_visible = false;
} else {
this.navbar_visible = true;
}
this.startY = scrollY;
}
}
what is does is just basically hide the navbar when scroll down and show navbar on scroll up. Is there a way on how to achieve it?

Simple.
Ensure that the search bar comes after the navbar and that the search bar is not nested; then on the search bar, position fixed; z-index: 1; you can use JavaScript to add a new class to give background a new colour.
Shouldn't be too hard. I'll write the code once I'm on my PC.

Related

Can't change transition on the fly for a transition group

In my app, clicking a modal's close button makes it disappear with a fade animation whereas swiping it down makes it disappear with a swipe animation. This is done by changing the modal's <transition name> based on event.
The same thing doesn't seem to work with a transition group. Am I doing something wrong, or is it actually not possible?
CodeSandbox
Template:
<transition-group :name="itemTransition">
<div
v-for="item in items"
:key="item.id"
v-hammer:swipe.up="() => onSwipeUp(notification.id)"
>
</div>
</transition-group>
Script:
export default {
data () {
return {
applySwipeTransition: false
}
},
computed: {
itemTransition () {
return this.applySwipeTransition ? 'swipe' : 'fade'
}
},
methods: {
onSwipeUp (id) {
this.applySwipeTransition = true
this.$nextTick(() => {
this.closeItem(id)
this.applySwipeTransition = false
})
}
}
}
CSS:
.fade-leave-active {
animation: fade-out .75s;
}
.swipe-leave-active {
animation: slide-up .25s;
}
The problem lies in the timing of component update. You are switching the transition mode back to fade in the same update cycle as when the element is closed. Thus, when the next component update is triggered (by removal of the item), the transition is already switched back to fade. At this point, you may have guessed that all that needs to be done, is to switch the transition back in the next update, triggered by removal of the item:
onSwipeUp (id) {
this.applySwipeTransition = true
this.$nextTick(() => {
this.closeItem(id)
this.$nextTick(()=>{
this.applySwipeTransition = false
})
})
}
Since there are no reasons to wait for component update to close the item, you can simplify the code a bit:
onSwipeUp (id) {
this.applySwipeTransition = true
this.closeItem(id)
this.$nextTick(() => {
this.applySwipeTransition = false
})
}
Here is your working sandbox: https://codesandbox.io/s/vue-template-forked-60lkk?file=/src/App.vue
So, I've worked around with your CSS by manually changing the name of the <transition-group to either fade or swipe to see if the there's a problem with the CSS animations.
Verdict: The fade works. swipe only transitions the list-item off the page by a click and drag, not true swipe, if that concerns you (by the way, my swipe is MacOS swipe - two-finger, no click)
Still, without changing the CodePen, the issue seems to be with your computed property where there's nothing telling the name to change dynamically even though you've bound it to a computed property - the logic for itemTransition() seems to always default to fade because the applySwipeTransition would never equal to "swipe", given that the CSS does work when you manually change name to swipe (see "Verdict)".
To see where the underlying issue was, I worked around with your itemTransition():
computed: {
itemTransition() {
return this.applySwipeTransition ? "fade" : "swipe";
},
Switching the order of the fade and swipe now makes swipe work. I hope this gives you some insight into the issue. You may need to create a custom Vue directive or event to handle the swipe / fade logic if needed.

VueJS - How to toggle between dark and light themes in vuexy by clicking on icon

I am trying to toggle between the dark and light themes using icon, i have tried using the radio buttons and it works absolutely fine i don't know where i am going wrong with icons.
Here is the code that works with vs-radio buttons:
<vs-radio v-model="changeTheme" vs-value="light" vs-name="theme-mode-light">Light</vs-radio>
<vs-radio v-model="changeTheme" vs-value="dark" vs-name="theme-mode-dark">Dark</vs-radio>
...
<script>
watch: {
layoutType (val) {
// Reset unsupported options
if (val === 'horizontal') {
if (this.changeTheme === 'semi-dark') this.changeTheme = 'light'
if (this.navbarType === 'hidden') this.navbarTypeLocal = 'floating'
this.$emit('updateNavbarColor', '#fff')
}
}
},
computed: {
changeTheme: {
get () { return this.$store.state.themecolr},
set (val) { this.$store.dispatch('updateTheme', val) }
},
}
</script>
Here is the code which i am trying to achieve currently:
<div class="con-img ml-3">
<feather-icon v-if="this.$store.state.themecolr=== 'light'" icon="Icon" v-model="changeTheme" vs-name="theme-mode-light"/>
</div>
<div class="con-img ml-3">
<feather-icon v-if="this.$store.state.themecolr=== 'dark'" icon="Icon" v-model="changeTheme" vs-value="dark" vs-name="theme-mode-light"/>
</div>
...
methods: {
changeTheme: {
get () { return this.$store.state.themecolr},
set (val) { this.$store.dispatch('updateTheme', val) }
},
}
I tried adding #change and #click to the feather icon but that did not work out, and i also tried adding the function like this :
changeTheme (){
if(this.$store.state.themecolr=== 'light'){
return this.$store.state.themecolr=== 'dark'
}else if(this.$store.state.themecolr=== 'dark'){
this.$store.state.themecolr=== 'light'
}
}
Please someone help me to achieve this, i want to toggle the theme using the feather icons, but i am able to do it with the radio buttons, but that s not what i want.
I looked at the implementation of the vue-feather-icons here
and it is missing the event handlers.
If that is the case, it means those components don't emit any events.
I would suggest you move your event handler to the surrounding div for the icons. see what I did here for an example: https://codesandbox.io/s/distracted-noether-gud0p?file=/src/App.vue

Resize button according to screen size

For a button, by default Bootstrap 4 allow you to set default button "size" between : xs, sm, md, lg, xl.
So, in my code, small screen first, i use sm size for screen <576px :
<button type="button" class="btn btn-success btn-sm"></button>
But for xl screen ≥1200px, need i to change size attribute or something else with Bootstrap to adjust button size ?
I don't really understand Bootstrap responsive behavior for button and 'size' attribute between small and large screen.
Thanks.
I don't think there's anything built out of the box for responsive buttons in bootstrap, you'd probably be better off extending the existing bootstrap button sizes in sass/media queries ie
.responsive-button {
#media (min-width: 576px) { #extend .btn-sm }
#media (min-width: 768px) { #extend .btn-md }
}
I haven't tested this so may need to research a bit further but hopefully this gets you on track :)
According to the Vue.js documentation, i had finally computed my CSS class dynamically according to window.onresizeevent call in mounted () function.
Example :
Here is my Bootstrap button :
<b-button :size="nsize" variant="outline-success" class="my-2 my-sm-0">
<font-awesome-icon icon="search"/>
</b-button>
Here is my function in App.vue file:
<script>
export default {
name: 'topnavbar',
data () {
return {
nsize: "sm",
mediaWidth: Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
}
},
mounted () {
if (window.addEventListener) {
window.addEventListener("resize", this.updateSize, false);
} else if (window.attachEvent) {
window.attachEvent("onresize", this.updateSize);
}
},
methods : {
updateSize: function (){
let sizeEl = "md";
let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(width <= 576){
sizeEl = "sm";
}
this.nsize = sizeEl;
}
}
}
</script>
Sources:
Get the browser viewport dimensions with JavaScript
https://fr.vuejs.org/v2/guide/class-and-style.html

Disable closing of sideNav when click outside the sideNav

I am using sideNav of MaterializeCSS in my application. I do not want to close sideNav while clicking outside. It can be achievable in modals like this:
{ dismissible: false }
How to do this in sideNav?
MaterializeCSS doesn't have a built-in method for achieve this task, but you can use a workaround, unbinding the click event from sideNav overlay:
$(function(){
$(".button-collapse").sideNav();
$(".drag-target").unbind('click');
$("#sidenav-overlay").unbind('click');
});
Update:
As of late, you can modify options of the sidenav by doing the following
$(".button-collapse").sideNav({
menuWidth: 300, // Default is 300
edge: 'left', // Choose the horizontal origin
closeOnClick: false, // clicking outside of the nav will not close it
draggable: true, // Choose whether you can drag to open on touch screens,
onOpen: function(el) { }, // A function to be called when sideNav is opened
onClose: function(el) { }, // A function to be called when sideNav is closed
});
});
you can take a look here to learn more: http://materializecss.com/side-nav.html

Run animation only one time with skrollr

I'm using skrollr to write a website and I need to make some icons appear when the user scrolls the page:
.illustration{
-skrollr-animation-name: icon;
}
#-skrollr-keyframes icon {
300-top {
opacity: 0;
transform: scale(0.2);
}
150-top {
opacity: 1;
transform: scale(1);
}
}
The problem is that I want the icon to appear only one time, so, if the user scrolls up, the icon have not to disappear and then appear again when the user scroll down...
How can I do?
Use this when initializing:
skrollr.init({
beforerender: function(data) {
return data.curTop > data.lastTop;
}
});