Element Plus implements Affix

Element Plus implements Affix

1. Component Introduction

Affix components are used to fix page elements in a specific visual area.

1.1 Properties

  • position: specifies the position of the pin, which can be set to top or bottom. The default is top
  • offset: Set the offset distance, the default is 0
  • target: specifies the container (CSS selector) to keep the pin inside the container at all times. If it exceeds the range, it will be hidden. The default container is document.documentElement.
  • z-index: The level of the pin, default is 100

1.2 Events

  • scroll: triggers the event when the container scrolls, the parameters are: the scrollTop value and status of the fixed pin (whether it is fixed)
  • change: triggered when the state of the fixed pin changes, the parameter is whether the fixed pin is currently in the fixed state

2. Source Code Analysis

2.1 template

<template>
  <div ref="root" class="el-affix" :style="rootStyle">
    <div :class="{'el-affix--fixed': state.fixed}" :style="affixStyle">
      <slot></slot>
    </div>
  </div>
</template>

The template part is very simple, receiving content through slot

2.2 script

// Some core codes, the code order is adjusted setup(props, { emit }) {
    // target container ref
    const target = ref(null) 
    // Fix ref, and cooperate with the ref attribute in template to get the HTML element const root = ref(null)
    // Scroll container ref
    const scrollContainer = ref(null)
    
    // Fixed state const state = reactive({
      fixed: false,
      height: 0, // height of root
      width: 0, // width of root
      scrollTop: 0, // scrollTop of documentElement
      clientHeight: 0, // clientHeight of documentElement
      transform: 0,
    })
    
    onMounted(() => {
      // Determine the target container based on the incoming target if (props.target) {
        target.value = document.querySelector(props.target)
        if (!target.value) {
          throw new Error(`target is not existed: ${props.target}`)
        }
      } else {
        target.value = document.documentElement
      }
      
      // According to the fixed element, find the scroll container upwards scrollContainer.value = getScrollContainer(root.value)
      // Listen for the scroll event of the scroll container on(scrollContainer.value, 'scroll', onScroll)
      // Listen for the resize event of the fixed element addResizeListener(root.value, updateState)
    })
    
    // The response function of the scroll container's scroll event const onScroll = () => {
      // Update the fixed state updateState()
      
      emit('scroll', {
        scrollTop: state.scrollTop,
        fixed: state.fixed,
      })
    }
    
    // Update the fixed state function const updateState = () => {
      const rootRect = root.value.getBoundingClientRect()
      const targetRect = target.value.getBoundingClientRect()
      state.height = rootRect.height
      state.width = rootRect.width
      state.scrollTop = scrollContainer.value === window ? document.documentElement.scrollTop : scrollContainer.value.scrollTop
      state.clientHeight = document.documentElement.clientHeight

      if (props.position === 'top') {
        if (props.target) {
          const difference = targetRect.bottom - props.offset - state.height
          // targetRect.bottom > 0 means that the fixed pin is always kept in the container and hidden if it exceeds the range state.fixed = props.offset > rootRect.top && targetRect.bottom > 0
          // Used to handle the scenario: During the scrolling process, if the visible area of ​​the target container is not enough to display the entire pin, the pin should be offset accordingly to display only part of it state.transform = difference < 0 ? difference : 0
        } else {
          state.fixed = props.offset > rootRect.top
        }
      } else {
        if (props.target) {
          const difference = state.clientHeight - targetRect.top - props.offset - state.height
          state.fixed = state.clientHeight - props.offset < rootRect.bottom && state.clientHeight > targetRect.top
          state.transform = difference < 0 ? -difference : 0
        } else {
          state.fixed = state.clientHeight - props.offset < rootRect.bottom
        }
      }
    }
    // Monitor the fixed state change and emit change events watch(() => state.fixed, () => {
      emit('change', state.fixed)
    })
    
    // Calculate the property and automatically update the style of the nail according to the state of the nail const affixStyle = computed(() => {
      if (!state.fixed) {
        return
      }
      const offset = props.offset ? `${props.offset}px` : 0
      const transform = state.transform ? `translateY(${state.transform}px)` : ''

      return {
        height: `${state.height}px`,
        width: `${state.width}px`,
        top: props.position === 'top' ? offset : '',
        bottom: props.position === 'bottom' ? offset : '',
        transform: transform,
        zIndex: props.zIndex,
      }
    })
}

2.3 Implementation summary:

  • By monitoring the scroll event of the scroll container (and the resize event of the pin itself);
  • In the event response function, the DOM attributes of the pin and the target container are dynamically obtained and used to calculate the state of the pin;
  • Use calculated properties to automatically update the style of the pin;

This is the end of this article about Element Plus’ implementation of Affix pinning. For more relevant Element Affix pinning content, please search 123WORDPRESS.COM’s previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of the use of Affix controls in BootStrap and how to keep the layout beautiful
  • Bootstrap additional navigation (Affix) plugin example detailed explanation
  • Comprehensive analysis of the use of transition and affix in Bootstrap
  • Bootstrap's Affix plugin

<<:  A collection of possible problems when migrating sqlite3 to mysql

>>:  VMware and CentOS system installation method to reset the root password

Recommend

Share the responsive frameworks commonly used by web design masters (summary)

This article introduces and shares the responsive...

Mysql cannot select non-aggregate columns

1. Introduction I recently upgraded my blog and a...

Open the Windows server port (take port 8080 as an example)

What is a Port? The ports we usually refer to are...

How to install mysql via yum on centos7

1. Check whether MySQL is installed yum list inst...

The whole process record of introducing Vant framework into WeChat applet

Preface Sometimes I feel that the native UI of We...

Detailed explanation of Vue form binding and components

Table of contents 1. What is two-way data binding...

Introduction to Vue3 Composition API

Table of contents Overview Example Why is it need...

How to install Nginx in Docker

Install Nginx on Docker Nginx is a high-performan...

Detailed steps for installing JDK and Tomcat on Linux cloud server (recommended)

Download and install JDK Step 1: First download t...

Detailed explanation of how to customize the style of CSS scroll bars

This article introduces the CSS scrollbar selecto...

Tutorial on how to install htop on CentOS 8

If you are looking to monitor your system interac...

JavaScript canvas to achieve raindrop effect

This article example shares the specific code for...

How to use multi-core CPU to speed up your Linux commands (GNU Parallel)

Have you ever had the need to compute a very larg...

How to display the border when td is empty

Previously, I summarized how to use CSS to achieve...