7.1.效果

在姓和名中输入任何值,全名也跟着变
image.png

7.2.插值语法实现

使用插值语法虽然可以实现效果,但如果有个需求,姓文本框输入的内容过多,在全名里做截图前三位显示,把插值{{firstName}}-{{lastName}}改成{{firstName.slice(0,3)}}-{{lastName}}就可以进行截取,但不建议这样做,{{}}里的内容要尽量保证简单性,因为要考虑到以后业务逻辑的复杂性

代码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>姓名案例_插值语法实现</title>
  6. <!-- 引入Vue -->
  7. <script type="text/javascript" src="../js/vue.js"></script>
  8. </head>
  9. <body>
  10. <!-- 准备好一个容器-->
  11. <div id="root">
  12. 姓:<input type="text" v-model="firstName"> <br/><br/>
  13. 名:<input type="text" v-model="lastName"> <br/><br/>
  14. 全名:<span>{{firstName}}-{{lastName}}</span>
  15. </div>
  16. </body>
  17. <script type="text/javascript">
  18. Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
  19. new Vue({
  20. el:'#root',
  21. data:{
  22. firstName:'张',
  23. lastName:'三'
  24. }
  25. })
  26. </script>
  27. </html>

7.3.methods 实现

{{fullName()}}表示调取funllName()方法的返回值,填充到标签中。
{{fullName}}表示将fullName的属性值填充到标签中。
问题:data中的任何一个数据发生变化时,Vue 的模板都会重新解析一边,每解析一次fullName()方法就会调用一次,也就是firstNamelastName所在的文本框每输入或者删除一个值就会触发一次fullName()方法的调用。这样会导致效率不高

代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>姓名案例_methods实现</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            姓:<input type="text" v-model="firstName"> <br/><br/>
            名:<input type="text" v-model="lastName"> <br/><br/>
            全名:<span>{{fullName()}}</span>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
        new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            methods: {
                fullName(){
                    console.log('@---fullName')
                    return this.firstName + '-' + this.lastName
                }
            },
        })
    </script>
</html>

7.4.计算属性实现

  1. 要显示的数据不存在,要通过计算得来。
  2. computed对象中定义计算属性
  3. 在页面中使用{{方法名}}来显示计算的结果。

计算属性是获取已赋值的属性进行加工和计算再生成一个新属性
在 Vue 中计算属性的配置项是computed

1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的gettersetter
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.set函数在数据发生改变的时候执行
5.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
6.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

代码

下面代码中,页面虽然会多次调用fullNameget()只会初始化一次,然后把值缓存起来,后面再次调用fullName读取就是缓存里的值,只有get()里面的值被修改的时候,fullName才会进行更新,例如下面代码中的x属性改变的时候不会引起get()的调用。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>姓名案例_计算属性实现</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            姓:<input type="text" v-model="firstName"> <br/><br/>
            名:<input type="text" v-model="lastName"> <br/><br/>
            测试:<input type="text" v-model="x"> <br/><br/>

            全名:<span>{{fullName}}</span> <br/><br/>
            <!-- 全名:<span>{{fullName}}</span> <br/><br/>
            全名:<span>{{fullName}}</span> <br/><br/>
            全名:<span>{{fullName}}</span> -->
        </div>
    </body>

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

        const vm = new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三',
                x:'你好'
            },
            methods: {
                demo(){

                }
            },
            computed:{
                fullName:{
                    //get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                    //get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
                    get(){
                        console.log('get被调用了')
                        // console.log(this) //此处的this是vm
                        return this.firstName + '-' + this.lastName
                    },
                    //set什么时候调用? 当fullName被修改时。
                    set(value){
                        console.log('set',value)
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
            }
        })
    </script>
</html>

计算属性简写

只有computed里的属性只考虑读取,不考虑修改的情况下才能使用简写形式。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>姓名案例_计算属性实现</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            姓:<input type="text" v-model="firstName"> <br/><br/>
            名:<input type="text" v-model="lastName"> <br/><br/>
            全名:<span>{{fullName}}</span> <br/><br/>
        </div>
    </body>

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

7.5. 侦听属性-watch

效果:

image.png

代码演示

实现方式一:用普通方法实现值的改变

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>天气案例</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h2>今天天气很{{info}}</h2>
            <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
            <!-- <button @click="isHot = !isHot">切换天气</button> -->
            <button @click="changeWeather">切换天气</button>
        </div>
    </body>

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


        const vm = new Vue({
            el:'#root',
            data:{
                isHot:true,
            },
            computed:{
                info(){
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                changeWeather(){
                    this.isHot = !this.isHot
                }
            },
        })
    </script>
</html>

侦听属性

watch监视属性

  1. 当被侦听的属性变化时,回调函数自动调用,进行相关操作
  2. 侦听的属性必须存在,才能进行侦听,既可以侦听data,也可以侦听计算属性
  3. 配置项属性**immediate:false**,改为 true,则初始化时调用一次 **handler(newValue,oldValue)**
  4. 侦听有两种写法
    1. 创建 Vue 时传入**watch: {}**配置。
      1. 使用场景:侦听目标很明确的情况下可以定义Vue对象的时候就侦听
    2. 通过Vue对象调用** vm.$watch() **进行监视。
      1. 使用场景:在定义Vue对象的时候无法知道我要侦听的目标,要根据具体业务进行调用的情况下使用。

        代码演示

        实现方式二:用侦听属性watch
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>天气案例_侦听属性</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h2>今天天气很{{info}}</h2>
            <button @click="changeWeather">切换天气</button>
        </div>
    </body>

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

        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调用一下
                    //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>
</html>

深度侦听

  1. Vue中的watch默认不监测对象内部值的改变(一层)。
  2. 配置deep:true可以监测对象内部值改变(多层)。

备注:

  1. Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
  2. 使用watch时根据数据的具体结构,决定是否采用深度侦听。

    代码演示

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="UTF-8" />
         <title>天气案例_深度侦听</title>
         <!-- 引入Vue -->
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <!-- 准备好一个容器-->
         <div id="root">
             <h2>今天天气很{{info}}</h2>
             <button @click="changeWeather">切换天气</button>
             <hr/>
             <h3>a的值是:{{numbers.a}}</h3>
             <button @click="numbers.a++">点我让a+1</button>
             <h3>b的值是:{{numbers.b}}</h3>
             <button @click="numbers.b++">点我让b+1</button>
             <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>
             {{numbers.c.d.e}}
         </div>
     </body>
    
     <script type="text/javascript">
         Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    
         const vm = new Vue({
             el:'#root',
             data:{
                 isHot:true,
                 numbers:{
                     a:1,
                     b:1,
                     c:{
                         d:{
                             e:100
                         }
                     }
                 }
             },
             computed:{
                 info(){
                     return this.isHot ? '炎热' : '凉爽'
                 }
             },
             methods: {
                 changeWeather(){
                     this.isHot = !this.isHot
                 }
             },
             watch:{
                 isHot:{
                     // immediate:true, //初始化时让handler调用一下
                     //handler什么时候调用?当isHot发生改变时。
                     handler(newValue,oldValue){
                         console.log('isHot被修改了',newValue,oldValue)
                     }
                 },
                 //侦听多级结构中某个属性的变化
                 /* 'numbers.a':{
                     handler(){
                         console.log('a被改变了')
                     }
                 } */
                 //侦听多级结构中所有属性的变化
                 numbers:{
                     deep:true,
                     handler(){
                         console.log('numbers改变了')
                     }
                 }
             }
         })
    
     </script>
    </html>
    

    侦听属性_简写

    简写使用场景:如果侦听属性除了handler没有其他配置项的话,可以进行简写

    代码演示

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="UTF-8" />
         <title>天气案例_监视属性_简写</title>
         <!-- 引入Vue -->
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <!-- 准备好一个容器-->
         <div id="root">
             <h2>今天天气很{{info}}</h2>
             <button @click="changeWeather">切换天气</button>
         </div>
     </body>
    
     <script type="text/javascript">
         Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    
         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)
                     }
                 }, */
                 //简写
                 /* 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)
             }
         }) */
    
         //简写
         /* vm.$watch('isHot',function(newValue,oldValue){
             console.log('isHot被修改了',newValue,oldValue,this)
         }) */
    
     </script>
    </html>
    

    计算属性 VS 侦听属性

    computedwatch之间的区别

  • computed能完成的功能,watch都可以完成
  • watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作

两个重要的小原则

  • 所有被Vue管理的函数,最好写成普通函数,这样 this的指向才是vm或组件实例对象
  • 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样 this的指向才是vm或组件实例对象

    代码演示

    使用计算属性

    new Vue({
      el:'#root', 
      data:{ 
          firstName:'张',
          lastName:'三'
      },
      computed:{
          fullName(){
              return this.firstName + '-' + this.lastName
          }
      }
    })
    

    使用监听属性

    使用侦听属性,可以针对单个属性进行异步处理,比如延迟加载

    <!DOCTYPE html>
    <html>
      <head>
          <meta charset="UTF-8" />
          <title>姓名案例_watch实现</title>
          <!-- 引入Vue -->
          <script type="text/javascript" src="../js/vue.js"></script>
      </head>
      <body>
          <!-- 准备好一个容器-->
          <div id="root">
              姓:<input type="text" v-model="firstName"> <br/><br/>
              名:<input type="text" v-model="lastName"> <br/><br/>
              全名:<span>{{fullName}}</span> <br/><br/>
          </div>
      </body>
    
      <script type="text/javascript">
          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    
          const vm = new Vue({
              el:'#root',
              data:{
                  firstName:'张',
                  lastName:'三',
                  fullName:'张-三'
              },
              watch:{
                  firstName(val){
            //箭头函数代码块里没有this,this.fullName中的this它会往自己的父级找
            //setTimeout的父级就是vm,所以这里的this就是vm
                      setTimeout(()=>{
                          console.log(this)
                          this.fullName = val + '-' + this.lastName
                      },1000);
                  },
                  lastName(val){
                      this.fullName = this.firstName + '-' + val
                  }
              }
          })
      </script>
    </html>