如果我使用grid-template-columns: repeat(3,1fr)將一些HTML元素放入一個3列的網格中,用JavaScript找到一個元素的列是可能的嗎?有些元素還跨越多行,因此元素的索引不一定與其列匹配。
例如:
const myElement = document.querySelector('div:nth-child(5)');
myElement.style.background = '#f00';
const columnIndex = 1; // How do I find this?
console.log('myElement is in column ' + columnIndex);
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 30px;
}
.item,
.item-large {
padding: 30px;
background: #3cf;
}
.item-large {
grid-row: span 2;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item-large"></div>
<div class="item">Which column am I in?</div>
<div class="item-large"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
我在這里做的是遍歷所有元素,每次左邊的位置增加并且小于我的元素位置時,我增加一個計數器來跟蹤該列。
我還修改了這里的代碼片段,使其更具互動性。如果您單擊div的,它會重新選擇并顯示新的列號..
var myElement = document.querySelector('div:nth-child(5)');
const allElements = document.querySelector('.grid').querySelectorAll('div');
//myElement.style.background = '#f00';
myElement.classList.add('item-found');
function showFound() {
let maxcolpos = -1, colposCount = 0;
for(elem of allElements) {
let l = elem.getBoundingClientRect().left;
if (l > maxcolpos) {
maxcolpos = l;
if (myElement.getBoundingClientRect().left > l) colposCount ++;
}
}
const columnIndex = colposCount + 1; //zero based, leave +1 if you want 0 based
myElement.innerText = 'Column = ' + columnIndex;
}
showFound();
document.querySelector('.grid').addEventListener("click", function(e) {
if (e.target && !e.target.matches(".grid")) {
myElement.classList.remove('item-found');
myElement.innerText = '';
myElement = e.target;
myElement.classList.add('item-found');
showFound();
}
});
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 30px;
}
.item,
.item-large {
padding: 30px;
background: #3cf;
}
.item-large {
grid-row: span 2;
}
.item-found {
background-color: red;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item-large"></div>
<div class="item"></div>
<div class="item-large"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
我知道這個話題很老了,但是對于那些糾結于React和TypeScript的人來說,這可能很有趣。
我制作了一個Dashboard組件,它有一個嵌套的Grid組件,Grid組件有嵌套的Widget組件,Widget組件可以獲得要跨越多少列的屬性——如果沒有給定值,則默認為1。
我不喜歡網格中的最后一項“沒有完成”整個塊。使用這段代碼,網格中的最后一項將延伸到最后一個網格列的末尾。它計算它的當前位置,所以如果你有一個未知網格項目的網格,但仍然想要一個完整的塊,這將派上用場。
不要忘記給JSX中的網格元素賦予ref={gridRef}屬性:-)
const gridRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (!gridRef.current) return;
const widgets = gridRef.current.children as HTMLCollectionOf<HTMLDivElement>;
const widgetsLeftPosition: number[] = [];
const widgetsInLastRow: HTMLDivElement[] = [];
// add offset from screenedge to array
for (let i = 0; i < widgets.length; i++) {
const currentWidgetLeftPosition = widgets[i].getBoundingClientRect().left;
widgetsLeftPosition.push(currentWidgetLeftPosition);
}
// add elements (from rear end) to array, and
// check if position of current element has same offset as first item, then break
// (which results in having only the elements of the last row in the array)
for (let i = widgetsLeftPosition.length - 1; i >= 0; i--) {
widgetsInLastRow.push(widgets[i]);
if (widgetsLeftPosition[i] === widgetsLeftPosition[0]) break;
}
// for every element in the last row: check the gridColumnEnd value and
// take the last character (which is a 'string-integer').
// parse it to a normal integer, then sum up all integers and return that value
const columnSpanStart = () => {
let sum = 0;
for (let i = 0; i < widgetsInLastRow.length; i++) {
const spanString = getComputedStyle(widgetsInLastRow[i]).gridColumnEnd;
sum += parseInt(spanString.slice(-1));
}
return sum;
};
// finally, use the returned value from columnSpanStart() as gridColumn 'start' value.
// this will overwrite the default 'grid-column-end' style given by the widget component.
const lastWidget = widgets[widgets.length - 1];
lastWidget.style.gridColumn = `${columnSpanStart()} / -1`;
}, []);