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

The most convenient way to build a Zookeeper server in history (recommended)

What is ZooKeeper ZooKeeper is a top-level projec...

A brief explanation of the reasonable application of table and div in page design

At the beginning of this article, I would like to ...

How to uninstall Linux's native openjdk and install sun jdk

See: https://www.jb51.net/article/112612.htm Chec...

Linux automatic login example explanation

There are many scripts on the Internet that use e...

Tutorial on installing lamp-php7.0 in Centos7.4 environment

This article describes how to install lamp-php7.0...

Native js to realize the upload picture control

This article example shares the specific code of ...

Summary of 10 advanced tips for Vue Router

Preface Vue Router is the official routing manage...

Clever use of webkit-box-reflect to achieve various dynamic effects (summary)

In an article a long time ago, I talked about the...

Why Seconds_Behind_Master is still 0 when MySQL synchronization delay occurs

Table of contents Problem Description Principle A...

Detailed analysis of classic JavaScript recursion case questions

Table of contents What is recursion and how does ...

js to achieve interesting countdown effect

js interesting countdown case, for your reference...

Detailed explanation of Vue3 life cycle functions and methods

1. Overview The so-called life cycle function is ...