Правильный способ обработки атрибута <picture>srcset в Vue - PullRequest
2 голосов
/ 02 августа 2020

У меня есть приложение 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 и передает некоторые свойства компоненту 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>

Это работает нормально, изображения отображаются так, как должны, однако теперь я хочу заменить свой тег img на picture тег, который будет иметь резервные варианты для старых браузеров (так как я хочу использовать webp), а также некоторые правила адаптивного изображения.

Очевидно, однако, я не могу просто использовать тот же require, что и я ' m без расширения файла, так как тогда Webpack не сможет распознать, какой ресурс он должен использовать.

Насколько я понимаю, единственный вариант, который я могу придумать, - это иметь разные props для шаблона 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>

Есть ли способ сделать то, что я бы предпочел сделать в этой ситуации?

РЕДАКТИРОВАТЬ: Решение

Тони предложили хорошее решение, однако я пошел гораздо более простым путем и просто поместил свои изображения в каталог public/. Не нужно так бороться с импортом веб-пакетов!

1 Ответ

1 голос
/ 02 августа 2020

Вместо того, чтобы иметь свойство image в вашем ProjectCard компоненте, как насчет images prop?

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>
...