sor*_*gon 9 javascript css grid flexbox vuejs2
编辑
我接受了下面@ 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); }
}
});Run Code Online (Sandbox Code Playgroud)
#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;
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
我有不同数量的元素可以有不同的宽度.我想在网格中对齐这些元素,使其左侧在每列中对齐.此外,我希望在窗口尺寸较小并保持网格时包裹元素.我在下面的图片中嘲笑了我想要的东西.
我正在使用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
}
});Run Code Online (Sandbox Code Playgroud)
#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;
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
这几乎有效; 每个元素都有自己的宽度,并在调整窗口大小时进行换行.但是,元素不与网格对齐.
我也研究过使用CSS Grid,但看起来你必须要指定每个元素的宽度或列数,这两者都需要是任意的.
我对使用CSS或JavaScript的任何解决方案持开放态度(请不要使用JQuery).我宁愿不包括第三方库,但如果它是唯一的选择,我会考虑它.
编辑:
max-content
属性来删除每列中的无关空格(不要将此属性与解释中的属性混淆,尽管每个元素的宽度值是基于每个列的宽度值,并且这个是每列的)justify-content我选择将其设置为居中,除了其他值,您可以将其设置为:Run Code Online (Sandbox Code Playgroud)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 */
在开始编写脚本之前,有几点注意事项:
@media query每个宽度一个并使用它完成但是单个元素也具有任意宽度所以我将使用javaScript编辑:这是一个使用CSS media query方法通知的脚本,您尝试将其自定义为不同的设备宽度越多,当单个元素宽度意外更改时,您捕获的风险就越大.
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
}
});Run Code Online (Sandbox Code Playgroud)
@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;
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
display:inline-block具有预期的行为CSS grid layout,你可以使用css列或垂直flexs,但元素将从上到下对齐,改变整个布局.那是针对JavaScript的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
}
});
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);Run Code Online (Sandbox Code Playgroud)
#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>Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
CSSgrid-template-columns确实支持内容感知值,即max-content. 唯一的问题是应该有多少列。
我编写了一个算法来探测最大列数。实现涉及JS,需要浏览器支持CSS Grid。演示可以在这里找到。(我使用 Pug 创建与您相同的源结构,样式也与您的相同,以便我们可以专注于 JS 面板和实现)。
在演示中,更改视口大小将重新排列网格项目。您可以通过调用在其他有趣的时刻手动触发重流flexgrid(container),例如异步加载项目然后重流。只要源结构保持不变,就允许更改项目的维度属性。
这是算法
步骤1)将容器设置为网格格式化上下文,将所有网格项布局在一行中,将每列宽度设置为max-content
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggg|hhh|iii|
Run Code Online (Sandbox Code Playgroud)
Step2) 找到第一条溢出网格线
|---container---|
|aaaaa|bbb|ccc|ddd|eee|fff|ggggg|hhh|iii|
^overflowed
Run Code Online (Sandbox Code Playgroud)
步骤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|
Run Code Online (Sandbox Code Playgroud)
由于所有列网格线都位于容器“内部”,因此我们已经完成了。在某些情况下,“包装”后会引入新的溢出网格线,我们需要重复步骤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.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
323 次 |
| 最近记录: |