带有 v-for 的 srcset

srcset with a v-for

我可能会错过一些基本的 vue.js 知识,但我有以下与 <picture> 相关的问题,特别是 srcset

我的 api 中有相同图片的不同格式,如下所示:

"posts": [
  {
    "image": {
      "formats": {
        "thumbnail": {
          "hash": "thumbnail_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 245,
          "height": 138,
          "size": 76.89,
          "url": "/uploads/thumbnail_image.png"
        },
        "large": {
          "hash": "large_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 1000,
          "height": 563,
          "size": 916.23,
          "url": "/uploads/large_image.png"
        },
        "medium": {
          "hash": "medium_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 750,
          "height": 422,
          "size": 562.28,
          "url": "/uploads/medium_image.png"
        },
        "small": {
          "hash": "small_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 500,
          "height": 281,
          "size": 275.16,
          "url": "/uploads/small_image.png"
        }
      }
    }
  },

我想要得到的最终结果是这样的:

<picture>
  <source srcset="https://apiurl.com/large_image.png 1000w, https://apiurl.com/medium_image.png  750w, https://apiurl.com/small_image.png 500w" />
</picture>

我已经将所有格式作为道具传递到组件中,因此它们都存储为 "images"

基本上我想要的是有一个单一的 source 可以遍历格式(不一定总是有大或小)并在里面添加 URL :srcset.

当然可以

<source v-for="format in images" :srcset="apiUrl + format.url">

有效但会生成多个 source

针对这种情况的最佳方法或解决方案是什么? 谢谢

简单的解决方案:

如果您不想使用 computedcomponent,您可以只使用传递 post 并且它 returns srcset urls.

methods: {
    postSrcSetUrls(post) {
        if (!post || !post.image || !post.image.formats)
            return null;

        let sizes = Object.keys(post.image.formats);
        return sizes.map(size => `${post.image.formats[size].url} ${post.image.formats[size].width}w`).join(", ");
    }
}

然后,在您的模板中

<picture v-for="post in posts">
    <source :srcset="postSrcSetUrls(post)" />
</picture>

计算/组件解决方案:

我会制作一个组件并使用 computed 属性 来完成您想要做的事情。然后,您可以使用 Object.keys 获取格式大小的名称,然后可以使用这些名称循环遍历您的格式。

我在下面包含了一个片段,您可能需要稍微更改一下,例如包含您的 api url.

这使用了文档的 Props, Computed Properties, Template Syntax, List Rendering and Component Registration 部分,可能会有用。

Vue.component("post-image-formats", {
  template: "<div><strong>Src Set Url</strong><br /> {{srcsetUrl}}</div>",
  props: ["formats"],
  computed: {
    srcsetUrl() {
      if (!this.formats)
        return null;

      let sizes = Object.keys(this.formats);
      return sizes.map(size => `${this.formats[size].url} ${this.formats[size].width}w`).join(", ");
    }
  }
});

let posts = [{
    "image": {
      "formats": {
        "thumbnail": {
          "hash": "thumbnail_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 245,
          "height": 138,
          "size": 76.89,
          "url": "/uploads/thumbnail_image.png"
        },
        "large": {
          "hash": "large_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 1000,
          "height": 563,
          "size": 916.23,
          "url": "/uploads/large_image.png"
        },
        "medium": {
          "hash": "medium_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 750,
          "height": 422,
          "size": 562.28,
          "url": "/uploads/medium_image.png"
        },
        "small": {
          "hash": "small_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 500,
          "height": 281,
          "size": 275.16,
          "url": "/uploads/small_image.png"
        }
      }
    }
  },
  {
    "image": {
      "formats": {
        "thumbnail": {
          "hash": "thumbnail_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 245,
          "height": 138,
          "size": 76.89,
          "url": "/uploads/thumbnail_image.png"
        },
        "large": {
          "hash": "large_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 1000,
          "height": 563,
          "size": 916.23,
          "url": "/uploads/large_image.png"
        },
        "medium": {
          "hash": "medium_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 750,
          "height": 422,
          "size": 562.28,
          "url": "/uploads/medium_image.png"
        },
        "small": {
          "hash": "small_image",
          "ext": ".png",
          "mime": "image/png",
          "width": 500,
          "height": 281,
          "size": 275.16,
          "url": "/uploads/small_image.png"
        }
      }
    }
  }
];

new Vue({
  el: "#app",
  data: () => {
    return {
      posts: posts
    };
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div>
    <post-image-formats v-for="post in posts" :formats="post.image.formats"></post-image-formats>
  </div>
</div>