【问题标题】:Vue 3 Masonry LayoutVue 3 砌体布局
【发布时间】:2021-03-06 07:37:38
【问题描述】:

有人知道适用于 Vue 3 和服务器端渲染的砌体布局吗?

我的要求是我不能预先指定列,我希望砖石布局能够解决这个问题。

在我的 Vue 2 应用程序中,我使用的是“vue-masonry”。我还必须使用“vue-client-only”作为我的应用程序,因为我的应用程序是服务器呈现的应用程序。

  <!-- Only rendered during client side rendering, vue-masonry is not support in SSR -->
  <client-only>
    <div
      class="grid"
      v-masonry="containerId"
      transition-duration="0.3s"
      item-selector=".grid-item">
      <div
        v-masonry-tile class="grid-item"
        v-for="(item, i) in items"
        v-bind:key="i">
        <img
          :src="getItemImage(item)"
          :data-key=i
          alt="Small preview">
      </div>
    </div>
  </client-only>

当我在我的 Vue 3 项目中有这个时,我得到了错误

slot is not a function

我尝试使用“vue-masonry-css”,但失败了

Uncaught TypeError: Cannot read property 'use' of undefined

如下代码

import Vue from 'vue';
import VueMasonry from 'vue-masonry-css';
Vue.use(VueMasonry);

【问题讨论】:

    标签: masonry vuejs3


    【解决方案1】:

    我自己一直在寻找实现动态 Masonry 布局的答案,但没有任何东西适合我,所以我不得不为我的博客页面开发自己的算法,甚至支持 IE11 和 Edge 浏览器。

    1.网格布局应具有以下结构:

    <div class="grid-container">
        <div class="grid-item">
            <div class="grid-item-content"></div>
        </div>
    </div>
    

    2. 设置网格容器的样式:

    .grid-container {
        min-width: 70%;
        max-width: 100%;
        display: grid;
        column-gap: 1rem;
        grid-template-columns: repeat( auto-fit, minmax(22em , 1fr));
        grid-auto-rows: 300px;
     }
    
    .grid-item {
        height: fit-content;
        /*add the rest of your desired styling properties*/
     }

    您可以更改容器的宽度并为其分配您想要的任何值。

    上述css sn-p的另外两个重要属性是:

    • grid-template-columns 生成响应式网格项目,最小宽度为 22em,最大宽度等于网格容器 1fr 的宽度。
    • grid-auto-rows 属性,顾名思义,隐式给出行高。为了使我们的砌体布局算法正常工作,我给出了在我的案例中网格项可以具有的最小高度值。

    3.下面的js算法会在加载后调整网格项以实现砌体布局:##

    resizeAllGridItems() {
        //calculate the grid container with
        let gridWidth = document.getElementsByClassName("grid-container")[0].offsetWidth;
        /*calculate the grid item width (the width should be the same for all grid items
        because we used `repeat( auto-fit, minmax(22em , 1fr))` to generate our responsive
        columns)*/
        let gridItemWidth = document.getElementsByClassName("grid-item")[0].offsetWidth;
        /*devide the with of the grid container by the with of the grid item item to get
        the number of generated columns*/
        let columnsNumber = ~~(gridWidth / gridItemWidth);
    
        /*the second part of the algorithm with loop through all the generated grid items.
        Starting with the second row, the grid item in that row will be given a `margin
        -top` value that equals the height of the grid item situated right above it, minus
        the value of `grid-auto-rows`. This way whenever there's an extra space, the grid
        item below will have it's `margin-top` value adjusted to take the extra space.*/
        let x = columnsNumber;
        let colIdx = 0;
        let columnsHeights = [0, 0, 0];
        let tempColumnsHeights = [];
        let allItems = document.getElementsByClassName("grid-item");
        for(x; x<allItems.length; x++) {
          let topItemHeight = columnsHeights[colIdx] + allItems[x - columnsNumber].offsetHeight;
          allItems[x].style.marginTop = (topItemHeight - 300) + 'px';
          tempColumnsHeights.push(topItemHeight - 300);
          colIdx++;
    
          /*move to the next row of grid items to adjust them if all the items of the
          previous row are adjusted*/
          if (colIdx === columnsNumber) {
            colIdx = 0;
            columnsHeights = tempColumnsHeights;
            tempColumnsHeights = [];
          }
        }
      }

    就是这样。现在您有了一个砌体布局,它是通过以编程方式调整网格项的边距顶部来制作的,其中考虑了几个变量,例如自动行的值、网格项的高度、它们的宽度和网格容器的宽度。

    我遇到了几篇文章,这些文章还解释了实现砌体布局的其他方法和算法,但它们对我不起作用。这个来自 css-Trick 的 article 解释了很多实现砌体布局的方法。但是我已经尝试了这两种其他方法,但对我不起作用:

    • the first 根据网格项的高度和内容调整grid-row-end 的值,使网格项跨越一行或多行。
    • 第二种方法是使用第三方库,例如Masonry

    注意如果您使用带有图像元素的网格项:我发现我尝试使用的 this article 使用了 imagesLoaded.js 库。使用这个库可以在加载所有图像后执行算法。在我的例子中,我给图像容器一个固定的高度,这样我的文章卡片的高度将独立于它包含的图像。

    IE11 和 Edge 支持

    使用 autoprefixer npm 包,它是一个 PostCSS 插件来解析 CSS 并使用 Can I Use 中的值将供应商前缀添加到 CSS 规则中。由谷歌推荐并在 Twitter 和阿里巴巴中使用。它添加所有必要的前缀并解析 IE11 和边缘的网格显示属性。您可以参考这个答案,了解如何使用 autoprefixer 启用网格支持,因为它默认被禁用:https://stackoverflow.com/a/61144097/8453311

    【讨论】:

      【解决方案2】:

      我还在寻找支持 SSR 和 Vue 3 的砖石布局。 由于找不到适合我的用例,我创建了https://github.com/DerYeger/vue-masonry-wall

      查看https://vue-masonry-wall.yeger.eu/ 的演示,看看它是否符合您的要求。

      【讨论】:

        【解决方案3】:

        在 Vue 3 中,no export global Vue instance 就像在 Vue 2 中一样。 当我检查 vue-masonry 源代码时,他们使用 Vue 全局实例,Vue 2 指令 API (breaking change in Vue 3)。

        所以我认为必须阅读该库并将其移植到 Vue 3 才能使其工作。 我遇到了同样的情况,仍在寻找支持 Vue 3 的库。 如果我找不到,也许我会在接下来的 2-3 周内自行移植。

        【讨论】:

          【解决方案4】:

          您是否尝试在 main.js 中添加 Vue Mansory

          喜欢:

          import VueMasonry from 'vue-masonry-css'
          
          createApp(App).use(VueMasonry).mount('#app')
          

          【讨论】:

            猜你喜欢
            • 2021-09-19
            • 2013-03-20
            • 2019-11-11
            • 2021-12-22
            相关资源
            最近更新 更多