computed怎么使用_Vue-computed和watch

进阶属性预览

5c754f8deb0945870b06172ace085f75.png

options.data发生的事情:

  1. 会被Vue监听,每次data的读写都会被vue监控
  2. 会被Vue的实例监听(vm)代理
  3. vue会在data变化时更新UI

computed属性

需求一:展示用户信息,如果有名字,展示名字;没有名字,展示邮箱;没有邮箱,展示手机号。

代码:

new Vue({
  data() {
    return {
      user:{
        email:"xiequantai@qq.com",
        nickname:"啊谢",
        phone:"13812345678"
      }
    }
  },
  computed: {
    displayName(){
      const user=this.user
      return user.nickname || user.email || user.phone
    }
  },
  template:`
    <div>
       {{displayName}}
       <div>
         {{displayName}}
       </div>
    </div>
  `
}).$mount('#app')

displayName是属性名,可以将display改成对象的形式,用getter、setter(写成函数)读取、设置displayName的值:

new Vue({
  data() {
    return {
      user:{
        email:"xiequantai@qq.com",
        nickname:"啊谢",
        phone:"13812345678"
      }
    }
  },
  computed: {
    displayName:{
      get(){
        const user=this.user
      return user.nickname || user.email || user.phone
      },
      set(value){
          //用户传入一个value,将nick的值改成value
        this.user.nickname=value
      }
    }
  },
  template:`
    <div>
       {{displayName}}
       <div>
         {{displayName}}
         <button @click="add">set</button>
       </div>
    </div>
  `,
  methods: {
      //点击时,将计算属性改成"圆圆"
    add(){
      this.displayName="圆圆"
    }
  },
}).$mount('#app')

第二个需求:点击"男"按钮,展示男的;点击“女”,展示女的;点击“全部”,展示全部列表。首先,写出3个按钮,然后将用户的姓名、性别都展示出来。

//封装一个写入姓名、性别的函数
let id=0
const createUser=(name,gender)=>{
  id+=1
  return{
    id:id,
    name:name,
    gender:gender
  }
}

new Vue({
  data() {
    return {
      users:[
        createUser("方方","男"),
        createUser("圆圆","女"),
        createUser("lisa","女"),
        createUser("啊谢","男")
      ]
    }
  },
  template:`
  <div>
    <div>
      <button>全部</button>
      <button>男</button>
      <button>女</button>
    </div>
    <ul>
      //v-for语法,u是给users里面的每一项取个名字。
      <li v-for="(u,index) in users":key="index">{{u.name}} - {{u.gender}}</li>
    </ul>
  </div>
  `,
}).$mount("#app")

下一步是让按钮有效:使用computed。

//封装一个函数:导出用户的姓名、性别
let id = 0;
const createUser = (name, gender) => {
  id += 1;
  return { id: id, name: name, gender: gender };
};
new Vue({
  data() {
    return {
      users: [
        createUser("方方", "男"),
        createUser("圆圆", "女"),
        createUser("小新", "男"),
        createUser("小葵", "女")
      ],
      //提前声明一下,也可以写成gender:undefined。否则,后面有用set,会很麻烦
      gender: ""
    };
  },
  //计算属性
  computed: {
    displayUsers() {
      const hash = {
        male: "男",
        female: "女"
      };
      //users和gender从vm对象上拿到,函数返回值就可以不加this了(在displayUsers)
      const { users, gender } = this;
      if (gender === "") {
        return users;
      } else if (typeof gender === "string") {
        return users.filter(u => u.gender === hash[gender]);
      } else {
        throw new Error("gender 的值是意外的值");
      }
    }
  },
  methods: {
    setGender(string) {
      this.gender = string;
    }
  },

  template: `
    <div>
      <div>
      <button @click="setGender('') ">全部</button>
      <button @click="setGender('male')">男</button>
      <button @click="setGender('female')">女</button></div>
      <ul>
        <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
      </ul>
      
    </div>
  `
}).$mount("#app");

@click的用法

第一种—— v-on:click="fn"

第二种——@click="fn"

第三种——@click="fn(参数)"

第二步:不用computed怎么筛选

//封装一个函数:导出用户的姓名、性别
let id = 0;
const createUser = (name, gender) => {
  id += 1;
  return { id: id, name: name, gender: gender };
};

new Vue({
  data() {
    return {
      users: [
        createUser("方方", "男"),
        createUser("圆圆", "女"),
        createUser("小新", "男"),
        createUser("小葵", "女")
      ],
      //用来复制users里面数据的
      displayUsers: []
    };
  },
  //完成对users里面的复制
  created() {
    this.displayUsers = this.users;
  },
  methods: {
    showMale() {
      this.displayUsers = this.users.filter(u => u.gender === "男");
    },
    showFemale() {
      this.displayUsers = this.users.filter(u => u.gender === "女");
    },
    showAll() {
      this.displayUsers = this.users;
    }
  },

  template: `
    <div>
      <div>
      <button @click="showAll">全部</button>
      <button @click="showMale">男</button>
      <button @click="showFemale">女</button></div>
      <ul>
        <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
      </ul>
      
    </div>
  `
}).$mount("#app");

计算属性是有缓存的,属性如果没有改变,数据不会重新渲染。

watch属性

当数据变化时,就会执行一个函数。

例子一:撤销

new Vue({
  data:{
    n:0,
    history:[],
    //开始的撤销模式是关闭的
    inUndoMode:false
  },
  watch:{
      //观察n的变化
    n(newValue,oldValue){
      if(!this.inUndoMode){
        //如果撤销模式关闭的,
        this.history.push({from:oldValue,to:newValue})
      }
    }
  },
  template:`
     <div>
      {{n}}
      <hr/>
      <button @click="add1">+1</button>
      <button @click="add2">+2</button>
      <button @click="minus1">-1</button>
      <button @click="minus2">-2</button>
      <hr/>
      <button @click="undo">撤销</button>
      <hr/>
      {{history}}
     </div>
  `,
  methods: {
    add1(){
      this.n+=1
    },
    add2(){
      this.n+=2
    },
    minus1(){
      this.n-=1
    },
    minus2(){
      this.n-=2
    },
    undo(){
      //pop从数组中拿到最后一项,然后拿到最后一项的from值
      const last=this.history.pop()
      console.log("----")
      console.log(last)
      console.log("----")
      const old=last.from
      console.log("-----")
      console.log(old)

      //打开撤销状态
      this.inUndoMode=true
      //watch是异步的
      this.n=old
      //一会关闭撤销模式,相当于setTimeout(,0)
      this.$nextTick(()=>{
        this.inUndoMode=false
      },0)
    }
  },
}).$mount("#app")

设置撤销模式的原因是,让history不记录撤销的数组。watch是异步的,关闭撤销模式需要再次设置一个异步,this.$nextTick().

例子二:模拟computed

new Vue({
  data: {
    user: {
      email: "fangfang@qq.com",
      nickname: "方方",
      phone: "13812312312"
    },
    displayName:undefined
  },
  watch: {
      //观察user.email的变化
    "user.email": {
      handler:"changed",
      immediate: true // 第一次渲染是也触发 watch
    },
    "user.nickname": {
      handler: "changed",
      immediate: true // 第一次渲染是也触发 watch
    },
    "user.phone": {
      handler: "changed",
      immediate: true // 第一次渲染是也触发 watch
    }
  },
  template: `
    <div>
       {{displayName}}
       <!--点击时,触发user.nickname函数,使nickname为空-->
       <button @click="user.nickname=null">remove nickname</button>
    </div>
  `,
  methods: {
    changed() {
      console.log(arguments);
      const user = this.user;
      //由于vue默认undefined或者null不展示,所以展示邮箱
      this.displayName =  user.nickname ||user.email || user.phone;
    }
  }
}).$mount("#app");

小结

  • 我们给"user.email"绑定了一个handler方法,我们写的 watch 方法其实默认写的就是这个handler,Vue会去处理这个逻辑,最终编译出来其实就是这个handler,handler后面可以接变量,也可以接函数。

而immediate:true代表如果在 wacth 里声明了"user.email"之后,就会立即先去执行里面的handler方法。如果没有immediate或者immediate:false,第一次变化不会执行。

  • deep选项,deep:true,只监听一个对象就可以,不需要监听里面的所有属性。如果deep:flase,就只看对象表层的地址,如果对象里面的属性发生了变化,对象的地址不发生变化。
  • watch选项里面不能写箭头函数,因为箭头函数里面不能用this,里面的this指代window,而vue里面的每一个this都应该指代vm。
  • watch里面的各种写法:

第一种:key:function(newValue,oldValue){ }

第二种:key(newValue,oldValue){ }

第三种:key变化时,分别执行f1和f2,key:[ f1,f2 ]

第四种:

key:'methodsName',然后在methods里面写相关的方法

第五种:

key:{
   handle:fn,
   deep:true,
   immediate:true,
   'object.a':function(){}
   }

第六种:第五种写到外面的形式

vm.$watch(
    'n',//监听的东西
    function(){},
    {deep:true,
     immediate:true,
    }
)

computed和watch的区别

computed就是计算属性的意思,watch就是监听的意思。computed如果依赖属性不变,computed的值就不会重新计算,即根据依赖会产生缓存。watch的作用是,监听一个属性,如果发生变化了,就执行函数。watch有两个属性,第一个是immediate,如果是true,第一次渲染就会执行computed里面的函数;第二个是deep,如果是true,表示监听一个对象的同时,也要监听对象里面属性的变化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值