Vue 中的动态样式分为动态绑定 class 和动态绑定 style。

1. 动态绑定class

class样式的动态添加,分为以对象方式添加和以数组方式添加两种。

1.1 以对象方式添加

  • 语法

    {key它就是样式名称:布尔值【true生效,false不生效】}

  • 案例

    <style>
        .active {
            color: red;
        }
    </style>
    
    <div id="app">
        <!-- v-bind动态绑定的简写,表示动态绑定数据源中的titleClass -->
        <div :class="titleClass">我是一个标题</div>
        <button @click="addClass">添加样式</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {  
                // 可以添加多个样式,用逗号隔开
                titleClass: { active: false }
            },
            methods: {
                addClass() {
                    // 点击切换
                    this.titleClass.active = !this.titleClass.active
                }
            }
        })
    </script>
    

    在这里插入图片描述

    如果我们想要在触发点击事件的时候,动态的追加新的属性,该怎么做?

    我们一共有三种方案,分别是直接在点击事件中追加新属性、通过改变titleClass的地址来追加、通过 Vue 中的方法追加。

    我们先来看第一种方案,通过点击事件直接追加新属性:

    <style>
        .active {
            color: red;
        }
    
        .font30 {
            font-size: 30px;
        }
    </style>
    
    <div id="app">
        <!-- v-bind动态绑定的简写,表示动态绑定数据源中的titleClass -->
        <div :class="titleClass">我是一个标题</div>
        <button @click="addClass">添加样式</button>
    </div>
    
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                titleClass: { active: false },
                // titleStyle: []
            },
            methods: {
                addClass() {
                    this.titleClass.active = true//这里执行的时候会刷新数据,会顺带执行了下一句
                    this.titleClass.font30 = true//注意,把上一句注释,只执行这一句的时候,样式不会生效,因为这里是是新加的属性,并没有被劫持,不会被动态添加
                }
            }
        })
    </script>
    

    在这里插入图片描述

    注意,这种方案是有很大弊端的:

    addClass方法中,如果把this.titleClass.active = true这一句注释,直接执行它的下一句this.titleClass.font30 = true,则点击添加样式时,div 的样式不会发生任何改变。

    这是因为font30样式并没有被劫持(这个属性并没有写在数据源中),并不能动态地和 div 绑定,上述代码之所以能够成功执行该样式,是因为active样式和 div 是动态绑定的,当active的布尔值发生变化,引发视图更新时,会顺带追加font30的样式。所以当this.titleClass.active = true这一句注释,只执行它的下一句this.titleClass.font30 = true,虽然数据发生了改变,但因为该数据不是响应式的,不会引发视图更新,所以此时视图并不会发生改变。

    第二种方案:通过改变titleClass的地址来追加:

    <style>
        .active {
            color: red;
        }
    
        .font30 {
            font-size: 30px;
        }
    </style>
    <div id="app">
        <!-- v-bind动态绑定的简写,表示动态绑定数据源中的titleClass -->
        <div :class="titleClass">我是一个标题</div>
        <button @click="addClass">添加样式</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                titleClass: { active: false },
            },
            methods: {
                addClass() {
                    // 方法1:直接改变地址
                    // 改变地址,也会动态添加上字体属性
                    // this.titleClass = { ...this.titleClass, font30: true }
    
                    // 方法2:使用JSON.stringify和JSON.parse拷贝一个新对象出来
                    // 改变地址 JSON.stringify(this.titleClass):将某个对象转换成 JSON 字符串形式
                    // JSON.parse:将数据转换为 JavaScript 对象。
                    // let titleClass = JSON.parse(JSON.stringify(this.titleClass))
                    // titleClass.font30 = true
                    // this.titleClass = titleClass
    
    
                    // 方法3:使用Object.assign()方法
                    // Object.assign()是对象的静态方法,可以用来复制对象的可枚举属性到目标对象,第一次是深复制
                    this.titleClass = Object.assign({}, this.titleClass, { font30: true })
                }
            }
        })
    </script>
    

    在这里插入图片描述

    上面列举了三种通过改变地址达到追加新属性效果的方法,在这里着重说一下后两种方法。

    方法2,使用JSON.stringify和JSON.parse拷贝一个新对象出来的原理是这样的,如果我们有一个复杂的对象,想要复制到另外一处,就需要对该对象进行复制操作。因为 js 对象数据是引用数据类型。如果只是简单的使用=复制对象,会修改掉原来的对象(因为他们真是保存的数据是一个地址,两个变量都指向都一个地址)。

    所以如果想要真实拷贝一份对象数据,且不能影响原来对象,则可以将原对象进行JSON.stringify操作,将该对象转换为 json 字符串,然后再新定义一个对象,使用JSON.parse转换该 json 字符串为对象。这样我们新得到的对象就是一份和原对象无关联的对象了,可以任意使用而不会影响原对象。

    方法3,Object.assign()方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target )。

    文末附有参考文章链接,文章中较好地解释了这两种方法的实现原理。

    在 Vue2 中,动态地给一个对象增加属性太麻烦了,这是因为 Vue2 是使用Object.defineProperty方法进行数据劫持的。这种方法在初始化的时候就已经将数据源中的数据进行了劫持,而新增的属性没有被劫持。而而 Vue3 中就没有这个问题,Vue3 中劫持的是一个对象,我们只要给对象增加属性,视图就可以发生改变。

    由于上面的原因,Vue2 中提供了一种简便的方法,让我们能够动态地追加属性,就是$set方法。

    $set方法

    语法:

    this.$set(给哪个对象添加属性,添加什么属性,该属性的值是什么)

    案例:

    <style>
        .active {
            color: red;
        }
    
        .font30 {
            font-size: 30px;
        }
    </style>
    <div id="app">
        <!-- v-bind动态绑定的简写,表示动态绑定数据源中的titleClass -->
        <div :class="titleClass">我是一个标题</div>
        <button @click="addClass">添加样式</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                titleClass: { active: false },
            },
            methods: {
                addClass() {
                    // Vue方法
                    // 动态给对象添加成员属性(Vue中的方法)
                    this.$set(this.titleClass, 'font30', true)
                }
            }
        })
    </script>
    

    在这里插入图片描述

  • 小结

    从上面的案例中,我们可以看出使用动态绑定 Class 的方式添加动态样式时,这种用对象方式添加的方法一般用于开关显示的样式,不太适合添加新的属性样式。

    学习了动态绑定样式的方式后,我们可以将这种方式应用到 tab 切换当中。

1.2 tab 切换案例

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>vue学习使用</title>
        <script src="./js/vue.js"></script>
        <style>
            .active {
                color: red;
                transition: all 2s;
            }
        </style>
    </head>

    <body>
        <div id="app">
            <ul>
                <li @click="setNav('a')" :class="{active:a}">aaa</li>
                <li @click="setNav('b')" :class="{active:b}">bbb</li>
                <li @click="setNav('c')" :class="{active:c}">ccc</li>
            </ul>
            <ul>
                <li v-if="a">11111</li>
                <li v-if="b">22222</li>
                <li v-if="c">33333</li>
            </ul>
        </div>

        <script>
            const vm = new Vue({
                el: '#app',
                data: {
                    a: true,
                    b: false,
                    c: false
                },
                methods: {
                    setNav(attrName) {
                        this.a = false
                        this.b = false
                        this.c = false
                        this[attrName] = true
                    }
                }
            })
        </script>

    </body>

</html>

在这里插入图片描述

1.3 以数组方式添加

概述:

以数组方式添加 class 动态绑定,更适合追加新的属性。也就是说,一般对于追加新样式,我们使用数组方式进行动态绑定。

案例:

<style>
    .active {
        color: red;
    }

    .font30 {
        font-size: 30px;
    }
</style>

<div id="app">
    <!-- 
    数组:[元素样式名称]
    一般对于追加新样式,使用数组
    -->
    <div :class="titleStyle">我是一个标题</div>
    <button @click="addStyle">添加样式</button>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            // titleClass: { active: false },
            titleStyle: []
        },
        methods: {
            addStyle() {
                // 给数组添加元素,元素就是样式名称,这样它会就追加样式
                // push unshift shift pop splice sort reverse 调用时都会让视图更新
                this.titleStyle.push('active')
                this.titleStyle.push('font30')
            }
        }
    })
</script>

在这里插入图片描述

注意:在 Vue 中调用 push unshift shift pop splice sort reverse 时都会让视图更新。

2. 动态绑定style

动态绑定style,也分为以对象方式添加和以数组方式添加两种。

<div id="app">

    <!-- style样式的动态添加,对象和数组方式 -->

    <!-- 对象 -->
    <div :style="{color:'blue',fontSize:'30px'}">我是一个标题</div>

    <!-- 数组 -->
    <div :style="[{color:'red'},{fontSize:'30px'}]">我是一个标题</div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
        },
        methods: {
        }
    })
</script>

在这里插入图片描述


参考文章:

https://blog.csdn.net/reembarkation/article/details/125515876

https://blog.csdn.net/qq_30100043/article/details/53422657

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐