Let's build Vue directives: Scrolling elements into view (2024)

TL: DR - take me to the code

It is one of those features that slowly but steadily found its way into most of the content-heavy pages, such as blogs or documentations. Scrolling elements into view gives your user an intuitive shortcut to the content they'd like to read about.

Reasons for a Vue directive

You might wonder - why would I need Javascript, even more, a Vue directive for this? I can use built-in HTML and CSS properties, such as href="#headline" in combination with scroll: smooth.

In fact, you can. If you don't mind a few limitations:

  • A fixed navbar might be in the way of your heading
  • You have to give every heading a fixed id or create it with Javascript
  • Globally applied smooth scrolling sometimes leads to some funny side effects when using SPA routers

You could arguably also use vanilla Javascript. Then again, the nature of Vue directives allows for a quick and reusable implementation.

Please note that this article focuses on Vue 3, in which custom directives are handled slightly different than in Vue 2. Check out the linked code sandboxes in TL:DR for differences in main.js and the vScroll.js directive file.

Setup a Vue 3 Project with Vite

We'll use Vite to spin up a basic application. You can alternatively use Vue CLI.

Change into a directory of your choice and type:

# 1: Init your projectnpm init vite@latest # using Vite with npm# yarn create vite # using Vite with yarn# vue create . # using Vue CLI# 2: Change into the created folder and start the dev servercd vite-projectnpm installnpm run dev

Make the app object available for directive registration

Before registering our custom directives, let's make a small adjustment in Vue's main file. It uses createApp on the fly, but we need the created app object to register components on.

This step is optional, you could also chain .directive() as part of the createApp bootstrapping process.

// Inside main.js: Change this import { createApp } from 'vue'import App from './App.vue'createApp(App).mount('#app')// ------// to import { createApp } from 'vue'import App from './App.vue'const app = createApp(App)// ... register directives hereapp.mount('#app')

With app.directive(directiveName, directiveFunction), we're now able to register our own directives everywhere in the app.

Create the scroll directive

For this purpose, we require two browser functions, both of which are available in all major browsers.

  • domElement.getBoundingClientRect() to receive the element's coordinates
  • window.scroll() to scroll to the calculated part of the window

What's left for us to do is to:

  • calculate the difference between the current window position and the element (1)
  • make the window scroll to that calculated position (2)

So let's move ahead and create a folder in the /src folder named /directives. Inside it, create a file named vScroll.js and paste the following code into it:

const vScroll = { mounted: (el) => { el.style.cursor = 'pointer'; el.addEventListener('click', () => { const coord = el.getBoundingClientRect().top + window.scrollY; //(1) window.scroll({ top: coord, behavior: 'smooth' }); //(2) }); },};export default vScroll;

Now let's go back into the main.js file and register vScroll:

import { createApp } from 'vue'import App from './App.vue'import vScroll from './directives/vScroll'const app = createApp(App)app.directive('scroll', vScroll)app.mount('#app')

Use the directive on the template

Now what's left to do is to check whether the directive works as intended. Let's go ahead and replace the content of the App.vue file with a Lorem Ipsum template.

Try adding v-scroll to any of the h2 - tags. Now, when clicking on them, they will be smoothly scrolled to the upper part of the window.

<h2 v-scroll>Cursus mattis</h2>

What about the fixed navbar problem?

The solution in a nutshell: You can bind values to directives! In this case to add a vertical offset when scrolling to an element. These bindings can be accessed the same way as the element itself, given they are passed as an argument in the directive's lifecycle function. In our case, binding.value will resolve to a number we want to subtract from the scroll-top position.

In the vScroll.js file:

const vScroll = { mounted: (el, binding) => { el.style.cursor = 'pointer'; el.addEventListener('click', () => { let coord = 0; coord = binding.value ? el.getBoundingClientRect().top + window.scrollY - binding.value : el.getBoundingClientRect().top + window.scrollY; window.scroll({ top: coord, behavior: 'smooth' }); }); },};

In the HTML template:

<h2 v-scroll="200"> Pharetra magna</h2><p> Congue quisque egestas diam in arcu cursus euismod quis viverra. Pharetra magna ac placerat vestibulum lectus mauris ultrices.....</p>

If everything went well, you now have a functional directive you can include in any new or existing project.

There's more to it

As you can see, we achieved this functionality fairly easily. You can move even further and extend the directive. For example, dynamically add an icon before the text or mutate the element's style whenever a user interacts with it. If you'd like to get an even deeper understanding of Vue directives, make sure to take a look into the official docs for Vue 3.

https://v3.vuejs.org/guide/custom-directive.html

Let's build Vue directives: Scrolling elements into view (2024)
Top Articles
All About Zendaya’s Parents, Claire and Kazembe
Valutakoersen vreemde valuta. Wisselkoersen en omrekenen.
Mybranch Becu
Gamevault Agent
Arkansas Gazette Sudoku
Jonathon Kinchen Net Worth
Southside Grill Schuylkill Haven Pa
Sarah F. Tebbens | people.wright.edu
Acts 16 Nkjv
Gameday Red Sox
Tabler Oklahoma
Clairememory Scam
Blue Ridge Now Mugshots Hendersonville Nc
Olivia Ponton On Pride, Her Collection With AE & Accidentally Coming Out On TikTok
Jasmine Put A Ring On It Age
General Info for Parents
Evil Dead Rise Showtimes Near Regal Columbiana Grande
Operation Cleanup Schedule Fresno Ca
Fool’s Paradise movie review (2023) | Roger Ebert
Letter F Logos - 178+ Best Letter F Logo Ideas. Free Letter F Logo Maker. | 99designs
Lancasterfire Live Incidents
Iu Spring Break 2024
Mission Impossible 7 Showtimes Near Marcus Parkwood Cinema
Is The Yankees Game Postponed Tonight
Imouto Wa Gal Kawaii - Episode 2
Blackboard Login Pjc
The Eight of Cups Tarot Card Meaning - The Ultimate Guide
UCLA Study Abroad | International Education Office
Is Light Raid Hard
Ewg Eucerin
Bad Business Private Server Commands
Have you seen this child? Caroline Victoria Teague
Fedex Walgreens Pickup Times
Jambus - Definition, Beispiele, Merkmale, Wirkung
Flixtor Nu Not Working
KITCHENAID Tilt-Head Stand Mixer Set 4.8L (Blue) + Balmuda The Pot (White) 5KSM175PSEIC | 31.33% Off | Central Online
RALEY MEDICAL | Oklahoma Department of Rehabilitation Services
Kerry Cassidy Portal
Anhedönia Last Name Origin
Craigslist Boats Dallas
Go Bananas Wareham Ma
Directions To The Closest Auto Parts Store
The Conners Season 5 Wiki
Cl Bellingham
Walmart 24 Hrs Pharmacy
Kate Spade Outlet Altoona
Rocket League Tracker: A useful tool for every player
Waco.craigslist
Tito Jackson, member of beloved pop group the Jackson 5, dies at 70
Grace Family Church Land O Lakes
Craigslist Com Brooklyn
O.c Craigslist
Latest Posts
Article information

Author: Mr. See Jast

Last Updated:

Views: 5720

Rating: 4.4 / 5 (55 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Mr. See Jast

Birthday: 1999-07-30

Address: 8409 Megan Mountain, New Mathew, MT 44997-8193

Phone: +5023589614038

Job: Chief Executive

Hobby: Leather crafting, Flag Football, Candle making, Flying, Poi, Gunsmithing, Swimming

Introduction: My name is Mr. See Jast, I am a open, jolly, gorgeous, courageous, inexpensive, friendly, homely person who loves writing and wants to share my knowledge and understanding with you.