Отзывчивый реквизит в компоненте Vue

У меня есть опора под названием src в компоненте Vue, которая привязывается к :style следующим образом:

<template>
  <section :class="color" class="hero" :style="{ backgroundImage: src && 'url(' + src + ')' }">
    <slot></slot>
  </section>
</template>

<script>
  export default {
    props: ['src', 'color']
  }
</script>

Что я хотел бы сделать, так это создать список адаптивных свойств, которые будут использоваться в зависимости от устройства или размера экрана посетителя сайта.

Например, я представляю себе список реквизитов, таких как src-sm, src-md, src-lg и т. Д. Пользователь вводит разные URL-адреса изображений для разных размеров устройства, а атрибут стиля будет использовать соответствующий URL-адрес в зависимости от экрана / размера.

Возможно ли это в VueJS. Если да, то как?

Спасибо.


person Moshe    schedule 04.09.2017    source источник
comment
Что-то вроде css-tricks.com/?   -  person Roy J    schedule 05.09.2017
comment
Вы ничего не показали о размерах изображений и о том, как вы определите, нужны ли вам src-md или src-lg? что ты уже испробовал?   -  person Andrey Popov    schedule 05.09.2017
comment
@RoyJ Выглядит отлично, но я не думаю, что это работает для фоновых изображений (поправьте меня, если я ошибаюсь).   -  person Moshe    schedule 05.09.2017
comment
@AndreyPopov Размеры изображений могут быть изменены пользователем, но значения по умолчанию будут основаны на размерах по умолчанию в vueitfyjs. Я еще не много пробовал (сейчас я изучаю возможность использования прослушивателя событий после того, как компонент был смонтирован, но я столкнулся с ошибками при попытке настроить что-то.   -  person Moshe    schedule 05.09.2017
comment
Фоновые изображения - это CSS, который использует медиа-запросы для адаптивного дизайна. См. smashingmagazine.com/2013/07/   -  person Roy J    schedule 05.09.2017
comment
Взгляните на vue-match-media.   -  person smilly92    schedule 05.09.2017


Ответы (2)


К сожалению, то, что вы пытаетесь сделать, нетривиально. Это связано с тем, что встроенные теги стиля не могут принимать медиа-запросы.

В спецификации говорится:

Значение атрибута style должно соответствовать синтаксису содержимого блока объявления CSS.


Решение 1. Это самое простое решение, возможно, не совсем то, что вы ищете.

Он работает, включая img элементов и показывая их скрытие через CSS.

<template>
    <div>
        <img class="image--sm" :src="src.sm" />
        <img class="image--md" :src="src.md" />
        <img class="image--lg" :src="src.lg" />
   </div>
</template>

<script>
    export default {
        props: {
            src: Object
        }
    }
</script>

<style>
    .image--md,
    .image--lg {
        display: none;
    }

    @media (min-width: 400px) {
        .image--sm {
            display: none;
        }

        .image--md {
          display: block;
        }
    }

    @media (min-width: 600px) {
        .image--md {
            display: none;
        }

        .image--lg {
            display: block;
        }
    }
</style>

Пример: https://jsfiddle.net/h3c5og08/1/.


Решение 2:

Теги изображений могут быть не тем эффектом, которого вы пытаетесь достичь. Это решение создает тег стиля в заголовке и вводит содержимое css для изменения фоновых изображений.

У вас не может быть тегов стилей в шаблоне Vue. Это вызовет ошибку, например:

Шаблоны должны отвечать только за отображение состояния в пользовательский интерфейс. Избегайте размещения тегов с побочными эффектами в ваших шаблонах, например, поскольку они не будут анализироваться.

Поскольку ошибка описывает, vue предназначен для отображения состояния пользовательского интерфейса. Использование тегов style в шаблоне запрещено, так как это может вызвать утечку информации во внешний мир.

Хотя вы не можете декларативно стили в шаблоне, мы можем использовать немного JS в смонтированном хуке компонента для добавления целевых и динамических стилей.

Сначала нам нужно ограничить этот элемент динамическими стилями. Мы можем использовать внутренний идентификатор созданного компонента this._uid, прикрепив его к области видимости css. (Обратите внимание, что это внутренний API, поэтому в него могут быть внесены изменения)

<template>
    <div class="image" :data-style-scope="_uid">
    </div>
</template>

Следующей частью является создание стиля в вычисляемом свойстве для последующего внедрения в блок стиля. Вы можете расширить это вычисляемое свойство, чтобы условно назначить свойства и т. Д. Примечание: сохраните для свойств только динамические значения.

css () {
    const selector = `.image[data-style-scope="${this._uid}"]`
    const img = val => `${selector} { background-image: url("${val}"); }`
    const sm = img(this.sm)
    const md = img(this.md)
    const lg = img(this.lg)

    return `
        ${sm}
        @media (min-width: 200px) { ${md} }
        @media (min-width: 300px) { ${lg} }
    `    
}

Эта сгенерированная строка из вычисляемого свойства css - это то, что мы теперь будем использовать при создании тега стиля при монтировании. При монтировании мы создаем узел стиля и добавляем его к голове. Назначение узлов виртуальной машине для ссылок.

Используя ссылки в виртуальной машине, мы можем наблюдать за изменениями в вычисляемом обновлении узла стиля.

Не забудьте очистить перед уничтожением компонента, удалив узел стиля.

{
    data () {
        return {
            // Reference data properties
            style: null,
            styleRef: null
        }
    },

    mounted () {
        // Create style node
        let style = document.createElement('style')
        style.type = "text/css"
        style.appendChild(document.createTextNode(''))

        // Assign references on vm
        this.styleRef = style
        this.style = style.childNodes[0]

        // Assign css the the style node
        this.style.textContent = this.css

        // Append to the head
        document.head.appendChild(style)
    },

    beforeDestroy () {
        // Remove the style node from the head
        this.style.parentElement.removeChild(this.style)
    },

    computed: {
        css () {
            // ...
        }
    },

    watch: {
        css (value) {
            // On css value change update style content
            this.style.textContent = this.css
        }
    }
}

Рабочий пример: https://jsfiddle.net/bLkc51Lz/4/

person Blake Newman    schedule 05.09.2017

Вы также можете попробовать модуль, описанный здесь: https://alligator.io/vuejs/vue-responsive-components/, который называется vue-response-components.

Он позволяет компоненту изменять свой CSS в зависимости от его собственной ширины (а не от всей ширины браузера).

person alexk    schedule 12.09.2018