牧羊人擅长照料他们的羊群,为羊群带来秩序和结构。 即使有数百只毛茸茸的动物,牧羊人仍然会在一天结束时将它们赶回农场。
在处理数据时,程序员常常不知道数据是否已正确过滤或排序。 当迭代数组然后在网站上显示数据时,尤其令人痛苦,因为不知道接收每个元素的位置。 Grid Shepherd 是一种技术,它使用 CSS Grid 而不是 JavaScript 来帮助将项目定位和排序到您想要的位置。
这就是我们将在本文中探讨的内容。 Grid Shepherd 技术可以为我们处理的数据带来秩序和结构,同时让我们比以往任何时候都更清楚地了解数据的使用位置和方式。
让我们深入了解。
使用 JavaScript 排序
我们将从迭代一个无序的农场动物数组开始。 想象一下,奶牛和绵羊在田野里快乐地吃草。 它们可以使用 Array.prototype.sort
方法以编程方式组合在一起并在页面上列出。
let animals = [
{ name: 'Edna', animal: 'cow' },
{ name: 'Liam', animal: 'sheep' },
{ name: 'Fink', animal: 'sheep' },
{ name: 'Olga', animal: 'cow' },
]
let sortedAnimals = animals.sort((a, b) => {
if (a.animal < b.animal) return -1
if (a.animal > b.animal) return 1
return 0
})
console.log(sortedAnimals)
/* Returns:
[ { name: 'Elga', animal: 'cow' },
{ name: 'Olga', animal: 'cow' },
{ name: 'Liam', animal: 'sheep' },
{ name: 'Fink', animal: 'sheep' } ]
*/
认识 Grid Shepherd
Grid Shepherd 方法使排序数据成为可能,**无需使用 JavaScript**。 相反,我们依靠 CSS Grid 为我们完成繁重的工作。
结构与上面的 JavaScript 对象数组完全相同,只是以 DOM 节点表示。
<main>
<div class="cow">Edna</div>
<div class="sheep">Liam</div>
<div class="sheep">Jenn</div>
<div class="cow">Fink</div>
</main>
查看 CodePen 上 David Bernegger (@Achilles_2) 的
1. 开始。
在 CodePen 上。
为了放牧动物,我们必须将它们围在一个公共区域内,这就是我们使用 <main>
元素的目的。 通过使用 display: grid
设置围栏,我们创建了一个 网格格式化上下文,我们可以在其中定义每只动物应占据的列(或行)。
.sheep { grid-column: 1; }
.cow { grid-column: 2; }
并且使用 grid-auto-flow: dense
,每只动物都会自动排列到每个定义区域的第一个可用位置。 这也可以与您想要的任意多个不同的排序选项一起使用——只需定义另一列,数据就会神奇地被放牧到其中。
main
display: grid;
grid-auto-flow: dense;
}
.sheep { grid-column: 1; }
.cow { grid-column: 2; }
查看 CodePen 上 David Bernegger (@Achilles_2) 的
2. 最终结果。
在 CodePen 上。
专业放牧
我们可以使用 CSS 计数器 进一步扩展我们的放牧示例。 通过这种方式,我们可以计算每列中有多少动物,并且——应用 Heydon Pickering 的数量查询(来自 Lea Verou 在 2011 年的演讲)——根据数量有条件地设置它们的样式。
数量查询依赖于某种用于计数类的选择器——这对于 :nth-child(An+B [of S]?)
伪类表示法来说非常棒,但目前它仅在 Safari 中可用)。 这意味着我们必须使用 :nth-of-type()
选择器作为解决方法。
我们需要一些新的元素类型才能使其正常工作。 这可以通过 Web Components 或将任何 HTML 元素重命名为自定义名称来实现。 即使这些元素不在 HTML 规范中,这也适用,因为浏览器使用 HTMLUnknownElement
来处理未定义的标签,这会导致它们的行为与 div 非常相似。 文档现在如下所示
<fence>
<sheep>Lisa</sheep>
<sheep>Bonnie</sheep>
<cow>Olaf</cow>
<sheep>Jenn</sheep>
</fence>
现在我们可以访问我们的自定义元素类型了。 当绵羊或奶牛的数量等于或小于 10 时,让我们应用红色背景。
sheep:nth-last-of-type(n+10),
sheep:nth-last-of-type(n+10) ~ sheep,
cow:nth-last-of-type(n+10),
cow:nth-last-of-type(n+10) ~ cow, {
background-color: red;
}
此外,计数器可以通过在父元素上使用 counter-reset: countsheep countcow;
并使用 before 选择器来定位每个元素并递增来轻松实现。
sheep::before {
counter-increment: countsheep;
content: counter(countsheep);
}
在这里,我们将使用 Vue 来动态添加和删除动物,使用 Vue 过渡 和两个不同的排序选项。 观察动物如何自然地占据正确的列,即使添加了更多动物并删除了一些动物也是如此。
查看 CodePen 上 David Bernegger (@Achilles_2) 的
3. 带有 Vue 过渡的最终结果。
在 CodePen 上。
Grid Shepherd 也可以用于任何无序数据以
- 分离和统计民意调查中的投票者(也许作为两个部分,以及相应的个人资料图片)并进行实时插入;
- 根据职位、年龄、身高对人员/同事进行分组;以及
- 创建任何层次结构
放牧和可访问性
grid-auto-flow: dense
不会更改网格的 DOM 结构——它只是在视觉上重新排序包含的元素。 在最后一个按字母顺序排序的示例中可以看到一个副作用,因为counter
数字会混淆。 更改 DOM 结构不仅会影响使用屏幕阅读器的人,还会影响标签遍历。
还要注意,扁平的文档结构 可能不利于屏幕阅读器。 相反,我会将这些演示网格视为图形,并提供更长的文本替代信息。
把它们都赶起来!
看到像网格这样的强大的 CSS 布局工具如何能够用于超出传统布局需求的用例,并应用于过去我们可能需要使用其他语言的场景,这真是太棒了。 在这种情况下,我们可以看到 CSS Grid 的布局优势和 JavaScript 的动态数据处理能力是如何重叠的,以及这如何为我们提供更多选择——以及能力——来按照我们的意愿弯曲渲染数据。
这很酷,但我很好奇会有多少用例。 按照文章的示例,如果您需要显示两个不同的列表,它们确实应该位于单独的
<ul>
标签中。不错。
想知道这是否易于访问。 当 UI 负责视觉外观时,一个可能不错的选项可能是按类型排序和渲染,以便将所有相同类型的元素放在一起?