Vue组件中的响应式道具

时间:2017-09-04 20:52:40

标签: css vue.js vuejs2 vue-component

我在Vue组件中有一个名为src的道具,它绑定到:style,如下所示:

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

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

我想要做的是根据网站访问者的设备或屏幕大小创建一个响应式道具列表。

例如,我想象一个道具列表,如src-smsrc-mdsrc-lg等。用户可以为不同的设备尺寸输入不同的图片网址,并且样式attr会使用适当的网址取决于屏幕/尺寸。

这是否可以在VueJS中使用。如果是这样,任何想法如何?

感谢。

2 个答案:

答案 0 :(得分:1)

不幸的是,你要做的事情并非无足轻重。这是因为内联样式标记无法接受媒体查询。

spec声明:

  

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模板中拥有样式标记。它会抛出一个错误:

  

模板应该只负责将状态映射到UI。避免在模板中放置带副作用的标签,例如,因为它们不会被解析。

由于错误描述了vue被设计为地图状态UI。禁止在模板中使用style标签,因为这可能会导致外部世界泄漏。

虽然你不能在模板中声明性地使用样式,但是我们可以在组件的挂钩中使用一些JS来添加目标和动态样式。

首先,我们需要将动态样式约束到此元素。我们可以使用创建的组件this._uid的内部id,附加到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计算属性生成的字符串是我们在mount上创建样式标记时将要使用的字符串。在mount中,我们创建一个样式节点并附加到头部。将节点分配给vm以进行引用。

使用vm中的引用,我们可以观察计算更新样式节点的更改。

请记住在破坏组件之前清理,删除样式节点。

{
    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/

答案 1 :(得分:0)

您还可以尝试此处描述的模块:https://alligator.io/vuejs/vue-responsive-components/,称为vue-response-components

它允许组件根据其自身宽度(而不是整个浏览器的宽度)更改CSS。