在 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'`引起