Learning framework languages and writing code is the fastest way to get started. In order to add new features to blogs built on VitePress, the following progress bar component was born following Vue3.

Experience the address – handwritten Code Snippets series

To create a progress bar that indicates the scrolling percentage of the page, there are two main considerations and one consideration:

  • useposition: fixedPlace the scroll bar at the top of the page,z-indexA large value is set to ensure that the element is at the top of the page content.
  • useEventTarget.addEventListenerElement.scrollTopTo determine the scroll percentage of the document and set it to the width of the scroll progress bar.
  • Think – what happens if the page container height changes?

💠 core

<div id="scroll_progress_bar"></div>
Copy the code
#scroll_progress_bar {
  position: fixed;
  top: 0;
  width: 0%;
  height: 4px;
  background: #7983ff;
  z-index: 10000;
}
Copy the code
const scrollProgress = document.getElementById('scroll_progress_bar');
// Scroll bar height
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;

window.addEventListener('scroll'.() = > {
  const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  // Current progress bar progress = current scroll bar position/scroll bar height
  scrollProgress.style.width = `${(scrollTop / height) * 100}% `;
});
Copy the code

✍️ implementation -vue3

<! -- ScrollProgress.vue -->

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'

// To use 'props' under the' 
const props = defineProps({
  // Scroll container - If the height of the container changes, it needs to be monitored, otherwise the scroll progress will be calculated error
  root: {
    type: String.default: '#app'.required: false,},// Scroll bar height
  height: {
    type: String.default: '4px'.required: false,},// Scroll bar color
  theme: {
    type: String.default: '#3eaf7c'.required: false.validator: (v: string) = > {
      document.head.style.color = v
      const q = document.head.style.color
      document.head.style.color = ' '
      return!!!!! q }, },// Scroll bar position: top or bottom
  placement: {
    type: String.default: 'top'.required: false.validator: (v: string) = > {
      if(! ['top'.'bottom'].includes(v)) {
        console.error(`[ScrollProgress(placement)] The value must match one of these strings: 'top' | 'bottom'`)
        return false
      }
      return true}},// Scroll bar hierarchy in the page
  zIndex: {
    type: [Number.String].default: 10000.required: false.validator: (v: string) = > / ^ -? [\d]+$/.test(v),
  },
})

const el = ref(null)
const appHeight = ref(0)

// To avoid the calculation deviation caused by the change of the height of the page container, you need to monitor the page container and dynamically obtain its height
onMounted(() = > {
  // The changing node needs to be observed
  const targetNode = document.querySelector(props.root)
  if(! targetNode)return console.error(`[ScrollProgress(root)] '${props.root}' is invalid`)
  // Observer configuration (what changes need to be observed)
  const config = { attributes: true.childList: false.subtree: true }
  // Create an observer instance and pass in the callback function to execute when changes are observed
  const observer = new MutationObserver((mutationsList: MutationRecord[]) = > {
    // Use traditional 'for loops' for IE 11
    for(let mutation of mutationsList) {
      if (mutation.type === 'attributes') {
        appHeight.value = document.documentElement.scrollHeight
      }
    }
  })
  // Start observing the target node
  observer.observe(targetNode, config)
})

// The callback function executed by the scroll event
const listener = () = > {
  const scrollProgress = el.value
  const height = appHeight.value - document.documentElement.clientHeight
  const scrollTop = document.body.scrollTop || document.documentElement.scrollTop
  scrollProgress.style.width = `${(scrollTop / height) * 100}% `
}

onMounted(() = > window.addEventListener('scroll', listener))
onUnmounted(() = > window.removeEventListener('scroll', listener))

const style: any = {
  background: props.theme,
  zIndex: props.zIndex,
  height: props.height,
}

if (props.placement === 'top') style.top = 0
if (props.placement === 'bottom') style.bottom = 0

// To explicitly expose attributes under the '
defineExpose({ style })
</script>

<template>
  <div id="scroll_progress" ref="el" :style="style" />
</template>

<style scoped>
#scroll_progress {
  position: fixed;
  width: 0%;
  transition: width 300ms ease-out;
}
</style>
Copy the code

🎥 demo


🔗 reference

  • [MDN] Document: Scroll Event – When a Document view or an element is scrolling, the scroll event of the element will be triggered.
  • [MDN] MutationObserver- The interface provides monitoring pairsThe DOM treeThe ability to make changes. It was designed to be oldMutation EventsA substitute for a function that isDOM3 EventsPart of the specification.
  • Vue3 API
    • props
    • <script setup>
    • Lifecycle Hooks
    • defineProps and defineEmits
    • defineExpose