I am developing a website currently, and have run into a small problem.
===
Steps to reproduce:
1.npm create svelte@latest test
(skeleton, typescript, eslint-prettier-playwright-vitest)
2.cd test
3.npm i
4.npm run dev -- --open
(to open in browser for debugging)
5.Create src/components/Navbar.svelte
with the following contents:
<script lang="ts">
import { onMount } from 'svelte';
function toggleHamburgerMenu() {
var x = document.getElementById('myLinks') as HTMLDivElement;
if (x.style.display === 'block') {
x.style.display = 'none';
} else {
x.style.display = 'block';
}
}
function getTranslatedPagePath(): string {
switch (window.location.pathname) {
case '/':
return 'nav.about';
case '/services':
return 'nav.services';
case '/updates':
return 'nav.updates';
case '/photos':
return 'nav.photos';
case '/contact':
return 'nav.contact';
case '/links':
return 'nav.links';
default:
return '';
}
}
$: currentTab = 'nav.about';
onMount(() => {
currentTab = getTranslatedPagePath();
function closeTopnav(this: HTMLAnchorElement) {
var x = document.getElementById('myLinks') as HTMLDivElement;
x.style.display = 'none';
currentTab = this.innerHTML;
}
// topnav doesnt close automatically when clicking on a link
const links = document.getElementsByClassName('topnav_link') as unknown as HTMLAnchorElement[];
for (let i = 0; i < links.length; ++i) {
links[i].addEventListener('click', closeTopnav);
}
// hide topnav when clicking outside
document.addEventListener('click', (e: MouseEvent) => {
var x = document.getElementById('topnav-wrapper') as HTMLDivElement;
var y: Node = e.target as Node;
var z = document.getElementById('myLinks') as HTMLDivElement;
if (!x.contains(y) && z.style.display == 'block') {
z.style.display = 'none';
}
});
});
</script>
<head>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
/>
</head>
<div id="topnav-wrapper">
<div>
<a href="/"><img src="" alt="Logo" /></a>
</div>
<div class="topnav">
<div id="content">
<a href="" class="active">{currentTab}</a>
<a href="" class="icon" on:click={toggleHamburgerMenu}>
<i class="fa fa-bars"></i>
</a>
</div>
<div id="myLinks">
{#each 'about, services, updates, photos, contact, links'.split(', ') as link}
{#if `nav.${link}` !== currentTab}
<a class="topnav_link" href="/{link === 'about' ? '' : link}">{`nav.${link}`}</a>
{/if}
{/each}
</div>
</div>
</div>
<style>
#topnav-wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
overflow: visible;
z-index: 100;
/* background-color: rgba(255, 255, 255, 0.6); */
margin: 0;
padding: 0;
}
.topnav {
overflow: hidden;
/* background-color: #333; */
/* width: fit-content; */
/* height: fit-content; */
margin: 1.5rem;
}
/* Hide the links inside the navigation menu (except for logo/home) */
.topnav #myLinks {
display: none;
position: absolute;
top: inherit;
left: inherit;
background-color: #333;
pointer-events: all;
}
/* Style navigation menu links */
.topnav a {
color: white;
padding: 14px 16px;
text-decoration: none;
display: block;
/* width: fit-content; */
background-color: rgba(255, 255, 255, 0.74);
color: black;
font-size: 1.5rem;
}
/* Style the hamburger menu */
.topnav a.icon {
background: black;
display: block;
}
/* Add a grey background color on mouse-over */
.topnav a:hover {
background-color: #ddd;
color: black;
}
/* Style the active link (or home/logo) */
.active {
background-color: rgb(135, 206, 235);
color: white;
}
img {
position: absolute;
top: 0;
left: 0;
}
#content {
display: flex;
}
#logo {
background-color: white;
opacity: 70%;
}
@media screen and (min-width: 320px) {
#logo,
img {
width: 115px;
height: 50px;
margin-left: 15px;
}
img {
top: 20px;
}
}
@media screen and (min-width: 520px) {
#logo,
img {
width: 135px;
height: 55px;
}
img {
top: 20px;
}
}
@media screen and (min-width: 720px) {
#logo,
img {
width: 155px;
height: 65px;
margin-top: 10px;
}
img {
top: 15px;
}
}
@media screen and (min-width: 920px) {
#logo,
img {
width: 175px;
height: 70px;
}
img {
top: 10px;
}
}
@media screen and (min-width: 1120px) {
#logo,
img {
width: 195px;
height: 75px;
margin-top: 20px;
}
img {
top: 10px;
}
}
@media screen and (min-width: 1320px) {
#logo,
img {
width: 215px;
height: 80px;
}
img {
margin-top: 5px;
}
}
@media screen and (min-width: 1520px) {
#logo,
img {
width: 235px;
height: 90px;
}
img {
top: 10px;
}
}
@media screen and (min-width: 1720px) {
#logo,
img {
width: 255px;
height: 100px;
margin-top: 20px;
}
img {
top: 10px;
}
}
@media screen and (min-width: 1920px) {
#logo,
img {
width: 275px;
height: 110px;
margin-top: 20px;
}
img {
top: -10px;
}
}
img {
top: 0px; /* TODO: responsive */
margin-top: 0px;
}
#content a {
background-color: transparent;
color: black;
font-size: 1.5rem;
}
</style>
6.Create src/routes/+layout.svelte
:
<script>
import Navbar from '../components/Navbar.svelte';
</script>
<Navbar />
<slot />
7.Create /(about), services, updates, photos, contact, links
routes with a simple h1
to mention the page title to easily understand which route we are in.
8.Go to the browser tab, open the burger menu on the top right, click through every link. Afterwards, if you try to click any of them, the title will not update, the links list will not update deleting the current page link, and the burger meu will not close(but we will go to correct page).
===
The problem I have is that after the first iteration through every link in the navbar, they get cached (or something along those lines I am not quite sure of the underlying mechanisms of svelte) and when I try to click them again:
- The navbar currentTab title doesn’t update,
- The links dont get updates, so I see the link of the currentTab which I shouldn’t
The common thing in both those problems is currentTab, I tried to make it a simple var to see if it changes anything but it doesn’t so I kinda run out of ideas.
Anybody knows how to fix this?
Expected:
- The navbar component to update on each
<a>
link click, so the title and the list of links update (and the burger menu to close).