到目前为止,学习Vue的时候也写了相当的示例,但老实说,这些示例在视觉上并没有什么吸引人的地方。今天我们将学习如何将样式运用到我们的元素中,让事情变得更加有趣。首先我们将通过将内联样式添加到HTML的元素中,其实也就是我们以前所说的内联样式。其实在学习v-bind的时候,我们已经或多或少的接触了,如何给元素添加内联样式或者绑定类名添加样式。但这可能不够系统,为了更好的学习这方面的知识,这篇文章专门是学习这方面知识而做的笔记。希望对和我一样的初学者有所帮助。

在Vue中使用内联样式

比如说,我们有一个widthheight都是200pxdiv,我想做的第一件事情就是设置这个元素的背景色为blue

<div style="width: 200px; height: 200px;" v-bind:style=""></div>

v-bind绑定到style属性时,表达式可以是对象也可以是数组。先看看对象语法是什么样子。这个对象中的键应该与想要设置的CSS样式相匹配,而值应该是一个表达式,它可以解析为一个值。在这种情况下,对象的keybackground-color。在JavaScript中,我们需要将键值放在引号内,因为它包含了一个破折号-。请注意,我将在这里使用单引号,因此不必避免双引号,因为它们会干扰HTML标记。

这就是我想要应用到div元素的样式的别名,对于值,也可以简单地在单引号中写入,比如blue

<div style="width: 200px; height: 200px;" v-bind:style="{ 'background-color': 'blue' }"></div>

我们期望看到一个blue的正方形。

在Vue中使用样式

事实上,这并没有起任何作用,因为我们在模板中直接定义了颜色。如果这就是我们所需要的,那么还不如直接在div元素的style属性中添加需要的样式,这样做将更有用。事实上,在Vue中通过v-bind绑定style是期望绑定一个动态颜色。让我们创建一个包含颜色的数据属性,并绑定到模板中的这个属性。

let app = new Vue({
    el: '#app',
    data () {
        return {
        color: 'blue'
        }
    }
})

现在我只需要将这个属性的名称作为background-color的表达式,结果是相同的。

<div style="width: 200px; height: 200px;" v-bind:style="{ 'background-color': color }"></div>

当然,这也不太有用,因为我们在Vue实例中硬编码了color。但这让我们能做的就是动态改变color。当我们这么做的时候,你也将会猜到,Vue将自动更新样式,因为我们已经将background-color绑定到了data中的color属性。为了展示这个效果,咱们可以添加一个button,给这个button绑定一个click事件,点击事件监听div颜色改变。

<div id="app">
    <button @click="{{changeColor}}">Click Me (^_^)</button>
    <div style="width: 200px; height: 200px;" v-bind:style="{ 'background-color': color }"></div>
</div>

使用Vue的computedbutton添加了changeColor。这个方法里侦听了background-color的改变,使用简单的if语句,将data中的colorblue转换成red

let app = new Vue({
    el: '#app',
    data () {
        return {
        color: 'blue'
        }
    },
    computed: {
        changeColor: function () {
            if (this.color = 'blue') {
                this.color = 'red'
            } else {
                this.color = 'blue'
            }
        }
    }
})

看到的效果如下:

在Vue中使用样式

当你点击按钮之后,我们看到div元素的背景从blue变成了red

上面的示例中,咱们使用的是Vue的computed,除了使用computed还可以使用methods或者说watch

你可能会想到,如果我们在模板中添加更多的属性,就很难读取它。为了解决这个问题,我们可以简单地将对象移到data中,并在模板中引用该属性,比如我将调用data中的styles属性。

将上面的代码稍微清理一下,历为我们将不再需要更改颜色的按钮。

data () {
    return {
        styles: {
            'background-color': 'blue'
        }
    }
}

有了这个,就可以在模板中通过v-bind调用styles

<div style="width: 200px; height: 200px;" v-bind:style="styles"></div>

你将看到的效果是和前面的示例一样的:

在Vue中使用样式

在文章最开始之前,你是否注意到了,在HTML模板中引用了一个style属性。我们可以将style属性中运用到的样式,一起放到datastyles中:

data () {
    return {
        styles: {
            'background-color': 'blue',
            width: '200px',
            height: '200px'
        }
    }
}

<div v-bind:style="styles"></div>

对于简单的例子来说,这一切都很好,但是如果我们需要使用其他数据属性来确定样式呢?也许我们总是想把width设置为height的一半。当然,我们可能会偷懒,只是把宽度改变100px,但这么做很没趣,是吧。由于我们无法从styles对象中访问其他数据属性,所以我们需要做些别的事情。你可能猜到了,我们可以使用Vue的computed。因此,让我们将数据属性改为一个计算属性。

let app = new Vue({
    el: '#app',
    data () {
        return {
            //
        }
    },
    computed: {
        styles: function () {
        let height = 200

        return {
            'background-color': 'blue',
            width: (height / 2) + 'px',
            height: height + 'px'
        }
        }
    }
})

<div v-bind:style="styles"></div>

在Vue中使用样式

现在我们看到的宽度是高度的一半。关键是,如果你的样式不依赖另一个数据属性,或者如果它们使用了计算属性,则可以使用数据属性。

前面也提到过,除了可以使用对象之外,还可以使用数组的样式。这可能有点不太常见,但让我们看看如何做。

如果我们添加一个数组而不是一个对象,那么这个数组实际上应该是一个对象数组,其中每个对象使用的语法和我们刚才看到的一样。重点是你可以重写样式。因此,我添加了一个名为moreStyles的新数据属性,它通过使用border-radiusdiv添加圆角。

let app = new Vue({
    el: '#app',
    data () {
        return {
            moreStyles: {
                'border-radius': '5px'
            }
        }
    },
    computed: {
        styles: function () {
            let height = 200

            return {
                'background-color': 'blue',
                width: (height / 2) + 'px',
                height: height + 'px'
            }
        }
    }
})

<div v-bind:style="[styles, moreStyles]"></div>

在Vue中使用样式

当然,我们可以引用一个由数组组成的数据属性,也可以是一个返回数组的计算属性。

它将两个对象合并在一起,所以说,我们运行代码,你会看到div仍然有相同的样式,但它现在也有圆角。这是因为VUe将这些对象合并在一起。值得注意的是,数组中的对象优先于它闪之前添加的任何对象。如果我将background-colormoreStyles中添加,并设置其值为red,我们会看到div的背景色变成了red。虽然我们已经在第一个对象styles,也就是computed中设置的background-colorblue

let app = new Vue({
    el: '#app',
    data () {
        return {
            moreStyles: {
                'border-radius': '5px',
                'background-color': 'red'
            }
        }
    },
    computed: {
        styles: function () {
            let height = 200

            return {
                'background-color': 'blue',
                width: (height / 2) + 'px',
                height: height + 'px'
            }
        }
    }
})

在Vue中使用样式

有趣的是,Vue会自动地将CSS样式预先修改,以确保浏览器的最大兼容性。这意味着在使用这样的内联样式时,不需要担心使用自动修复程序之类的工具,因为这些工具很难使用内联样式。

上在我们看到的都是在Vue中怎么使用内联样式,其实除了内联样式,还可以使用CSS的class样式。接下来看看如何在Vue中使用CSS的类样式。

在Vue中使用CSS类的样式

通过前面的学习,我们知道如何通过v-bind绑定style属性来添加内联样式,现在我们来看看如何使用类来进行样式美化。虽然使用样式属性是很方便的,有时也很有必要的,但很多时候都是基于元素的classid在外部编写CSS样式才是最佳的方式。

我已经提前准备了一些简单的CSS的类。假设我们有一个shapes的数组,它可以是一个圆,也可以是一个正方形,而且每个形状都有一些与之相关的通用样式。我们通过在每个形状对象上有一个isRound属性来区分是圆形还是正方形。有了这个,我们就可以创建一个div元素,它通过使用v-for指令来遍历data中的shapes数组。在我们决定哪个类应该在div元素上使用之前,我将把它写出来。

<div id="app">
    <div v-for="shape in shapes"></div>
</div>

注意:始终给div元素添加shape的类名。

<div id="app">
    <div v-for="shape in shapes" class="shape"></div>
</div>

假设shape有一个默认的样式:

.shape {
    width: 150px;
    height: 150px;
    margin: 10px; 
    background: #f36;
}

这个时候你看到的效果将是这样:

在Vue中使用样式

类似前面所讲的一样,同样可以使用v-bind绑定style那样来绑定class属性:

<div id="app">
    <div v-for="shape in shapes" class="shape" v-bind:class="{ }"></div>
</div>

现在,这个对象的语法在class属性的上下文中略有不同。对象的键应该匹配类名,而值应该是计算而尔值的表达式。如果布尔值为true,则添加类名,否而类名将不会添加到DOM中。因此,你可以向对象添加类,即使你不知道它们是否将在运行时添加。

我们现在要做的事情是,将有条件添加类名circle,因此我将输入circle作为对象的key。至于表达式,如果isRound属性在这个对象上是true,那么就给这个元素添加类名circle

<div id="app">
    <div v-for="shape in shapes" class="shape" v-bind:class="{ circle: shape.isRound }"></div>
</div>

因此,如果shape对象上的isRound属性为true时则会添加circle类。如果它是false,那么这个类就不会被添加到DOM中。

现在我们已经检查了shape是不是一个圆,但是我们也需要检查它是否是一个正方形,如果是这样,添加适当的类。我们对square类做同样的操作。

<div id="app">
    <div v-for="shape in shapes" class="shape" v-bind:class="{ circle: shape.isRound, square: !shape.isRound }"></div>
</div>

这样,每个div元素都将包含shape类名,并且会根据isRound的值对应的添加circle或者square类名。

我们可以根据样式来判断,第一个形状是圆,第二个形状是方形的。所以这一切看起来都很好。

很明显,这段代码在isRound属性上不太适合超过两个形状的时候,比如我们有三角形的时候。

假设预定好了CSS样式,所以我们只需要把两个类名分配到一个div,比如指定triangle和指定三角形方向的类名,它可以是updownrightleft。好,现在我们可以清楚地看到,isRound属性不是最好的,所以去掉它,添加一个更通用的属性。

我们现在可以假设shape属性的值将匹配给定形状的CSS类。那么如何将这个类应用到div元素呢?当我们提供一个对象作为类属性的绑定时,我们指定类名作为对象的键(key),但在这种情况下,我们需要更动态的东西。我们可以使用另一种诘未能来解决这个问题,它允许我们指定一个数组而不是一个对象。这允许我们指定一组表达式,其中每个表达式可以是字符串,也可以是数据属性的名称。

<div id="app">
    <div v-for="shape in shapes" v-bind:class="[  ]" class="shape"></div>
</div>

现在添加适当的类就像键入包含类的属性一样简单,在这种情况下,shape属性在shape的别名上。

<div id="app">
    <div v-for="shape in shapes" v-bind:class="[ shape.shape ]" class="shape"></div>
</div>

let app = new Vue({
    el: '#app',
    data () {
        return {
            shapes: [
                {
                    shape: 'circle'
                },
                {
                    shape: 'square'
                }
            ]
        }
    }
})

在Vue中使用样式

运行代码将显示圆形和正方形,正如上图所看到的效果。这一次以一种更动态的方式来实现的,看上去也比前面的示例更简单。目前为止一切都很顺利。现在让我们来添加三角形,因此我们需要向shapes数组中添加一些对象。三角形形状的类名不是我们想要的三角形,我们需要指定一个方向,可以是updownleftright。将给每个方向添加一个三角形。

let app = new Vue({
    el: '#app',
    data () {
        return {
            shapes: [
                {
                    shape: 'circle'
                },
                {
                    shape: 'square'
                },
                { 
                    shape: 'triangle', 
                    direction: 'up' 
                },
                { 
                    shape: 'triangle', 
                    direction: 'right' 
                },
                { 
                    shape: 'triangle', 
                    direction: 'down' 
                },
                { 
                    shape: 'triangle', 
                    direction: 'left' 
                }
            ]
        }
    }
})

运行上面的代码,并没有看到我们想要的三角形。对于要显示三角形,我们还需要向类中添加三角形方向的类名。但是,不是所有的形状都有方向,所以我们怎么才能动态地添加方向的类名呢?记住,数组语法允许我们添加表达式,因此可以添加一个简写if语句来检查当前形状是否有方向属性。因此,如果direction属性包含一个truthy值(也就是说不是未定义的),我们将把属性值添加为一个类,否则我们将添加一个空字符串。

<div id="app">
    <div v-for="shape in shapes" v-bind:class="[ shape.shape, shape.direction ? shape.direction : '' ]" class="shape"></div>
</div>

在Vue中使用样式

现在,我们看到了三角形在页面上渲染出来了。为了向你展示一些我们可以用数组语法做的事情,把示例的功能做得更强一些。假设我们要在加载页面时应用一个动画到某些形状上。

在CSS样式中我已经添加好了一个名为animate的类名来处理这个效果。现在需要做的就是把这个类添加到元素上,让这个形状动起来。首先需要知道哪些形状会有动画效果,所以在shapes对象中添加一个animate的布尔属性。

let app = new Vue({
    el: '#app',
    data () {
        return {
            shapes: [
                {
                    shape: 'circle'
                },
                {
                    shape: 'square'
                },
                { 
                    shape: 'triangle', 
                    direction: 'up' 
                },
                { 
                    shape: 'triangle', 
                    direction: 'right',
                    animate: true
                },
                { 
                    shape: 'triangle', 
                    direction: 'down' 
                },
                { 
                    shape: 'triangle', 
                    direction: 'left',
                    animate: true
                }
            ]
        }
    }
})

现在在datashapes数组里的对象上添加好了animate属性。现在我们要面对一个小问题。我们如何将animate类添加到shape上,这取决于animate属性的值是否为true。既然我们知道这个类的名称,我们可以使用另一个简写的if语句,但我并不想使用这种方法,我想向你展示一种更干净的方法。前面使用对象的时候,它允许我们基于布尔值来切换类。这种方法现在对我们很有用,而且庆幸的是,这也可以用在数组中使用。我们可以做的是,添加一个与前面看到的相同的语法的对象。因为我们想要切换animate类名,所以将使用它作为对象键,而值是shape别名上的animate属性,它包含一个布尔值。如果animate属性不存在,会视为false,将不会添加animate类名。

<div id="app">
    <div v-for="shape in shapes" v-bind:class="[ shape.shape, shape.direction ? shape.direction : '', { animate: shape.animate } ]" class="shape"></div>
</div>

当你现在运行代码时,你就可以看到三角形有对应的动画效果,因为animate类名被添加到了这些形状中。

正如你所看到的,数组语法提供了很多的灵活性,因为你可以混合字符中、数据属性和对象等。

Vue组件的样式

前面看到的是如何在Vue中添加行内样式和通过类名来控制样式。接下来简单的看看Vue组件的样式处理。

得益于Vue-loader,在Vue中可以使用类似于Web Component的组件化写法:

<template>
    <!-- 组件模板写在这里 -->
</template>
<script>
    // 组件逻辑相关代码写这里
</script>
<style>
    /* 组件样式写在这里 */
</style>

在大多数情况下,我们希望组件间定义的样式是相互隔离的。所以我们可以增加scoped标识。Vue-loader在编译的过程中会为组件每一个元素节点增加scoped作为属性,同时为所有样式类加上属性选择器scoped,从而达到隔离的效果。

如果我们是使用Vue-CLI构建Vue项目,其已经内置好了Sass和LESS这样的处理器的配置。如果我们需要的话直接下载两个模块就可以了,而Webpack它会根据lang属性自动用适当的加载器去处理。

如果需要使用Sass,则安装:

npm i node-sass --save-dev
npm i sass-loader --save-dev

如果需要使用LESS,则安装:

npm i less --save-dev
npm i less-loader --save-dev

在组件中写样式的时候,可以这样处理:

<style lang="sass" scoped>
    /* Sass 样式*/
</style>

<style lang="less" scoped>
    /* LESS 样式*/
</style>

有关于这方面更详细的介绍,我们可以在学习组件开发的时候再深入的了解。

Logo

前往低代码交流专区

更多推荐