20230415----重返学习-vue计算属性-watch监听器-vue过滤器-vue生命周期

day-050-fifty-20230415-vue计算属性-watch监听器-vue过滤器-vue生命周期

vue计算属性

  • computed 计算属性
    1. 可以计算的属性,写法是函数,使用时当做属性来使用,即类似于data中的值

    2. 函数运算后的结果(return),就是计算属性的值

    3. 多个值改变,影响一个结果的时候

      • 即多个data中的响应式数据变化,返回一个新的响应式数据的场景
    4. 逻辑简单

    5. 计算属性要求在data里面没有同名的属性

    6. 计算有缓存

      • 如果依赖的变量没有变化,那么它的值就会一直被缓存起来
        • this.数据变量名中this后面的值没有发生变动时,它就不会重复进行计算。
    7. 值与结果

      • 大多数情况:多个值改变,影响一个结果的时候
      • 极少数情况:1个值变化,影响到多个结果
        • 也就是用全写形式,用计算属性的set方法反向计算出来源值
    8. 全写形式:是一个对象,用get函数与set函数,用于在计算属性被修改时调用set函数

      computed:{
          fullName(){//简写---get
              return this.firstName+"--"+this.lastName;
          }
      }
      
      • 相当于
      computed:{
          fullName:{//全写
              get(){
                  return this.firstName+"--"+this.lastName;
              },
          }
      }
      
      • 可扩展于在set中用于修改源头的data响应式属性
      computed:{
          fullName:{//全写
              get(){
                  return this.firstName+"--"+this.lastName;
              },
              set(newvalue){
                let arr=newvalue.split("--");
                this.firstName=arr[0];
                this.lastName=arr[1];
              }
          }
      }
      
DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  head>
  <body>
    
    <div id="app">
      <input type="text" v-model="firstName" />
      +
      <input type="text" v-model="lastName" />
      =
      <input type="text" v-model="fullName" />
    div>
    <script>
      var vm = new Vue({
        el: "#app",
        data: {
          firstName: "李",
          lastName: "丽丽",
        },
        computed: {
          // fullName(){//简写---get
          //    return this.firstName+"--"+this.lastName;
          // }
          fullName: {
            //全写
            get() {
              return this.firstName + "--" + this.lastName;
            },
            set(newvalue) {
              let arr = newvalue.split("--");
              this.firstName = arr[0];
              this.lastName = arr[1];
            },
          },
        },
      });
    script>
  body>
html>

购物车

DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      .box {
        box-sizing: border-box;
        margin: 0 auto;
        width: 480px;
        height: 590px;
        background-image: url(images/bg.png);
      }

      /* 按钮 */
      .minus,
      .add {
        display: inline-block;
        width: 52px;
        height: 44px;
        cursor: pointer;
        vertical-align: middle;
        background-image: url(images/sub.png);
      }

      .add {
        background-image: url(images/add.png);
      }

      /* 文本框 */
      .pronum,
      .info {
        box-sizing: border-box;
        width: 40px;
        height: 35px;
        line-height: 35px;
        background: white;
        border-radius: 3px;
        text-align: center;
        vertical-align: middle;
      }

      .pronum {
        display: inline-block;
      }

      /* 头部 */
      .top {
        padding: 50px 20px 0;
        height: 387px;
      }

      .hang {
        margin-bottom: 20px;
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
      }

      .hang .info {
        box-sizing: border-box;
        padding: 0 10px;
        width: 260px;
        color: white;
        font-size: 14px;
        text-align: left;
        line-height: 35px;
        background: #171818;
      }

      .bottom {
        padding-top: 20px;
        color: #878787;
        padding-left: 50px;
        line-height: 40px;
      }
    style>
  head>
  <body>
    <div id="app">
      <div class="box" id="computedBox">
        <div class="top">
          <div class="hang" v-for="item in list" :key="item.id">
            <i class="minus" @click="change(item.id,'minus')">i>
            <span class="pronum">{{item.count}}span>
            <i class="add" @click="change(item.id,'add')">i>
            <span class="info"
              >单价:{{item.price}}元   
              小计:<em>{{(item.count*item.price).toFixed(2)}}em>span
            >
          div>
        div>
        <div class="bottom">
          商品合计:<span class="pronum">{{all.allCount}}span>  <br />
          共花费了:<span class="pronum">{{all.allCountPrice}}span>  <br />
          最贵商品单价:<span class="pronum">{{all.highPrice}}span>  div>
      div>
    div>
    <script>
      var vm = new Vue({
        el: "#app",
        data: {
          list: [
            {
              id: 0,
              count: 2,
              price: 20,
            },
            {
              id: 1,
              count: 4,
              price: 14,
            },
            {
              id: 3,
              count: 0,
              price: 10,
            },
            {
              id: 4,
              count: 0,
              price: 16,
            },
            {
              id: 5,
              count: 0,
              price: 22,
            },
          ],
        },
        methods: {
          change(index, type) {
            //先找到,点击的那行数据
            let item = this.list.find((item) => item.id == index);
            //根据传递的参数,实现 加 减
            if (type == "minus") {
              //减
              if (item.count < 1) {
                item.count = 0;
                return;
              }
              item.count--;
            } else {
              //加
              item.count++;
            }
          },
        },
        computed: {
          // allCount(){
          //  // let result=this.list.reduce((res,item)=>{
          //     //     return res+item.count;
          //  // },0)

          //  let result=0;
          //  this.list.forEach((item)=>{
          //         result+=item.count;
          //  })
          //  return result;
          // },
          // allCountPrice(){
          //  let result=0;
          //  this.list.forEach((item)=>{
          //         result+=item.count*item.price;
          //  })
          //  return result;
          // },
          // highPrice(){
          //  let arr=[0];//初始值
          //  this.list.forEach((item)=>{
          //   if(item.count>0){
          //    arr.push(item.price);
          //   }
          //  })
          //  //如果是空数组,无法比大小,所以数组要设置初始值
          //  return Math.max(...arr);
          // },
          all() {
            let Cresult = 0;
            let Presult = 0;
            let arr = [0]; //初始值

            this.list.forEach((item) => {
              Cresult += item.count;
              Presult += item.count * item.price;
              if (item.count > 0) {
                arr.push(item.price);
              }
            });

            return {
              allCount: Cresult,
              allCountPrice: Presult,
              highPrice: Math.max(...arr),
            };
          },
        },
      });
    script>
  body>
html>

watch监听器

  • watch:监听器
    1. watch是一个对象,它内部具体要监听到的data响应式属性名的写法是函数

    2. 一个值变化,影响到多个结果

      • 也就是watch监听到的data响应式数据的值变化了,就会影响到其它值或方法的调用
    3. 逻辑介于 computed 和 methods 之间

      • 里面得出的结果一般比computed复杂,但比methods里的方法要来得简单
    4. 必须是data里面已有的

    5. 没有缓存

    6. 只有:一个值变化,影响到多个结果,无法反推

    7. 只有watch可以监控路由($route)

    8. 全写形式:是一个对象,用于watch监听器的具体属性

      • 之前的函数就写在handler属性里,可以用es的简写

        data: {
          fullName: "李-丽丽",
        },
        watch: {
          fullName(newValue,oldValue){//简写
            console.log(newValue,oldValue);
          }
        },
        
        watch: {
          fullName:{//全写,可以设置属性
              handler(newValue,oldValue){
                console.log(newValue,oldValue);
              },
          }
        },
        
      • immediate:true 是否打开页面就立刻监控1次

        data: {
          fullName: "李-丽丽",
        },
        watch: {
          fullName(newValue,oldValue){//简写
            console.log(newValue,oldValue);
          }
        },
        
        data: {
          fullName: "李-丽丽",
        },
        watch: {
          fullName:{//全写,可以设置属性
              handler(newValue,oldValue){
                console.log(newValue,oldValue);
              },
              immediate:true//打开页面,立刻监控1次
          }
        },
        
      • deep:true 是否深度监控,用于监控对象里面内容的变化

        data: {
          obj: {
            n: {
              a: 10,
            },
          },
        },
        watch: {
          obj(newValue, oldValue) {
            console.log(newValue, oldValue, "obj简写监控-不深层级");//只有obj.n变化时,不执行
          },
          "obj.n"(newValue, oldValue) {
            console.log(newValue, oldValue, "obj.n简写监控-不够深层级-只具体到对象");//只有obj.n变化时,不执行
          },
          "obj.n.a"(newValue, oldValue) {
            console.log(newValue, oldValue, "obj.n.a简写监控-深层级-具体到非对象值");//只有obj.n变化时,也执行
          },
        },
        
        data: {
          obj: {
            n: {
              a: 10,
            },
          },
        },
        watch: {
          obj: {
            handler(newValue, oldValue) {
              console.log(newValue, oldValue, "obj全写监控-深层级deep为true");//只有obj.n变化时,也执行
            },
            deep: true,//为true,就可以实现深度监听
          },
        },
        
        • 为true,就可以实现深度监听
    9. 如果要监听对象的某个具体属性,可以加引号

      watch: {
        "obj.n.a":{//全写,可以设置属性
            handler(newValue,oldValue){
                console.log(newValue,oldValue);
            }
        }
      
      },
      
DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  head>
  <body>
    <div id="app">
      <input type="text" v-model="firstName" />
      +
      <input type="text" v-model="lastName" />
      =
      <input type="text" v-model="fullName" />

      <input type="text" v-model.number="obj.n.a" />
    div>
    <script>
      var vm = new Vue({
        el: "#app",
        data: {
          firstName: "李",
          lastName: "丽丽",
          fullName: "李-丽丽",
          obj: {
            n: {
              a: 10,
            },
          },
        },
        watch: {
          // fullName(newValue,oldValue){//简写
          //   //console.log(newValue,oldValue);
          //   let arr=newValue.split("-");
          //   this.firstName=arr[0];
          //   this.lastName=arr[1];
          // }
          // fullName:{//全写,可以设置属性
          //     handler(newValue,oldValue){
          //         console.log("111");
          //        let arr=newValue.split("-");
          //        this.firstName=arr[0];
          //        this.lastName=arr[1];
          //     },
          //     immediate:true//打开页面,立刻监控1次
          // }

          // obj:{//全写,可以设置属性
          //     handler(newValue,oldValue){
          //         console.log(newValue,oldValue);
          //     },
          //     deep:true//默认 无法深度监控,对象里面内容的变化
          //     //为true,就可以实现深度监听
          // }

          //复杂内容监控的时候,必须加引号
          // "obj.n.a": {
          //   //全写,可以设置属性
          //   handler(newValue, oldValue) {
          //     console.log(newValue, oldValue);
          //   },
          // },

          obj(newValue, oldValue) {
            console.log(newValue, oldValue, "obj简写监控-不深层级");//不执行
          },
          "obj.n"(newValue, oldValue) {
            console.log(newValue, oldValue, "obj.n简写监控-不够深层级-只具体到对象");//不执行
          },
          "obj.n.a"(newValue, oldValue) {
            console.log(newValue, oldValue, "obj.n.a简写监控-深层级-具体到非对象值");//执行
          },
          obj: {
            handler(newValue, oldValue) {
              console.log(newValue, oldValue, "obj全写监控-深层级deep为true");//执行
            },
            deep: true,//为true,就可以实现深度监听
          },
        },
      });
    script>
  body>
html>

watch与computed和methods之间的对比

  1. computed(多个值变化,影响到一个结果) 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。他虽然是函数但主要当作属性来使用,逻辑简单。
  2. methods方法表示一个具体的操作,主要书写业务逻辑,是函数并且以函数的方式来调用。
  3. watch(一个值变化,影响到多个结果改变)一个对象,键是需要观察的表达式,值是对应回调函数。
    • 主要用来监听某些特定数据的变化(watch监控路由对象‘$route’),从而进行某些具体的业务逻辑操作;
      • 以及在对应数据变化进而触发函数时,在内部调用异步函数。
    • 可以看作是computedmethods的结合体;
  • computed是属性调用,而methods是函数调用
  • computed带有缓存功能,而methods不是
  • computed可以监控对象,而methods不是
  • watch可以监控对象,而methods不是
    • watch和computed均可以监控程序员想要监控的对象,当这些对象发生改变之后,可以触发回调函数做一些逻辑处理。
      • watch监控自身属性变化(重新编译,性能差),只要调用就会调用回调。 vm.$watch()

      • watch监控路由对象(一个值变化,影响到多个结果改变),数据变化时来执行异步操作,这时watch是非常有用的。

      • 计算属性computed的特点(多个值变化,影响到一个结果)

        • 计算属性会依赖于他使用的data中的属性,
        • 只要是依赖的属性值有改变,则自动重新调用一下计算属性;
          • 如果他所依赖的这些属性值没有发生改变,那么计算属性的值是从缓存中来的,而不是重新编译,那么性能要高一些,所以vue中尽可能使用computed替代watch。
DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  head>
  <body>
    <div id="app">
      <p>num1: {{num1}}p>
      <p>num2: {{num2}}p>
      <p>num3: {{num3}}p>
      <p>num1AddNum2Methods: {{num1AddNum2Methods()}}p>
      <p>num1AddNum2Computed: {{num1AddNum2Computed}}p>
      <p>num1AddNum2Watch: {{num1AddNum2Watch}}p>

      <button v-on:click="num1++">num1++button>
      <button v-on:click="num2++">num2++button>
      <button v-on:click="num3++">num3++button>
    div>
    <script>
      let vm = new Vue({
        el: "#app",
        data: {
          num1: 1,
          num2: 2,
          num3: 88,
          num1AddNum2Watch: 0,
        },
        computed: {
          num1AddNum2Computed() {
            console.log("num1AddNum2Computed-computed计算属性,依赖的值变动才调用一次");
            return this.num1 + this.num2;
          },
        },
        watch: {
          num1: {
            handler(value) {
              console.log("num1AddNum2Watch-num1-watch回调函数,监听的值变动就调用一次");
              this.num1AddNum2Watch = this.num1 + this.num2;
            },
            immediate: true, //打开页面,立刻监控1次
          },
          num2: {
            handler(value) {
              console.log("num1AddNum2Watch-num2-watch回调函数,监听的值变动就调用一次");
              this.num1AddNum2Watch = this.num1 + this.num2;
            },
            immediate: true, //打开页面,立刻监控1次
          },
        },
        methods: {
          num1AddNum2Methods() {
            //每次更新页面的时候就会执行
            console.log("num1AddNum2Methods-methods函数,页面刷新时就会触发");
            return this.num1 + this.num2;
          },
        },
      });
    script>
  body>
html>

vue过滤器

  • 过滤器使用场景:对数据进行统一处理,得到一个统一规范的结果

    • 第一个形参就是要进行过滤处理的数据

    • 第二及后面的形参,就是过滤器要传的参数

    • return 过滤器的新结果

      filters: {
        //局部过滤器
        currency(val, a = "¥", b = 2) {
          //val:过滤处理的数据
          //a:过滤器函数调用传递的第一个参数
          //b:过滤器函数调用传递的第二个参数
          return a + val.toFixed(b);
        },
      },
      
    • 可以使用过滤器的是 {{}} 和 v-bind,其余的指令基本都不可以

      {{msg|capitalize}}
      

      111

  • 过滤器使用的方式为在值后面用|接上过滤器名称及传参

    {{n|currency}} 
    {{m|currency("$",3)}}
    
  • 可以给过滤器传参

    {{m|currency("$",3)}}
    
    DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <title>title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
      head>
      <body>
        <div id="app">
          {{n|currency}} {{m|currency("$",3)}} 
        <script>
    
          var vm = new Vue({
            el: "#app",
            data: {
              n: 100,
              m: 200,
              msg: "hello",
            },
            filters: {
              //局部过滤器
              currency(val, a = "¥", b = 2) {
                //val:过滤处理的数据
                //a:过滤器函数调用传递的第一个参数
                //b:过滤器函数调用传递的第二个参数
                return a + val.toFixed(b);
              },
            },
          });
        script>
      body>
    html>
    
  • 全局过滤器与局部过滤器

    • 全局过滤器,项目中常用的方式。建议用全局函数代替。

      Vue.filter("capitalize",function(val){//全局过滤器
        let startNum=val.slice(0,1).toUpperCase();
        let endNum=val.slice(1);
        return startNum+endNum;
      })
      
    • 局部过滤器,只能在当前配置的vue实例中使用。

      var vm = new Vue({
        el: "#app",
        filters: {
          //局部过滤器
          currency(val, a = "¥", b = 2) {
            //val:过滤处理的数据
            //a:过滤器函数调用传递的第一个参数
            //b:过滤器函数调用传递的第二个参数
            return a + val.toFixed(b);
          },
        },
      });
      
DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  head>
  <body>
    <div id="app">
      {{n|currency}} {{m|currency("$",3)}}
      
      {{msg|capitalize}}
      <h1 :title="msg|capitalize">111h1>
    div>

    <div class="appa">
      {{nn|currency}} {{mm|currency("$",3)}} {{msga|capitalize}}
    div>

    <script>
      Vue.filter("capitalize", function (val) {
        //全局过滤器
        let startNum = val.slice(0, 1).toUpperCase();
        let endNum = val.slice(1);
        return startNum + endNum;
      });

      var vm = new Vue({
        el: "#app",
        data: {
          n: 100,
          m: 200,
          msg: "hello",
        },
        filters: {
          //局部过滤器
          currency(val, a = "¥", b = 2) {
            //val:过滤处理的数据
            //a:过滤器函数调用传递的第一个参数
            //b:过滤器函数调用传递的第二个参数
            return a + val.toFixed(b);
          },
        },
      });

      var vma = new Vue({
        el: ".appa",
        data: {
          nn: 101,
          mm: 202,
          msga: "world",
        },
      });
    script>
  body>
html>

vue生命周期

  • 生命周期(钩子函数):
    1. 初始化阶段
      • beforeCreate:初始化之前,组件实例刚被创建,什么也没有,只有默认的生命周期和事件。
        • 默认的事件就是实例事件,如当前vue实例的
      • created:初始化之后,组件实例创建完成,初始化了 data 和 methods都赋值了, 有了el,但是没有赋值(一般用于发送ajax)
    2. 模板编译
      • beforeMount:模板编译之前,已经存在 虚拟DOM了,el这个时候赋值了,并没有渲染到页面上
      • mounted:模板编译之后, 虚拟DOM转化为真实DOM,并且渲染页面上
    3. 更新阶段(data 的数据修改的时候,会触发)
      • beforeUpdate:数据更新了,但是页面没有更新
      • updated:数据更新了,并且页面也更新了
    4. 销毁阶段(触发销毁 vm.$destory())
      • beforeDestroy :销毁之前,所有的功能和数据,methods 等,都可使用
      • destroyed:销毁之后,所有的都解除绑定,功能和属性,methods都无法使用,保持原来的样式,不在受vue的控制
    • 激活时
      • activated: keep-alive,组件被激活时
      • deactivated: keep-alive,组件被激活完成
DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  head>
  <body>
    <div id="app">
      <div>msg: {{msg}}div>
      <div>obj: {{obj}}div>
      <div>number: {{number}}div>
      <button @click="handleAdd">组件内number++button>
    div>
  body>

  <button id="addNumber">组件外number++button>
  <button id="handleDestroy">卸载vue组件button>
html>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
  let vm = new Vue({
    name: "componentName",
    el: "#app",
    data: {
      msg: "data-msg-李",
      obj: {
        name: "lili",
      },
      number: 5,
    },
    methods: {
      handleAdd() {
        console.log(`vue实例内部this-->`, this.number, this);
        this.number++;
      },
    },
    beforeCreate() {
      console.log("初始化前beforeCreate: ", this, this.$attrs, [
        this.$nextTick,
        this.$emit,
        this.$slots,
      ]); //已经可以访问this及它的一些实例方法如$nextTick及$attrs等了,但this里面的数据和方法还不能访问;
      // debugger;

      // console.log("beforeCreate---this.$el: ", this.$el); //还没生成,也没赋值;
      // console.log("beforeCreate---this.$data: ", this.$data); //还没生成,也没赋值;
      // console.log("beforeCreate---this.msg: ", this.msg); //还没生成,也没赋值;

      // 一般这个阶段用不着,一般也就不与模板有数据的ajax时用到,如统计类ajax、数据埋点、单纯地操作全局变量之类的。
      //this.obj["ageb"]=182;//报错
    },
    created() {
      console.log("初始化后created: ", this.$el); //已经生成,也没赋值;
      // console.log("created: ", this.$data); //已经生成,已经赋值;
      console.log("created: ", this.msg); //已经生成,已经赋值;
      // 一般用于发送与页面相关的ajax。

      this.obj["createdAge"] = 2;
    },
    beforeMount() {
      console.log("挂载前beforeMount: ", this.$el); //已经生成,就是el对应的模版变成了虚拟DOM对象了,已经赋值,但没把模版替换到页面上;
      this.obj["beforeMountAge"] = 3;
    },
    mounted() {
      console.log("挂载后mounted: ", this.$el);
      this.obj["mountedAge"] = 4;
    },
    beforeUpdate() {
      console.log("更新前beforeUpdate: ", this.number, this.$el.innerHTML);
    },
    updated() {
      console.log("更新后updated: ", this.number, this.$el.innerHTML);
    },
    beforeDestroy() {
      console.log("卸载前beforeDestroy: ", this.number);
    },
    destroyed() {
      console.log("卸载后destroyed: ", this.number, this.number);
    },
  });

  let addNumber = document.querySelector("#addNumber");
  addNumber.onclick = function () {
    // vm.number++;
    vm.handleAdd()
    console.log(`vue实例外部vm.number-->`, vm.number, vm);
  };
  let handleDestroy = document.querySelector("#handleDestroy");
  handleDestroy.onclick = function () {
    vm.$destroy();
  };
script>

进阶参考

  1. 前端框架Vue中methods,computed,watch的调用时机的理解

你可能感兴趣的:(重返学习,前端,javascript,vue.js,学习)