在 Vue 中处理 <picture> srcset 属性的正确方法

Posted

技术标签:

【中文标题】在 Vue 中处理 <picture> srcset 属性的正确方法【英文标题】:Proper way to handle <picture> srcset attribute in Vue 【发布时间】:2020-11-22 16:32:09 【问题描述】:

我有一个带有项目页面的 Vue 应用程序,我希望在其中有许多 Project 卡片,每个卡片都附有图片。

这就是我的Projects.vue 路由/组件目前的样子。为了简洁起见,我省略了一些不相关的divs 和类。

<template>
    <div>
        <ProjectCard
            v-for="project in ProjectList"
            :key="project.title"
            :title="project.title"
            :description="project.description"
            :image="require(`../assets/images/projects/$project.name.jpg`)"
        />
    </div>
</template>

<script>
    import ProjectCard from "@/components/ProjectCard";
    import ProjectList from "@/assets/images/projects/imageList.json";

    export default 
        name: "Projects",
        components: 
            ProjectCard
        ,
        data() 
            return 
                ProjectList
            ;
        
    ;
</script>

如您所见,它只是循环遍历一个 JSON 列表并将一些 props 向下传递给 ProjectCard 组件。

这是ProjectCard 组件

<template>
    <div>
        <img :src="image" />
        <h1> title </h1>
        <h3> description </h3>
    </div>
</template>

<script>
    export default 
        name: "ProjectCard",
        props: 
            image: String,
            title: String,
            description: String
        
    ;
</script>

这很好用,图片按原样显示,但是我现在想用picture 标记替换我的picture 标记,该标记将为旧浏览器提供后备(因为我想使用webp)作为以及一些响应式图片规则。

但很明显,我不能只使用我正在使用的相同 require 而不使用文件扩展名,因为这样 Webpack 将无法识别它应该使用的资产。

就我所见,我能想到的唯一选择是为ProjectCard 模板设置不同的道具来引用每种不同的图像格式,但这似乎太手动了。假设目录看起来像这样:

projects /
    a-small.jpg
    a-medium.jpg
    a-large.jpg
    a-small.webp
    a-medium.webp
    a-large.webp

我必须制作 5 个额外的道具,才能正确显示一张图像,而不是只拥有一个我可以传递的道具,然后在 html 中执行类似的操作

<picture>
    <source media="(max-width: 1400px)" :srcset="`$image-large.webp`" >
    <source media="(max-width: 1000px)" :srcset="`$image-medium.webp`" >
    <source media="(max-width: 600px)" :srcset="`$image-small.webp`" >
    <source media="(max-width: 1400px)" :srcset="`$image-large.jpg`" >
    <source media="(max-width: 1000px)" :srcset="`$image-medium.jpg`" >
    <source media="(max-width: 600px)" :srcset="`$image-small.jpg`" >
</picture>

在这种情况下有什么方法可以做我想做的事吗?

编辑:解决方案

Tony 提供了一个很好的解决方案,但是我采用了更简单的方法,只需将我的图像放在 public/ 目录中即可。无需尝试以这种方式处理 webpack 导入!

【问题讨论】:

可能更容易使用vue-lazyload。内置动态srcset 功能 【参考方案1】:

不要在ProjectCard 组件中使用image 属性,而使用images 属性呢?

Projects.vue

<template>
    <div>
        <ProjectCard
            v-for="project in ProjectList"
            :key="project.title"
            :title="project.title"
            :description="project.description"
            :images="imagesAndMaxWidthMapped"
        />
    </div>
</template>

<script>
    import ProjectCard from "@/components/ProjectCard";
    import ProjectList from "@/assets/images/projects/imageList.json";

    export default 
        name: "Projects",
        components: 
            ProjectCard
        ,
        data() 
            return 
                ProjectList: ....,
                imagesAndMaxWidthMapped: [
                   maxWidth: '1400px', src: 'a-large.webp',
                   maxWidth: '1000px', src: 'a-medium.webp',
                   maxWidth: '600px',  src: 'a-small.webp',
                   maxWidth: '1400px', src: 'a-large.jpg',
                   maxWidth: '1000px', src: 'a-medium.webp',
                   maxWidth: '1000px', src: 'a-small.jpg',
                ]
            ;
        
    ;
</script>

ProjectCard.Vue

<template>
    <div>
      <picture>
        <source v-for="(image, index) in images" :key="index" media="(max-width: `$image.maxWidth`)" :srcset="require(`../assets/images/projects/$image.src`">
      </picture>
      <h1> title </h1>
      <h3> description </h3>
    </div>
</template>

<script>
    export default 
        name: "ProjectCard",
        props: 
            images: 
              type: Array,
              required: true,
            ,
            title: String,
            description: String
        
    ;
</script>

【讨论】:

这是一个很好的解决方法,但是我采用了更简单的方法并将图像放在public/ 目录中。不需要 webpack 恶作剧

以上是关于在 Vue 中处理 <picture> srcset 属性的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

vue-jest 错误:“SyntaxError: Unexpected token <”由`import PictureInput from 'vue-picture-input'`引起

vue中input框的fileREader技术上传图片

POJ 1177 Picture

vue实现头像上传

vue头像上传压缩

在 HTML5 的 <figure> 元素中使用 <picture>?