How to make Fixed navbar with vue js? - javascript

I try build a landing page using vue.js, with header design like on the picture above.
So, I create a component called "header",with contain content according to the design.
How do I make a fixed navbar, when the page is scrolled the navbar is still on top ?

Another option could be to use the bootstrap-vue package.
It has the b-navbar component which can be made fixed to the
top
<b-navbar class="header" fixed="top"></b-navbar>
Example:
const vm = new Vue({el: '#app'})
<link href="http://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css" rel="stylesheet"/><link href="http://unpkg.com/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"/><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script src="http://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script><script src="http://unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script><div id="app">
<!-- ************************************ -->
<!-- Place the fixed prop within b-navbar -->
<!-- ************************************ -->
<b-navbar class="header" type="dark" variant="info" fixed="top">
<b-navbar-brand href="#"> My fixed header </b-navbar-brand>
</b-navbar>
<!-- *********************************** -->
<div style="margin-top: 60px;"><ol><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li><li>link</li></ol></div></div>

You can set a fixed navbar by applying the following class.
.header {
position:fixed; /* fixing the position takes it out of html flow - knows
nothing about where to locate itself except by browser
coordinates */
left:0; /* top left corner should start at leftmost spot */
top:0; /* top left corner should start at topmost spot */
width:100vw; /* take up the full browser width */
z-index:200; /* high z index so other content scrolls underneath */
height:100px; /* define height for content */
}
An element with position:fixed; property doesn't change when the window is scrolled, so a fixed positioned element will stay right.

new Vue({
el: "#app",
data:{
active: false
},
methods: {
toggleNavClass(){
if(this.active == false){
return 'nav'
} else {
return 'sticky-nav'
}
}
},
mounted(){
window.document.onscroll = () => {
let navBar = document.getElementById('nav');
if(window.scrollY > navBar.offsetTop){
this.active = true;
} else {
this.active = false;
}
}
}
})
/*scrollY returns the scroll amount in pixels.
offsetTop is the px difference between the navBar and closest parent element*/
body {
margin: 0;
box-sizing: border-box;
}
#app {
color: #2c3e50;
background-color: #ccd6dd;
height: 120vh;
}
a {
font-weight: bold;
color: white;
text-decoration: none;
margin: 0 1vw;
}
a:hover {
transition: linear 100ms;
color: red;
}
/* two classes, decided on scroll */
.nav {
transition: 100ms;
padding: 25px;
}
.sticky-nav{
transition: 100ms;
padding: 20px;
}
#nav {
display: flex;
justify-content: space-between;
width: 100%;
background-color: #55acee;
position: fixed;
top: 0;
}
/* have to add the ID nav (#nav) otherwise the backgrnd color won't change as the previous background color is set in an ID and ID trumps class notation */
#nav.sticky{
transition: 150ms;
box-shadow: 0px 15px 10px -15px #111;
background-color: #ccd6dd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="nav" :class="{sticky:active}">
<div id="nav-container" :class="toggleNavClass()">Menu
</div>
<router-view />
</div>
I just built a site using Vue.
This is my code

Related

Is it possible to change the autoscroll offset when dragging?

I have a single-page app written in Vue.js. The UI comprises three main elements:
a navbar with position: fixed at the top and z-index: 2
a sidebar with position: fixed on the left and z-index: 1 and padded to account for the presence of the navbar
a central area, padded to account for the presence of the other fixed elements.
The sidebar is scrollable with overflow-y: auto. Some elements in the sidebar, that I designated here with the text item X, are draggable.
Normally, when dragging towards the edges of a scrollable area, the area will automatically scroll in that direction. In my application the sidebar does not auto-scroll, because the upper edge is hidden by the navbar.
An obvious solution would be to change the structure of the sidebar so that its upper edge lies visible instead of being one top-padded div. However this might break other things.
Question:
I would like to know if there's a way to trigger auto-scroll on drag when the mouse is arbitrarily close to the edge, e.g. $navbarHeight pixels.
I'm looking for a pure HTML5 solution, vanilla js, or something with my current framework (Vue.js v3).
What I already tried:
I've done a great deal of googling but I'm probably using the wrong search queries: "auto scroll while dragging", "scroll sensitivity area", "autoscroll offset", and several combinations of quotes did not yield relevant results.
JS Fiddle: https://jsfiddle.net/7f5wh1mj/4/
What the page looks like (see the fiddle for a working example):
Nowdays, you may use grid to create such layouts , here is an example without position but grid ;)
new Vue({
el: "#app",
data: {
todos: [{
text: "Learn JavaScript",
done: false
},
{
text: "Learn Vue",
done: false
},
{
text: "Play around in JSFiddle",
done: true
},
{
text: "Build something awesome",
done: true
}
],
items: 12
},
methods: {
toggle: function(todo) {
todo.done = !todo.done
}
}
})
* {
box-sizing: border-box;
/* reset , optionnal */
}
body {
background: #20262E;
font-family: Helvetica;
overflow: hidden;
margin: 0;
height: 100vh;
/* needed */
width: 100vw;
}
#app {
background: #fff;
display: grid;
grid-template-columns: 150px 1fr;
grid-template-rows: auto 1fr;
height: 100%;
/* do not remove */
}
.navbar {
grid-row: 1;
grid-column: 1 / 3;
padding: 0.5em;
background-color: lightgreen;
}
.sidebar {
background-color: lightgray;
/* z-index: 1; no need */
overflow-y: auto;
}
.content {
background-color: #fff;
/* z-index: 0; no need */
overflow: auto;
/* make it scroll too instead body */
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
aside p {
text-align: center;
color: white;
background:gray;
position:sticky;
top:0;
margin:0;
padding:0.25em 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="navbar">
<h1>Navbar</h1>
</div>
<aside class="sidebar">
<p>Sidebar</p>
<ul>
<li draggable v-for="n in items">item {{ n }}</li>
</ul>
</aside>
<div class="content">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<input type="checkbox" v-on:change="toggle(todo)" v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
</div>
edit : added comment and a sticky example inside the sidebar.

Showing a dropdown on click instead of on hover

I am using Avada (fusion-theme) theme on Wordpress for my website (under construction).
They have a mega-menu option that I am using, but I would want it to appear when someone clicks on the main-menu item instead of hovering over it.
Site: www.paradigmtek.com
So right now if someone hovers over say "smart home" at the top, the sub menu appears (smart home tech support, smart hub or speaker setup, etc.). But I would like it to appear on click instead of on hover.
I don't think this will require not a simple CSS trick, but a JS one.
Anyone has experience with that theme or know how to do it?
You can simply add a class to change the opacity of the dropdown menu upon clicking one of the menus. In this example below, I'm adding show class to dropdown to change opacity from 0 to 1 upon clicking the menu. At the same time, I'm addding a class to the clicked menu (i.e. clicked) to give it an accent colour to indicate that it is the menu being clicked.
const menus = document.querySelectorAll('.menu')
const dropdown = document.querySelector('.dropdown')
let activeMenu = null
menus.forEach(menu => {
menu.addEventListener('click', e => {
// Removing previous active menu that is not itself
if (activeMenu && activeMenu !== menu) {
activeMenu.classList.remove('clicked')
activeMenu = menu
}
else if (activeMenu && activeMenu === menu) {
activeMenu = null
} else {
activeMenu = menu
}
menu.classList.toggle('clicked')
// If there is an active menu, show
if (activeMenu) dropdown.classList.add('show')
else dropdown.classList.remove('show')
})
})
* {
box-sizing: border-box;
font-family: Helvetica;
}
html,
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.container {
display: flex;
justify-content: center;
background: #121212;
}
.menu {
color: white;
margin: 20px;
padding: 20px;
border-radius: 5px;
cursor: pointer;
}
.menu:hover {
color: #ff8888;
}
.menu.clicked {
color: #ff8888;
}
.dropdown {
width: 100%;
height: 100px;
background: #333333;
display: flex;
flex-direction: column;
opacity: 0;
transition: opacity 0.5s ease;
}
.dropdown.show {
opacity: 1;
}
.line {
width: 100%;
height: 3px;
background: #00a5ff;
}
<div class="container">
<div class="menu">Menu 1</div>
<div class="menu">Menu 2</div>
<div class="menu">Menu 3</div>
<div class="menu">Menu 4</div>
</div>
<div class="dropdown">
<div class="line"></div>
</div>
In the options: avada options -> menu -> submenu
You just have to specify hover / click with the select button.
You can also build your own menu by creating a layout
-> avada -> layout
In your layout you can add a menu element on which you apply the wanted options.
Getting Started With Avada Layouts
Understanding Custom Headers
How To Use The Menu Element

how to assign an Event to an element that may change based on screen size

Background: I am using a snippet of JQuery to assign an event to an element based on its ID. That event slides a menu from the left side of the screen.
Question: When the screen size changes to < 710px I am going to hide the original element and show a new element (which is just a different icon). But I want that new element to trigger the same event.
Should I just assign the event to both elements one after another or can I combine that into one Event?
Below is an example of my HTML JS and CSS
PLEASE NOTE THE TRIGGER WILL NOT WORK UNLESS THE TEST WINDOW IS ABOVE 711PX
window.onload = function(){
document.getElementById('megga-nav-toggle').addEventListener('click', function () {
var documentBody = $('#megga-global-menu');
documentBody.toggleClass('is-active');
if (documentBody.hasClass('hide-megga')) {
documentBody.removeClass('hide-megga');
return;
}
documentBody.addClass('hide-megga');
});
document.getElementById("megga-global-menu").addEventListener("mouseleave", menuHide);
};
function menuHide() {
document.getElementById("megga-global-menu").classList.add('hide-megga');
}
#megga-global-menu {
background: red ;
position: fixed;
top: 50px;
bottom: 0;
left:0px;
width: 200px;
z-index: 1000000;
transition: ease all .6s;
}
#megga-global-menu.hide-megga {
left: -200px;
transition: ease all .6s;
}
#megga-nav-toggle {
display: inline-block;
z-index:999998;
font-size: 30px;
color: #000;
cursor: pointer;
}
#media screen and (min-width: 710px) {
#megga-navmobile-toggle {
display:none;
}
}
#media screen and (max-width: 710px) {
#megga-nav-toggle {
display:none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<span id="megga-nav-toggle">FULL SCREEN</span><Bn/><Br/>
<span id="megga-navmobile-toggle">MOBILE SCREEN</span>
<div id="megga-global-menu" class="">
My slide out menu goes here!
</div>
I'm not sure I understand your problem, but if you want just show different icon based on screen size, why not put both of them in the same element and display the wanted icon with #media?
#media screen and (min-width: 710px) {
#megga-navmobile-toggle-icon { display: none; }
}
#media screen and (max-width: 710px) {
#megga-nav-toggle-icon { display: none; }
}
And your html should be:
<div id="megga-nav-toggle">
<span id="megga-nav-toggle-icon">FULL SCREEN</span><Bn/><Br/>
<span id="megga-navmobile-toggle-icon">MOBILE SCREEN</span>
</div>

Change header background and font-color after scrolling through gray section

I want to add a class to header after (gray)section scroll is over. And remove the same class when (gray)section reappers on scroll-up.
https://jsfiddle.net/tgLybw2e/1/
$(window).scroll(function(event){
didScroll = true;
});
You can use a window.onscroll function along with window.scrollY to detect when the screen has scrolled to the bottom of the gray element, then add a class.
This could be made more dynamic by using JS to get the height of the gray element so it doesn't need to be hardcoded to the same value as set in CSS.
window.onscroll = function() {
var header = document.getElementById('header');
if (window.scrollY > 630) {
header.classList.add('updated-class');
} else {
header.classList.remove('updated-class');
}
}
header{
height: 70px;
border-bottom: 1px solid #000;
position: fixed;
color: #fff;
left:0;
right:0;
text-align:center;
}
header.changeColor{
color: 000;
}
section{
height: 700px;
background: #cdcdcd;
}
section + section{
background: #fff;
}
.red{
background:red;
}
.updated-class {
background-color: red;
transition: background 1s linear;
}
<header id="header">
abcfdff
</header>
<section>
</section>
<section>
</section>
<section class="red">
</section>
Try this,
$(window).scroll(function(event){
if (window.scrollY > 700) {
$('header').addClass('changeColor');
}else
$('header').removeClass('changeColor');
});
jsFiddle for the same
https://jsfiddle.net/tgLybw2e/2/
step one1
On window load add class to header & count height of gray section
step 2
On event window scroll count scroll Y of window
step 3
create function to compare gray height = window scroll Y,
when its true, remove class from header.

Float image from left to right with a animation?

I have a hamburger (three horizontal bars) icon I want to change from float: left to float:right but with a smooth animation.
I can't use jQuery but I can use JavaScript so I have this small function that changes float state when the image is clicked:
var menuButton = document.getElementById('menu-button');
menuButton.onclick = function () {
menuButton.style.float = "right";
}
So this works but not smooth animation how can I make it a smooth animation?
A running demo:
var menuButton = document.getElementById('menu-button');
menuButton.onclick = function () {
menuButton.style.float = "right";
}
nav {
background: pink;
height: 60px;
}
nav #menu-button {
margin: 20px 24px;
display: inline;
float: left;
}
<nav id="nav-bar">
<img id="menu-button"alt="menu icon" src="images/toggle-open.svg">
</nav>
If you know the width of your container, do not use float properties but margin-left :
a {
margin-left: 0;
transition: margin-left 1s ease-in-out;
}
a.right{
margin-left: 400px; /* change for good value */
}
Then add right class to your a element with javascript
https://jsfiddle.net/rd4h4s5h/
Unfortunately, changing left-to-right float can't be simply animated with any current tech, because an animation requires a relative anchor-point from which to perform calculations.
What you could do is animate the relative left-floated position, to an approximated right-floated position (by increasing left-margin, for example), and upon completion, change to a right-float. But really, the last step isn't necessary, except to handle future layout changes to the page (e.g. window resize, for a fluid-width site).
I was able to get this working using CSS3 transitions and marginLeft.
There's a little hackery in the parentElement.parentElement (to climb two levels of the DOM tree), and in the -44px to account for the icon width plus margin width, but if you wanted to, you could write more complex coded solutions to these (handling the element's actual width / margin on the fly).
var menuButton = document.getElementById('menu-button');
menuButton.onclick = function () {
var left = menuButton.parentElement.parentElement.clientWidth - 44;
menuButton.style.marginLeft = left+"px";
window.setTimeout(function() {
menuButton.style.float = "right";
}, 1000);
}
nav {
background: pink;
height: 60px;
}
nav #menu-button {
margin: 20px 24px;
display: inline;
float: left;
/* Width and height hack to represent missing image's height and width */
width: 20px;
height: 20px;
/* CSS Transition added */
-webkit-transition: margin-left 1s;
transition: margin-left 1s;
}
<nav id="nav-bar">
<img id="menu-button"alt="menu icon" src="images/toggle-open.svg">
</nav>
I would do it this way:
<style>
nav {
position: relative;
}
nav a {
position: absolute;
left: 0;
transition: left 1s linear;
}
</style>
<nav id="nav-bar">
<a id="box" href="#/index"><img id="menu-button" alt="menu icon" src="images/toggle-open.svg"></a>
</nav>
<script>
const navBar = document.getElementById("nav-bar");
const box = document.getElementById("box");
const menuButton = document.getElementById("menu-button")
menuButton.addEventListener("click", (e) => {
box.style.left = (navBar.offsetWidth - box.offsetWidth) + "px";
});
</script>

Categories

Resources