너비가 다른 임의의 수의 요소를 래핑을 사용하여 그리드에 정렬
편집
아래 @user943702의 답변을 받았습니다.아래 스니펫과 같이 Vue 구현과 연동하기 위해 약간 수정이 필요했습니다.
const theElements = [{
name: "ele1",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}, {
name: 4
}, {
name: 5
}]
}, {
name: "ele2",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele3",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele4",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele5",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele6",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele7",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele8",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele9",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele10",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele11",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}, {
name: 4
}, {
name: 5
}]
}, {
name: "ele12",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}];
new Vue({
el: '#ele-grid',
data: {
elements: theElements
},
methods: {
// find the first grid line excess {max}
// return index; -1 means no overflow
firstoverflowline: function(cols, max) {
var sum = 0;
for (var i = 0; i<cols.length; ++i) {
sum += cols[i];
if (sum >= max)
return i;
}
return -1;
},
// compute max no of columns in grid
// use by `grid-template-columns:repeat(<max>, max-content)`
computegridlines: function(container) {
var cols = getComputedStyle(container).gridTemplateColumns.split(/\s+/).map(parseFloat);
var x = this.firstoverflowline(cols, parseFloat(getComputedStyle(container).width));
if (x == -1) return;
container.style.gridTemplateColumns = `repeat(${x}, max-content)`;
this.computegridlines(container);
},
// polyfill `width:max-content`
maxcontent: function(container) {
var items = Array.from(container.children);
for(var i = 0; i < items.length; i++) {
var item = items[i];
item.style.display = "flex";
item.style.flexFlow = "column";
item.style.alignItems = "start";
var max = Array.from(item.children).reduce(function(max,item) {
var {left, right} = item.getBoundingClientRect();
return Math.max(max, right - left);
}, 0);
item.style.width = `${max}px`;
}
},
// flex-grid-ify a container
flexgrid: function(container) {
container.style.display = `grid`;
container.style.gridTemplateColumns = `repeat(${container.children.length}, max-content)`;
this.computegridlines(container);
this.maxcontent(container);
}
},
mounted: function() {
var container = document.getElementById('ele-grid');
var _this = this;
this.flexgrid(container);
window.onresize = function(e) { _this.flexgrid(container); }
}
});
#ele-grid {
width:100vw;
}
.ele-card {
border: 1px solid black;
background: cyan;
margin: 5px 3px;
}
.ele-card .children {
display: flex;
flex-wrap: nowrap;
padding: 5px;
}
.ele-card .child {
margin: 0 5px;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border: 1px solid black;
background: magenta;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
<div id="ele-grid">
<div class="ele-card" v-for="ele in elements" :key="ele.name">
<div class="element">{{ele.name}}</div>
<div class="children">
<div class="child" v-for="child in ele.children" :key="child.name">{{child.name}}</div>
</div>
</div>
</div>
다른 폭을 가질 수 있는 요소의 개수를 알 수 없습니다.이 요소들을 그리드에 정렬하여 왼쪽이 각 열에 정렬되도록 합니다.또한 창이 작을 때 요소를 랩하고 그리드를 유지했으면 합니다.아래 이미지에서 내가 원하는 것을 조롱했다.
VueJs 2를 사용하여 요소를 그리드에 채우고 CSS Flexbox를 사용하여 다음 CSS를 사용하여 요소를 정리합니다.다음은 현재 기능하는 방법의 일부입니다.
const theElements = [{
name: "ele1",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}, {
name: 4
}, {
name: 5
}]
}, {
name: "ele2",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele3",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele4",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele5",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele6",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele7",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele8",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele9",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele10",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}, {
name: "ele11",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}, {
name: 4
}, {
name: 5
}]
}, {
name: "ele12",
children: [{
name: 1
}, {
name: 2
}, {
name: 3
}]
}];
new Vue({
el: '#ele-grid',
data: {
elements: theElements
}
});
#ele-grid {
display: flex;
flex-wrap: wrap;
}
.ele-card {
border: 1px solid black;
background: cyan;
margin: 5px 3px;
}
.ele-card .children {
display: flex;
flex-wrap: nowrap;
padding: 5px;
}
.ele-card .child {
margin: 0 5px;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border: 1px solid black;
background: magenta;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
<div id="ele-grid">
<div class="ele-card" v-for="ele in elements" :key="ele.name">
<div class="element">{{ele.name}}</div>
<div class="children">
<div class="child" v-for="child in ele.children" :key="child.name">{{child.name}}</div>
</div>
</div>
</div>
이것은 거의 기능합니다.창의 크기를 조정할 때 요소는 각각 고유한 너비와 랩을 가집니다.그러나 요소는 그리드에 정렬되지 않습니다.
CSS 그리드를 사용하는 것도 검토했습니다만, 각 요소의 너비 또는 열의 수를 지정해야 합니다.둘 다 임의여야 합니다.
CSS 또는 JavaScript를 사용하는 솔루션(JQuery가 아닌)은 모두 사용할 수 있습니다.서드파티 라이브러리는 포함하지 않는 것이 좋지만, 그것이 유일한 옵션이라면 검토해 보겠습니다.
편집:
- @user943702가 지적한 바와 같이 각 열의 불필요한 공간을 제거하기 위해 이 속성을 사용할 수 있습니다(이 속성은 요소당 폭 값이고 이것은 열당 폭 값이지만 설명에 나오는 것과 혼동하지 마십시오).
공간 분배의 경우: I've selected to set it to center라는 편리한 속성이 있습니다.다른 값 중에서도 다음과 같이 설정할 수 있습니다.
space-between; /* The first item is flush with the start,the last is flush with the end */ space-around; /* Items have a half-size space on either end */ space-evenly; /* Items have equal space around them */ stretch; /* Stretch 'auto'-sized items to fitthe container */
스크립트에 들어가기 전에 몇 가지 주의사항이 있습니다.
- 할 수 .css 을 、 css 、 you you you you 。
@media query
되지만 각 이므로 JavaScript를
편집: 이 스크립트는 다른 디바이스 폭으로 커스터마이즈하려고 하면 할수록 개개의 요소의 폭이 예기치 않게 변경되었을 때 잡힐 위험이 커집니다.
const theElements = [{ name: "ele1", children: [{ name: 1 }, { name: 2 }, { name: 3 }, { name: 4 }, { name: 5 }]}, { name: "ele2", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele3", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele4", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele5", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele6", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele7", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele8", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele9", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele10", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele11", children: [{ name: 1 }, { name: 2 }, { name: 3 }, { name: 4 }, { name: 5 }]}, { name: "ele12", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}];
new Vue({
el: '#ele-grid',
data: {
elements: theElements
}
});
@media (min-width: 1020px) {
#ele-grid {
display:grid;
grid-template-columns:repeat(5, 1fr);
justify-content: center;
}
}
@media (min-width:400px) and (max-width: 1020px) {
#ele-grid {
display:grid;
grid-template-columns:max-content max-content max-content;
}
}
@media (max-width: 400px) {
#ele-grid {
display:grid;
grid-template-columns:max-content;
}
}
.ele-card {
margin: 5px 3px;
}
.ele-card .children {
display: flex;
flex-wrap: nowrap;
padding: 5px;
}
.ele-card .child {
margin: 0 5px;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border: 1px solid black;
background: magenta;
}
.wrapper{
border: 1px solid black;
background: cyan;
display:inline-block;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>
<div id="ele-grid">
<div class="ele-card" v-for="ele in elements" :key="ele.name">
<div class="wrapper">
<div class="element">{{ele.name}}</div>
<div class="children">
<div class="child" v-for="child in ele.children" :key="child.name">{{child.name}}</div>
</div>
</div>
</div>
</div>
- 필요한 폭을 얻기 위해 아쉽게도 다른 브라우저에서는 아직 지원되지 않는 우수한 -moz-max-content 속성이 있기 때문에 자녀용 래퍼를 추가하여 만들었습니다.
display:inline-block
의도된 행동을 가지고 있다. - 사용 중이고 css column 또는 vertical을 사용할 수 있습니다.
flex
대신 요소가 위에서 아래로 정렬되어 전체 레이아웃이 변경됩니다.
이것은 css용, JavaScript용입니다.
- 간단히 말해 이 스크립트는 최대 열(여기서는 10개까지 늘릴 수 있음)을 가진 레이아웃을 취하여 스크롤하지 않고 적합한지, 감소하지 않는지를 확인합니다.
- 이 스크립트에서는 크기 조정 이벤트를 사용하여 요소가 응답합니다.
const theElements = [{ name: "ele1", children: [{ name: 1 }, { name: 2 }, { name: 3 }, { name: 4 }, { name: 5 }]}, { name: "ele2", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele3", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele4", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele5", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele6", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele7", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele8", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele9", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele10", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}, { name: "ele11", children: [{ name: 1 }, { name: 2 }, { name: 3 }, { name: 4 }, { name: 5 }]}, { name: "ele12", children: [{ name: 1 }, { name: 2 }, { name: 3 }]}];
new Vue({
el: '#ele-grid',
data: {
elements: theElements
}
});
function resizeHandler(){
colStart=10; // max number of columns to start with
allCards= document.getElementsByClassName('wrapper');
totalWidth=0;
maxWidTab=[];
for (i=colStart;i>0;i--){
for(j=0;j<i; j++){ //initializing and resetting
maxWidTab[j]=0;
}
for (j=0; j<allCards.length; j++){
cellWidth=parseInt(getComputedStyle(allCards[j]).width); //parseInt to remove the tailing px
maxWidTab[j%i]<cellWidth?maxWidTab[j%i]=cellWidth:'nothing to be done';
}
for(j=0;j<i; j++){ //sum to see if fit
totalWidth+=maxWidTab[j]+2+6 //borders and margins
}
if (totalWidth<innerWidth){
grEl = document.getElementById("ele-grid");
grEl.style.gridTemplateColumns="repeat("+i+", max-content)";
/*console.log(i);*/
break;
}else{
totalWidth=0; //resetting
}
}
}
window.addEventListener("resize",resizeHandler);
document.addEventListener ("DOMContentLoaded",resizeHandler);
#ele-grid {
display:grid;
justify-content: center;
grid-template-columns:repeat(10, max-content); /* starting by 10 columns*/
}
.ele-card {
margin: 5px 3px;
}
.ele-card .children {
display: flex;
flex-wrap: nowrap;
padding: 5px;
}
.ele-card .child {
margin: 0 5px;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border: 1px solid black;
background: magenta;
}
.wrapper{
border: 1px solid black;
background: cyan;
display:inline-block;
}
</style>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>
<div id="ele-grid">
<div class="ele-card" v-for="ele in elements" :key="ele.name">
<div class="wrapper">
<div class="element">{{ele.name}}</div>
<div class="children">
<div class="child" v-for="child in ele.children" :key="child.name">{{child.name}}</div>
</div>
</div>
</div>
</div>
CSSgrid-template-columns
다음과 같은 콘텐츠 인식 값을 지원합니까?max-content
유일한 문제는 몇 개의 컬럼이 있어야 하는가 하는 것입니다.
나는 최대 열 수를 탐색하는 알고리즘을 쓴다.구현에는 JS가 포함되며 CSS 그리드를 지원하려면 브라우저가 필요합니다.데모는 이쪽에서 보실 수 있습니다(Pug를 사용하여 고객님과 동일한 소스 구조를 만들고 스타일링도 고객님과 동일하기 때문에 구현인 JS패널에 집중할 수 있습니다).
데모에서 뷰포트 크기를 변경하면 그리드 항목이 다시 흐릅니다.를 호출하여 다른 중요한 순간에 수동으로 재플로우를 트리거할 수 있습니다.flexgrid(container)
예를 들어, 항목을 비동기적으로 로드한 후 다시 플로우합니다.소스 구조가 변경되지 않는 한 항목의 치수 속성을 변경할 수 있습니다.
알고리즘은 다음과 같습니다.
Step1) 컨테이너를 그리드 포맷 컨텍스트로 설정하고 모든 그리드 항목을 한 행에 레이아웃하고 각 열 너비를 다음과 같이 설정합니다.max-content
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggg|hhh|iii|
스텝 2) 첫 번째 오버플로 그리드 선 찾기
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggg|hhh|iii|
^overflowed
순서 3) 삭감grid-template-columns
우리의 경우 3. 그 이후로grid-row
디폴트auto
CSS 엔진은 마지막 열 그리드 선을 넘어 다음 행에 그리드 항목을 레이아웃합니다.나는 이것을 "포장"이라고 한다.또한 그리드 항목은 다음과 같은 이유로 자동 확장됩니다.grid-template-columns:max-content
(예: "ddd"는 첫 번째 열의 가장 넓은 콘텐츠 길이로 확장됩니다.)
|---container---|
|aaaaa|bbb|ccc|
|ddd |eee|fff|
|ggggg|hhh|iii|
모든 열 그리드 라인이 "내부" 컨테이너에 있으므로 이 작업을 완료했습니다.일부의 경우, 새로운 오버플로우 그리드 라인이 "랩핑" 후에 도입되고 있습니다.모든 그리드 라인이 "내부" 컨테이너에 배치될 때까지 2&3단계를 반복해야 합니다.
#layout in one row
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggggg|hhhhh|iii|
#find the first overflowed grid line
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggggg|hhhhh|iii|
^overflowed
#reduce `grid-template-columns`
|---container---|
|aaaaa |bbb |ccc|
|ddd |eee |fff|
|ggggggg|hhhhh|iii|
#find the first overflowed grid line
|---container---|
|aaaaa |bbb |ccc|
|ddd |eee |fff|
|ggggggg|hhhhh|iii|
^overflowed
#reduce `grid-template-columns`
|---container---|
|aaaaa |bbb |
|ccc |ddd |
|eee |fff |
|ggggggg|hhhhh|
|iii |
#find the first overflowed grid line
#None, done.
언급URL : https://stackoverflow.com/questions/47676820/align-arbitrary-number-of-elements-with-different-widths-to-a-grid-with-wrapping
'itsource' 카테고리의 다른 글
클래스와 인터페이스를 갖춘 Java Generics - 함께 (0) | 2022.08.17 |
---|---|
C의 함수의 크기가 항상 1바이트인 이유는 무엇입니까? (0) | 2022.08.17 |
Vue.js vuex 모듈 내보내기/가져오기 실패 (0) | 2022.08.16 |
Java에서 개체 배열을 문자열 배열로 변환하는 방법 (0) | 2022.08.16 |
Vue에서 구성 요소가 생성되었을 때 기능을 구현하는 방법은 무엇입니까? (0) | 2022.08.16 |