1.计算属性-computed

  • 所谓的计算属性,就是拿着你Vue中原有的属性(data里面的)去加工,计算,生成的全新的属性。
    1. 定义:要用的属性不存在,要通过已有属性计算得来。
    1. 原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
    1. get函数什么时候执行?
    • (1).初次读取时会执行一次。
    • (2).当依赖的数据发生改变时会被再次调用。
    1. 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。(在开发者工具(Vue)当中可以直接观察到)
    1. 备注:
    • (1).计算属性最终会出现在vm上,直接读取使用即可。
    • (2).如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

代码例子:

   <script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

// 创建Vue实例
const vm = new Vue({
el : '#root',
data : {
firstname : '张',
lastname : '三'
},
// 计算属性(实际上计算属性没有真正的值,你的每一次调用,Vue都会给你现算的,算过一次存在缓存)
computed : {
fullName : {
// 一定要有get()且不能使用箭头函数(没有this指向)
//这里的get()就是Object.defineproperty,当数据被读取时调用
get(){//Vue把这里的get指向改成了 Vue实例对象 非常好的点
// console.log(this);//指向Vue实例对象
console.log('get被调用了!');
// 一定要有return
return this.firstname + '-' + this.lastname;
},
// set什么时候调用:当指向数据(fullName)被修改时
set(value){//比较少用,一般数据是只读取不修改的
console.log('接收的数据为:',value);
const arr = value.split('-');//字符串分割
this.firstname = arr[0];
this.lastname = arr[1];
}
}
},
methods : {
fullname(){//每一次你更改名字,这个函数都会调用一次
console.log(this);//指向的是Vue实例对象
return this.firstname + '-' + this.lastname
}
}
})
</script>

运行结果:

image
image

计算属性(computed)简写形式

<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三',
        },
        computed:{
            //完整写法
            /* fullName:{
                get(){
                    console.log('get被调用了')
                    return this.firstName + '-' + this.lastName
                },
                set(value){
                    console.log('set',value)
                    const arr = value.split('-')
                    this.firstName = arr[0]
                    this.lastName = arr[1]
                }
            } */
            //简写
            fullName(){
                console.log('get被调用了')
                return this.firstName + '-' + this.lastName
            }
        }
    })
</script>

运行结果(与完整版一致):

image

2.监视属性-watch

    1. 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
    1. 监视的属性必须存在,才能进行监视!!
    1. 监视的两种写法:
    • (1).new Vue时传入watch配置
    • (2).通过vm.$watch监视

代码解析:

<div id="root">
<h2>今天天气很{{weather}}</h2>
<!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
<!-- <button @click="isHot = !isHot">切换天气</button> -->
<button @click = 'changeWeather'>点击切换天气</button>      
</div>

<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
       
// Vue实例化
st vm = new Vue({
el : '#root',
data : {
    isHot : true//设置一个标志位,用于判断炎热还是凉爽
},
methods: {
    changeWeather(){
        this.isHot = !this.isHot
    }
},
computed : {
    weather(){//get的简写
       return this.isHot ? '炎热' : '凉爽'
    }
},
// 监视属性
watch : {
// 设置要监视的属性
isHot:{
        // immediate属性是watch属性里面自带的,用于初始化时让handler调用一下
             immediate : true,

             // 里面有这样一个函数 : handler
             //handler什么时候调用?当isHot发生改变时。
             handler(newValue,oldValue){
                 console.log('isHot被修改了',newValue,oldValue)
             }
        }
      }
  })

  // 同样可以这样写,(外部调用,当我们一开始不知道要监视哪一个属性时)
  vm.$watch('isHot',{
      immediate:true, //初始化时让handler调用一下
      //handler什么时候调用?当isHot发生改变时。
      handler(newValue,oldValue){
          console.log('isHot被修改了',newValue,oldValue)
      }
  })
</script>  

运行结果:

image
![image](../upload/Vue/V3/5 .png)

2.1 深度监视(deep)

  • (1).Vue中的watch默认不监测对象内部值的改变(一层)。
  • (2).配置deep:true可以监测对象内部值改变(多层,无论层级有多深)。
  • 备注:
    • (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
    • (2).使用watch时根据数据的具体结构,决定是否采用深度监视。

代码解析:

<!-- 准备好一个容器 -->
<div id="root">
    <h2>今天天气很{{weather}}</h2>
    <button @click = 'changeWeather'>点击切换天气</button><hr>
    <h2>a:{{number.a}}</h2>
    <!-- @xxx = '这里可以写一些简单的js语句' -->
    <button @click = 'number.a++'>点击切换天气</button><hr>
    <h2>b:{{number.b}}</h2>
    <button @click = 'number.b++'>点击切换天气</button><hr>      
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
       
    // Vue实例化
    const vm = new Vue({
        el : '#root',
        data : {
            isHot : true ,//设置一个标志位,用于判断炎热还是凉爽
            number : {
                a : 1 ,
                b : 1
            }
        },
        methods: {
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        computed : {
            weather(){//get的简写
               return this.isHot ? '炎热' : '凉爽'
            }
        },
        // 监视属性
        watch : {
            // 深度监视的应用
            number:{
                // 开启深度监测
                deep : true,

                // 里面有这样一个函数 : handler
                //handler什么时候调用?当number发生改变时。
                handler(newValue,oldValue){
                    console.log('number被修改了',newValue,oldValue)
                }
            }
        }
    })
</script>

运行结果:

  • 未开启深度监视
    image
  • 开启深度监视
    image

2.2 简写形式

  • 前提是你不使用 immediate属性 和 deep属性.
    const vm = new Vue({
                el:'#root',
                data:{
                    isHot:true,
                },
                computed:{
                    info(){
                        return this.isHot ? '炎热' : '凉爽'
                    }
                },
                methods: {
                    changeWeather(){
                        this.isHot = !this.isHot
                    }
                },
                watch:{
                    //正常写法
                    /* isHot:{
                        // immediate:true, //初始化时让handler调用一下
                        // deep:true,//深度监视
                        handler(newValue,oldValue){
                            console.log('isHot被修改了',newValue,oldValue)
                        }
                    }, */
                    //简写(前提是你不适用 immediate属性 和 deep属性)  
                    isHot(newValue,oldValue){
                        console.log('isHot被修改了',newValue,oldValue,this)
                    }
                }
            })

            //正常写法
            /* vm.$watch('isHot',{
                immediate:true, //初始化时让handler调用一下
                deep:true,//深度监视
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue)
                }
            }) */

            //简写(前提是你不适用 immediate属性 和 deep属性)
            vm.$watch('isHot',function(newValue,oldValue){//不能使用箭头函数
                console.log('isHot被修改了',newValue,oldValue)
            })

3.计算属性VS监听属性

  • 一般来将实现相同的功能,使用计算属性实现起来更为简单,但是计算属性里面却不能开启异步任务来维护数据,因为computed(计算属性是依靠返回值),但是监听属性却可以,因为watch不靠返回值,编辑者自己去修改代码来控制.
  • computed和watch之间的区别:
    • 1.computed能完成的功能,watch都可以完成。
    • 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
  • 两个重要的小原则:
    • 1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
    • 2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

例如:

  • 提一个需求:要求姓名延迟一秒显示到页面上(watch能做到,但是computed却做不到)
    watch:{
    firstName(val){
    // 这里的定时器一定要用箭头函数,因为它没有this指向,会向上找到firstName的this最终指向Vue实例,但是如果你用function的话,它会指向windows,但是windows里面没有fullName,这要会导致报错
        setTimeout(()=>{
            console.log(this)
            this.fullName = val + '-' + this.lastName
        },1000);
    },
    lastName(val){
        this.fullName = this.firstName + '-' + val
    }
    }

4.绑定 CSS 和 style 样式

  • 1. class样式
    • 写法:class=”xxx” xxx可以是字符串、对象、数组。
      • 字符串写法适用于:类名不确定,要动态获取。
      • 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
      • 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
  • 2. style样式
    • :style=”{fontSize: xxx}”其中xxx是动态值。
    • :style=”[a,b]”其中a、b是样式对象。

代码解析:

<style>
    .basic{
        width: 400px;
        height: 100px;
        border: 1px solid black;
    }
   
    .happy{
        border: 4px solid red;;
        background-color: rgba(255, 255, 0, 0.644);
        background: linear-gradient(30deg,yellow,pink,orange,yellow);
    }
    .sad{
        border: 4px dashed rgb(2, 197, 2);
        background-color: gray;
    }
    .normal{
        background-color: skyblue;
    }

    .wydx1{
        background-color: yellowgreen;
    }
    .wydx2{
        font-size: 30px;
        text-shadow:2px 2px 10px red;
    }
    .wydx3{
        border-radius: 20px;
    }
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
    <body>
    <!-- 准备好一个容器-->
    <div id="root">
            <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
            <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>

            <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
            <div class="basic" :class="classArr">{{name}}</div> <br/><br/>

            <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
            <div class="basic" :class="classObj">{{name}}</div> <br/><br/>

            <!-- 绑定style样式--对象写法 -->
            <div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
            <!-- 绑定style样式--数组写法 -->
            <div class="basic" :style="styleArr">{{name}}</div>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
       
        const vm = new Vue({
            el:'#root',
            data:{
                name:'五邑大学',
                mood:'normal',
                classArr:['wydx1','wydx2','wydx3'],
                classObj:{
                    wydx1:false,
                    wydx2:false,
                },
                styleObj:{
                    //这里的属性名要用驼峰命名法(font-size要变成fontSize)
                    fontSize: '40px',
                    color:'red',
                },
                styleObj2:{
                    // background-color 变成 backgroundColor
                    backgroundColor:'orange'
                },
                styleArr:[
                    {
                        fontSize: '40px',
                        color:'blue',
                    },
                    {
                        backgroundColor:'gray'
                    }
                ]
            },
            methods: {
                changeMood(){
                    const arr = ['happy','sad','normal']
                    const index = Math.floor(Math.random()*3)
                    this.mood = arr[index]
                }
            },
        })
    </script>