current position:Home>[day ui] affix component learning
[day ui] affix component learning
2022-06-24 12:44:51【Uncertainty】
A fastener component is a component that compares an element of a page to a page HTML
Or a dom
Internal positioning display , For example, fix the top of the page / The bottom shows , Page width and height change will also keep the original position . If scrolling , Beyond the defined range, it will be fixed , Otherwise, it will scroll with the page
In the last section, we introduced DButton
and DIcon
The implementation of the , So new affix
We will not introduce the file directory structure more . We will mainly learn about the internal implementation , The essence is location , Let's see what judgments and third-party libraries are used , If there is anything wrong, please correct me .
Effect analysis
- The first case is that no container is set , According to
position
Position setting fixed positioning , If the position is settop
, So when listening to page scrolling , If the current element'stop
The value is less than the set offset , Set upfixed
location ( converselybottom
Is the morebottom
The value is greater than the difference between the page height and the offsetfixed
location ) - The second case is to set the container , that
top / bottom
Is displayed only in the container , The container is not behind the page , The positioning element disappears . If thetop
value , So when the current elementtop
The value is less than the offset and the container'sbottom
Greater than 0, Elementsfixed
location ( converselybottom
The offset needs to calculate the page height andbottom
Worth comparing ). I learned recently that ,fixed
Positioning is relative to the window by default , But if you define attributes for the parent nodetransform、filter、perspective,fixed
Positioning is relative to the parent set , If you are interested, you can check by yourself .
The code analysis
dom structure
<template> <div ref="root" class="d-affix" :style="rootStyle"> <!-- Positioning elements Listen while scrolling root The relationship between the position and the viewable area of the page is set fixed, Set the style when positioning --> <div :class="{ 'd-affix--fixed': state.fixed }" :style="affixStyle"> <slot></slot> </div> </div> </template>
Outer layer definition d-affix
class , The height is the same as the internal element , To be an internal element fixed
When locating out of document flow , The page placeholder structure remains unchanged ; At the same time, we need to compare d-affix
Of top
and bottom
Value to determine when an element leaves the document , When to reset .
attribute
props: { // Locate the level of the element zIndex: { type: Number, default: 100 }, // In which container , No transmission is the view target: { type: String, default: '' }, // Up and down offset offset: { type: Number, default: 0 }, // From top to bottom position: { type: String, default: 'top' } }, // There are two ways to expose to the outside world , Monitor scrolling and fixed State change emits: ['scroll', 'change'],
setUp The core
// Locate element attributes const state = reactive({ fixed: false, height: 0, // height of target Get assignment when scrolling width: 0, // width of target scrollTop: 0, // scrollTop of documentElement clientHeight: 0, // Window height transform: 0 // The elements are in target When positioning y direction }) // Compute properties , Only when scrolling can we get the specific // d-affix Class always exists in the document stream , As long as width and height , Scroll position to determine whether fixed const rootStyle = computed(() => { return { height: state.fixed ? `${state.height}px` : '', width: state.fixed ? `${state.width}px` : '' } }) // Locate element attributes 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 } })
Judgment of positioning attribute during scrolling :
const updateState = () => { // obtain d-affix Node information const rootRect = root.value.getBoundingClientRect() // obtain target Node information const targetRect = target.value.getBoundingClientRect() state.height = rootRect.height state.width = rootRect.width // No, target take html Of scrollTOP( Yes target stay target Middle scroll ) state.scrollTop = scrollContainer.value === window ? document.documentElement.scrollTop : scrollContainer.value.scrollTop state.clientHeight = document.documentElement.clientHeight // Set the top margin if (props.position === 'top') { if (props.target) { // Locate the element in target Sliding distance in element ,bottom Continuous change const difference = targetRect.bottom - props.offset - state.height // target Elements top Outside the viewing area ,bottom Locate in the visible area state.fixed = props.offset > rootRect.top && targetRect.bottom > 0 state.transform = difference < 0 ? difference : 0 } else { // With html Is a relative container , Page scrolling , Fixed position (d-affix Outside the visual area ) state.fixed = props.offset > rootRect.top } } else { // Set bottom margin 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 { // offset + bottom > View height , Elements are positioned state.fixed = state.clientHeight - props.offset < rootRect.bottom } } }
const onScroll = () => { updateState() emit('scroll', { scrollTop: state.scrollTop, fixed: state.fixed }) } watch( () => state.fixed, () => { emit('change', state.fixed) } ) // When the page is mounted onMounted(() => { if (props.target) { // Pay attention to the format target.value = document.querySelector(props.target) if (!target.value) { throw new Error(`target is not existed: ${props.target}`) } } else { target.value = document.documentElement // html } // Let's analyze the auxiliary function scrollContainer.value = getScrollContainer(root.value) // Functional programming ,on Rewritten addEventListener on(scrollContainer.value, 'scroll', onScroll) addResizeListener(root.value, updateState) }) // The page is about to close. Cancel listening and remove onBeforeMount(() => { off(scrollContainer.value, 'scroll', onScroll) removeResizeListener(root.value, updateState) })
Auxiliary function
- on// Functional programming handles element listening export const on = function(element, event, handler, useCapture = false) { if (element && event && handler) { element.addEventListener(event, handler, useCapture) } }export const off = function(element, event, handler, useCapture = false) { if (element && event && handler) { element.removeEventListener(event, handler, useCapture) } }/** * Get the scroll container * @param {*} el Rolling container * @param {*} isVertical Scroll vertically or horizontally * @returns */ export const getScrollContainer = (el, isVertical) => { if (isServer) return let parent = el while (parent) { // None, just window if ([window, document, document.documentElement].includes(parent)) { return window } // Whether the container is scrollable if (isScroll(parent, isVertical)) { return parent } parent = parent.parentNode } return parent }export default typeof window === 'undefined'/** * * @param {*} el * @param {*} isVertical Is it vertical overflow-y * @returns */ export const isScroll = (el, isVertical) => { if (isServer) return const determineDirection = isVertical === null || isVertical === undefined const overflow = determineDirection ? getStyle(el, 'overflow') : isVertical ? getStyle(el, 'overflow-y') : getStyle(el, 'overflow-x') return overflow.match(/(scroll|auto)/) }// Gets the attribute value of the element export const getStyle = function(element, styleName) { if (isServer) return if (!element || !styleName) return null styleName = camelize(styleName) if (styleName === 'float') { /** * ie6~8 Next :style.styleFloat FF/chrome as well as ie9 above :style.cssFloat */ styleName = 'cssFloat' // FF/chrome as well as ie9 above float Compatibility writing } try { const style = element.style[styleName] if (style) return style // obtain window object , firefox Low version 3.6 Can be used getComputed Method ,iframe pupup extension window === document.defaultView, Otherwise, the point is wrong // https://www.cnblogs.com/yuan-shuai/p/4125511.html const computed = document.defaultView.getComputedStyle(element, '') return computed ? computed[styleName] : '' } catch (e) { return element.style[styleName] } }resize-observer-polyfill This library is the first time I have seen , If you don't know the source code . I think it's very interesting , Here is a brief introduction .
- off
- getScrollContainer
- isSserver
- isScroll
- getStyle
The main function of this library is to listen for elements size
change . Usually, we can only use to monitor the size change window.size
perhaps window.orientationchange
( The mobile terminal screen displays horizontally and vertically ).resize
The event will be in 1s
Internal trigger 60
Times or so , Therefore, it is easy to cause performance problems when changing the window size , So when we listen for changes in an element, it seems a bit wasteful .
ResizeObserver API
It's new , There is also compatibility in some browsers , This library is very compatible .ResizeObserver
Using observer mode , When element size
Trigger when a change occurs ( The presence of hidden nodes will also trigger ).
usage
const observer = new ResizeObserver(entries => { entries.forEach(entry => { console.log(' Size position ', entry.contentRect) console.log(' Monitoring dom', entry.target) }) }) // The object of listening is body, You can change the size of the browser window to see the printing effect observer.observe(document.body)// dom node , It's not a class name id name
width
: Refers to the width of the element itself , It doesn't containpadding,border
valueheight
: Refers to the height of the element itself , It doesn't containpadding,border
valuetop
: fingerpadidng-top
Valueleft
: fingerpadding-left
Valueright
: fingerleft + width
Valuebottom
: valuetop + height
Value
Method
ResizeObserver.disconnect()
Cancel listening for all elementsResizeObserver.observe()
Monitor elementsResizeObserver.unobserve()
End listening for an element
Components use
We are onMounted
Chinese vs root
Element listening . Listen while scrolling , Element size changes should also be monitored
import ResizeObserver from 'resize-observer-polyfill' import isServer from './isServer' const resizeHandler = function(entries) { for (const entry of entries) { /** * const {left, top, width, height} = entry.contentRect; * 'Element:', entry.target Element's size: ${ width }px x ${ height }px` Element's paddings: ${ top }px ; ${ left }px` */ const listeners = entry.target.__resizeListeners__ || [] if (listeners.length) { // Element changes the direct execution method listeners.forEach(fn => fn()) } } } // monitor element Elements size change , perform fn export const addResizeListener = function(element, fn) { if (isServer || !element) return if (!element.__resizeListeners__) { element.__resizeListeners__ = [] /** * https://github.com/que-etc/resize-observer-polyfill * */ element.__ro__ = new ResizeObserver(resizeHandler) // The object of observation element.__ro__.observe(element) } element.__resizeListeners__.push(fn) } // Exit remove listening export const removeResizeListener = function(element, fn) { if (!element || !element.__resizeListeners__) return element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1) if (!element.__resizeListeners__.length) { // Cancel monitoring element.__ro__.disconnect() } }
That's right affix
Component learning . If there is any mistake, please correct it . Next, let's go to alert
Component learning . If the article helps you , Welcome to the official account Touch the front end
, Or add wechat :wajh123654789, Learning together .
copyright notice
author[Uncertainty],Please bring the original link to reprint, thank you.
https://en.chowdera.com/2022/175/20210526152008381F.html
The sidebar is recommended
- [Tencent cloud 618 countdown!] Promotion strategy of the promotion activities
- Simple and flexible permission design?
- Making daily menu applet with micro build low code
- 99% of the students can't write good code because of this problem!
- Istio practical skills: using prism to construct multi version test services
- Kubernetes practical technique: setting kernel parameters for pod
- A scheme for crawlers to collect public opinion data
- Essential key steps in the construction of e-commerce live broadcast source code
- How do websites and we media tap user needs? Deeply expose the secrets behind the keywords!
- From theory to practice, decipher Alibaba's internal MySQL optimization scheme in simple terms
guess what you like
Continuous testing | key to efficient testing in Devops Era
It's settled! Bank retail credit risk control just does it!
Encapsulate the method of converting a picture file object to Base64
The pod is evicted due to insufficient disk space of tke node
Post processing - deep camera deformation effects
Tencent released credit risk control results safely: it has helped banks lend more than 100 billion yuan
Interesting erasure code
Five minutes to develop your own code generator
How to make secruecrt more productive
About me, a 19 line programmer
Random recommended
- Kubernetes practical skill: entering container netns
- [programming navigation] the practical code summarized by foreign great God, learned in 30 seconds!
- Design and implementation of high performance go log library zap
- Ghost, a synonym for blog system
- Engage in audio and video development? Several things I have to say about SRT live broadcast protocol
- IOMMU (VII) -vfio and mdev
- [highlights] summary of award-winning activities of Tencent cloud documents
- The programmer's graduation project is still bald after a year
- How to solve the problem that MBR does not support partitions over 2T, and lossless transfer to GPT
- Another prize! Tencent Youtu won the leading scientific and technological achievement award of the 2021 digital Expo
- Use txvideoeditor to add watermark and export video card at 99%? No successful failed callback?
- Reset the password, and the automatic login of the website saved by chrome Google browser is lost. What is the underlying reason?
- [log service CLS] Tencent cloud log service CLS accesses CDN
- [live broadcast of celebrities] elastic observability workshop
- Smart Policing: how to use video intelligent analysis technology to help urban policing visual comprehensive supervision and command system
- SMS SMS
- WPF from zero to 1 tutorial details, suitable for novices on the road
- Dingding, Feishu, and enterprise wechat: different business approaches
- [2022 national tournament simulation] BigBen -- determinant, Du Jiao sieve
- How to do research on plant endophytes? Special topic on Microbiology
- Mlife forum | microbiome and data mining
- 105. simple chat room 8: use socket to transfer pictures
- Parse NC format file and GRB format file dependent package edu ucar. API learning of netcdfall
- Reading notes of returning to hometown
- Generate the NC file of 4-D air pressure and temperature, and then read the code (provide the code)
- Codereview tool chain for micro medicine
- Babbitt | metauniverse daily must read: 618 scores have been announced. How much contribution has the digital collection made behind this satisfactory answer
- On the value foam of digital copyright works from the controversial nature of "Meng Hua Lu"
- Use the open source tool k8tz to gracefully set the kubernetes pod time zone
- How does Argo family bucket make Devops easier?
- A hero's note stirred up a thousand waves across 10 countries, and the first-line big factories sent people here- Gwei 2022 Singapore
- MySQL foreign key impact
- Common special characters in JS and TS
- The text to voice function is available online. You can experience the services of professional broadcasters. We sincerely invite you to try it out
- Who said that "programmers are useless without computers? The big brother around me disagrees! It's true
- what the fuck! I'm flattered. He actually wrote down the answers to the redis interview questions that big companies often ask!
- Concept + formula (excluding parameter estimation)
- [database] final review (planning Edition)
- Troubleshooting and optimization of files that cannot be globally searched by ordinary users in easydss video platform customization project
- How can ffmpeg streaming to the server save video as a file through easydss video platform?