【问题标题】:Masonry layout adaptative to child's height适应儿童身高的砌体布局
【发布时间】:2021-08-05 11:44:12
【问题描述】:

我的网站上有一个页面,我在其中展示了一些砖石布局的卡片。

它是在 Vue 3 中实现的,我希望布局能够适应容器的子高度。

布局从上到下,从左到右。就像图片显示的那样:

为了实现这一点,我使用order CSS 属性和弹性框将卡片分成不同的列。

但是,要使其正常工作,父容器需要具有固定高度。

我希望这是确保所有卡片都适合的最小高度,即布局中最长列的确切高度。

我最初尝试将容器的高度设置为 0,然后根据卡片的高度对其进行更新,但是,这不是很好,而且真的很笨拙。

<template>
    <section class="container" :style="{ height: containerHeight }">
        <project-card v-for="i in projects.length" :key="i" :project="projects[i - 1]"
                      :style="{ order: (i - 1) % numberColumns + 1, width: (100 / numberColumns) - 1.5 + '%' }"
                      :ref="setProjectCardRef">
        </project-card>

        <span v-for="i in numberColumns - 1" :key="i" :style="{ order: i }" class="item break"></span>
    </section>
</template>

<script>
import Projects from "@/api/Projects";
import ProjectCard from "@/components/ProjectCard";

export default {
    name: "Projects",
    components: {
        "project-card": ProjectCard,
    },
    data() {
        return {
            projects: [],
            projectCardsRefs: [],
            windowWidth: window.innerWidth,
            containerHeight: "100%"
        }
    },
    mounted() {
        this.getData();
        window.addEventListener('resize', () => {
            this.windowWidth = window.innerWidth
        })
    },
    methods: {
        getData() {
            Projects.list().then((response) => {
                for (let project of response.data)
                    project.image_url = process.env.VUE_APP_API_ENDPOINT + project.image_url;
                this.projects = response.data;
            });
        },
        setProjectCardRef(el) {
            if (!this.projectCardsRefs.includes(el))
                this.projectCardsRefs.push(el)
        }
    },
    computed: {
        numberColumns() {
            return Math.round(this.windowWidth / 400)
        },
    },
    async updated() {
        await new Promise(r => setTimeout(r, 200));
        let heights = Array(this.numberColumns).fill(0)
        
        for (let i = 0; i < this.projectCardsRefs.length; i++) {
            const style = this.projectCardsRefs[i].$el.currentStyle || window.getComputedStyle(this.projectCardsRefs[i].$el);
            const marginTop = parseInt(style.marginTop.match(/\d+/g)[0]);
            const height = parseFloat(style.height.match(/\d+(.\d+)?/g)[0]);
            heights[i % this.numberColumns] += height + marginTop
        }

        this.containerHeight = 40 + Math.max(...heights) + "px";
    }
}
</script>

<style scoped>
.container {
    @apply flex flex-col flex-wrap space-y-6;
}
.break {
    @apply mx-3 w-0;
    flex-basis: 100%;
}
</style>

如何以更灵敏的方式根据其子级设置容器的高度?

【问题讨论】:

  • 更新了问题@Paulie_D
  • 定义“更具响应性”,不,flexbox 需要定义的高度。我建议你真的需要 masonry.js。
  • 你可以看到它目前是如何实现的here。一开始有一个短暂的时刻,当它仍在更新容器并且内容正在加载时,卡片会在其中跳来跳去。当页面调整大小时也会发生这种情况,并且并不总是正确计算高度,有时会与必要的高度相差一些像素并使内容不合适

标签: css vue.js


【解决方案1】:

按照 Paulie_D 的建议,我使用 Masonry.JS 实现了它

<template>   
    <section id="container" v-masonry transition-duration="0.2s" item-selector=".item"
             percent-position="true" ref="container" :gutter="spaceBetween">
        <project-card class="item" v-masonry-tile v-for="i in projects.length" :key="i" :project="projects[i - 1]"
                      :style="`width: ${itemWidth}px; margin-bottom: ${spaceBetween}px`"/>
    </section>
</template>

<script>
import Projects from "@/api/Projects";
import ProjectCard from "@/components/ProjectCard";

export default {
    name: "Projects",
    components: {
        "project-card": ProjectCard,
    },
    data() {
        return {
            projects: [],
            containerWidth: 0,
            spaceBetween: 20
        }
    },
    mounted() {
        this.getData();

        new ResizeObserver(this.onResize).observe(document.getElementById("container"))
        this.onResize()
    },
    methods: {
        getData() {
            Projects.list().then((response) => {
                for (let project of response.data)
                    project.image_url = process.env.VUE_APP_API_ENDPOINT + project.image_url;

                this.projects = response.data;
            });
        },
        onResize() {
            this.containerWidth = document.querySelector("main").offsetWidth;
        }
    },
    computed: {
        numberColumns() {
            return Math.round(this.containerWidth / 400);
        },
        itemWidth() {
            return (this.containerWidth - this.numberColumns * this.spaceBetween) / this.numberColumns;
        }
    }
}
</script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-17
    • 2020-05-30
    • 2013-03-20
    • 2019-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多