当前位置:网站首页>[day ui] affix component learning
[day ui] affix component learning
2022-06-24 12:44:00 【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
positionPosition setting fixed positioning , If the position is settop, So when listening to page scrolling , If the current element'stopThe value is less than the set offset , Set upfixedlocation ( converselybottomIs the morebottomThe value is greater than the difference between the page height and the offsetfixedlocation ) - The second case is to set the container , that
top / bottomIs displayed only in the container , The container is not behind the page , The positioning element disappears . If thetopvalue , So when the current elementtopThe value is less than the offset and the container'sbottomGreater than 0, Elementsfixedlocation ( converselybottomThe offset needs to calculate the page height andbottomWorth comparing ). I learned recently that ,fixedPositioning is relative to the window by default , But if you define attributes for the parent nodetransform、filter、perspective,fixedPositioning 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,bordervalueheight: Refers to the height of the element itself , It doesn't containpadding,bordervaluetop: fingerpadidng-topValueleft: fingerpadding-leftValueright: fingerleft + widthValuebottom: valuetop + heightValue
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 .
边栏推荐
- WPF从零到1教程详解,适合新手上路
- Tencent security monthly report - zero trust development trend forum, digital Expo Technology Award, Mercedes Benz security research results
- WPF from zero to 1 tutorial details, suitable for novices on the road
- From theory to practice, decipher Alibaba's internal MySQL optimization scheme in simple terms
- What should music website SEO do?
- Go basic series | 1 Leading
- Argo 全家桶如何让 DevOps 变的更容易?
- Interesting erasure code
- 一纸英雄帖,激起千层浪,横跨10国,一线大厂都派人来了!-GWEI 2022-新加坡
- 文本转语音功能上线,可以体验专业播音员的服务,诚邀试用
猜你喜欢

WPF from zero to 1 tutorial details, suitable for novices on the road

MySQL foreign key impact

Opencv learning notes - loading and saving images

The text to voice function is available online. You can experience the services of professional broadcasters. We sincerely invite you to try it out

Opencv learning notes -- Separation of color channels and multi-channel mixing

Codereview tool chain for micro medicine

Use the open source tool k8tz to gracefully set the kubernetes pod time zone
[mysql_16] variables, process control and cursors

On the value foam of digital copyright works from the controversial nature of "Meng Hua Lu"

一纸英雄帖,激起千层浪,横跨10国,一线大厂都派人来了!-GWEI 2022-新加坡
随机推荐
Hardware enterprise website ranking, 8 commonly used processes
Collation of related papers on root cause analysis
105. simple chat room 8: use socket to transfer pictures
Continuous testing | key to efficient testing in Devops Era
短信服務sms
Pipeline shared library
实现领域驱动设计 - 使用ABP框架 - 创建实体
Istio Troubleshooting: uneven grpc service load
Reset the password, and the automatic login of the website saved by chrome Google browser is lost. What is the underlying reason?
What should music website SEO do?
[highlights] summary of award-winning activities of Tencent cloud documents
Adjustment method of easynvr video platform equipment channel page display error
Design and implementation of high performance go log library zap
生成 4维 的 气压温度的 nc文件,之后进行代码读取(提供代码)
Cluster control management
Example of SMS interface verification code function implemented by ThinkPHP framework
Reading notes of returning to hometown
About Adobe Photoshop adjusting selection
Examples of AES and RSA encryption operations implemented by php7.1
How does easygbs, a national standard platform, solve the problem that information cannot be carried across domains?