gpt4 book ai didi

javascript - 如何使用 javascript 获取 "fixed"定位元素的包含 block ?

转载 作者:行者123 更新时间:2023-12-01 14:56:49 27 4
gpt4 key购买 nike

假设我们有以下设置:

#header {
background-color: #ddd;
padding: 2rem;
}
#containing-block {
background-color: #eef;
padding: 2rem;
height: 70px;
transform: translate(0, 0);
}
#button {
position: fixed;
top: 50px;
}
<div id="header">header</div>
<div id="containing-block">
containing-block
<div>
<div>
<div>
<button id="button" onclick="console.log('offsetParent', this.offsetParent)">click me</button>
</div>
</div>
</div>
</div>


按钮的位置 fixed位置和包含 block 有 transform属性(property)到位。

这可能会让人感到意外,但按钮的位置相对于 #containing-block ,而不是视口(viewport)(正如人们在使用 fixed 时所期望的那样)。那是因为 #containing-block元素具有 transform属性集。见 https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed为了澄清。

有没有一种简单的方法可以找出按钮的包含 block ?哪个是元素 top: 50px是相对于计算?假设您没有对包含 block 的引用,并且您不知道它有多少层。如果没有具有 transform 的祖先,它甚至可能是 documentElement , perspectivefilter属性集。

对于 absoluterelative定位元素,我们有 elem.offsetParent这给了我们这个引用。但是,对于 fixed,它设置为空。元素。

当然,我可以查找 dom 并找到第一个具有 transform 样式属性的元素, perspectivefilter设置,但这似乎很老套,不是 future 的证明。

谢谢!

最佳答案

已知行为和规范兼容。规范可能应该改变。
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent

我已经包含了来自各种库的一些解决方法。

来自 dom-helpers 的解决方法(似乎是最一致的,并且使用 offsetParent 进行遍历意味着它应该只真正遍历一次或两次。):
https://github.com/react-bootstrap/dom-helpers/blob/master/src/offsetParent.ts

// taken from popper.js
function getStyleComputedProperty(element, property) {
if (element.nodeType !== 1) {
return [];
}
// NOTE: 1 DOM access here
const window = element.ownerDocument.defaultView;
const css = window.getComputedStyle(element, null);
return property ? css[property] : css;
}

getOffsetParent = function(node) {
const doc = (node && node.ownerDocument) || document
const isHTMLElement = e => !!e && 'offsetParent' in e
let parent = node && node.offsetParent

while (
isHTMLElement(parent) &&
parent.nodeName !== 'HTML' &&
getComputedStyle(parent, 'position') === 'static'
) {
parent = parent.offsetParent
}

return (parent || doc.documentElement)
}
#header {
background-color: #ddd;
padding: 2rem;
}
#containing-block {
background-color: #eef;
padding: 2rem;
height: 70px;
transform: translate(0, 0);
}
#button {
position: fixed;
top: 50px;
}
<div id="header">header</div>
<div id="containing-block">
containing-block
<div>
<div>
<div>
<button id="button" onclick="console.log('offsetParent', getOffsetParent(this),this.offsetParent)">click me</button>
</div>
</div>
</div>
</div>


取自 jQuery 源代码的解决方法代码。不处理非元素,也不处理 TABLE TH TD,但它是 jQuery。
https://github.com/jquery/jquery/blob/master/src/offset.js

// taken from popper.js
function getStyleComputedProperty(element, property) {
if (element.nodeType !== 1) {
return [];
}
// NOTE: 1 DOM access here
const window = element.ownerDocument.defaultView;
const css = window.getComputedStyle(element, null);
return property ? css[property] : css;
}

getOffsetParent = function(elem) {
var doc = elem.ownerDocument;
var offsetParent = elem.offsetParent || doc.documentElement;
while (offsetParent &&
(offsetParent !== doc.body || offsetParent !== doc.documentElement) &&
getComputedStyle(offsetParent, "position") === "static") {

offsetParent = offsetParent.parentNode;
}
return offsetParent;
}
#header {
background-color: #ddd;
padding: 2rem;
}
#containing-block {
background-color: #eef;
padding: 2rem;
height: 70px;
transform: translate(0, 0);
}
#button {
position: fixed;
top: 50px;
}
<div id="header">header</div>
<div id="containing-block">
containing-block
<div>
<div>
<div>
<button id="button" onclick="console.log('offsetParent', getOffsetParent(this),this.offsetParent)">click me</button>
</div>
</div>
</div>
</div>


取自 popper.js 的解决方法代码。似乎没有让 doc.body 正确。唯一专门处理 TH TD TABLE 的。 dom-helpers 应该工作只是因为它使用 offsetParent 来遍历。
https://github.com/popperjs/popper-core/blob/master/src/dom-utils/getOffsetParent.js

var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';

const isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
const isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);
function isIE(version) {
if (version === 11) {
return isIE11;
}
if (version === 10) {
return isIE10;
}
return isIE11 || isIE10;
}

function getStyleComputedProperty(element, property) {
if (element.nodeType !== 1) {
return [];
}
// NOTE: 1 DOM access here
const window = element.ownerDocument.defaultView;
const css = window.getComputedStyle(element, null);
return property ? css[property] : css;
}

function getOffsetParent(element) {
if (!element) {
return document.documentElement;
}

const noOffsetParent = isIE(10) ? document.body : null;

// NOTE: 1 DOM access here
let offsetParent = element.offsetParent || null;
// Skip hidden elements which don't have an offsetParent
while (offsetParent === noOffsetParent && element.nextElementSibling) {
offsetParent = (element = element.nextElementSibling).offsetParent;
}

const nodeName = offsetParent && offsetParent.nodeName;

if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
return element ? element.ownerDocument.documentElement : document.documentElement;
}

// .offsetParent will return the closest TH, TD or TABLE in case
// no offsetParent is present, I hate this job...
if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
return getOffsetParent(offsetParent);
}

return offsetParent;
}
#header {
background-color: #ddd;
padding: 2rem;
}
#containing-block {
background-color: #eef;
padding: 2rem;
height: 70px;
transform: translate(0, 0);
}
#button {
position: fixed;
top: 50px;
}
<div id="header">header</div>
<div id="containing-block">
containing-block
<div>
<div>
<div>
<button id="button" onclick="console.log('offsetParent', getOffsetParent(this))">click me</button>
</div>
</div>
</div>
</div>

关于javascript - 如何使用 javascript 获取 "fixed"定位元素的包含 block ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60778773/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com