vue2的普通监听、首次监听、深度监听、路由监听、销毁监听、计算属性、过滤器

2,038 阅读3分钟

一. 前言

  • 监听器的我们一般是采用watch作为方法进行使用。

  • watch监听器的作用是为了满足开发者对数据能够时时获取其变化,从而对数据的变化进行操作

  • 注意watch的位置是和name,data,methods等同级的

二. 普通监听

  • 直接在watch中使用变量名做为方法名,两个默认参数,分别为新值/旧值
<template>
  <div class='box'>
    {{ num }}
    <button @click="num++">自増++</button>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      num: 1,
    };
  },
  methods: {},
  created() { },
  computed: {},
  components: {},
  watch: {
    num(nVal, oVal) {
      console.log(nVal, oVal);  // 2 1
    },
  }
};
</script>
<style lang='scss' scoped></style>

二. 首次监听

  • immediate是能够保证在刚进入界面的时候便开始进行监听
  • 如果没有添加这个事项的话是无法在刚进入页面的时候就触发监听事件。
<template>
  <div class='box'>
    <!-- {{ num }}
    <button @click="num++">按钮</button> -->
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      num: 1,
    };
  },
  methods: {},
  created() { },
  computed: {},
  components: {},
  watch: {
    //调用对象格式的监听器
    num: {
      //侦听器的处理函数
      handler(nVal, oVal) {
        console.log(nVal, oVal);  // 1 undefined
      },
      //表示一进入界面就立即触发一次监听事件,false是默认值
      immediate: true
    }
  }
};
</script>
<style lang='scss' scoped></style>

三. 深度监听

深度监听用deep属性实现 , deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,修改里面任何一个属性都会触发这个监听器里的 handler。

  • 这里我们只推荐最优方案,就是优化深度监听

优化深度监听

我们可以是使用字符串形式监听。这样Vue.js才会一层一层解析下去,直到遇到该属性,然后才给它设置监听函数。

<template>
  <div class='box'>
    {{ obj.a.a1 }}
    <button @click="obj.a.a1 += 10">按钮</button>
    <input type="text" v-model="obj.a.a1">
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      obj: {
        a: {
          a1:10
        }
      }
    };
  },
  methods: {},
  created() { },
  computed: {},
  components: {},
  watch: {
    //调用对象格式的监听器
    'obj.a.a1': {
      //侦听器的处理函数
      handler(nVal, oVal) {
        console.log(nVal, oVal);  // 10 undefined
      },
      //表示一进入界面就立即触发一次监听事件,false是默认值
      immediate: true, 
      // 开启深度监听
      deep: true
    }
  }
};
</script>
<style lang='scss' scoped></style>

四. 路由监听

在开发vue项目的过程中,经常会对某些页面或全局项目的路由进行监听,当路由发生变化的时候去执行某些操作,下面是对监听路由的简单概括

watch: {
    '$route': { // $route可以用引号,也可以不用引号
      handler(to, from) {
       console.log(to, from);
      },
      deep: true, // 深度监听
      immediate: true, // 第一次初始化渲染就可以监听到
    }
  }
  • 第一个参数要去的路由信息(如果首次则为当前路由信息),第二个参数为从何而来

image.png

五. 销毁监听

为什么要注销 watch?因为我们的组件是经常要被销毁的,比如我们跳一个路由,从一个页面跳到另外一个页面,那么原来的页面的 watch 其实就没用了,这时候我们应该注销掉原来页面的 watch 的,不然的话可能会导致内置溢出。好在我们平时 watch 都是写在组件的选项中的,他会随着组件的销毁而销毁。

但是,如果我们使用下面这样的方式写 watch,那么就要手动注销了,这种注销其实也很简单,app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就可以了。

const unWatch = app.$watch('text', (newVal, oldVal) => {
  console.log(`${newVal} : ${oldVal}`);
})
 
unWatch(); // 手动注销watch

六. 计算属性

  • 在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。
  • 计算属性还可以依赖多个Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新。
  • 通过下面的小案例,可以了解一下计算属性的使用
<template>
  <div class='box'>
    <!-- 展示单价 -->
    <div class="price">单价: {{ price }}</div>
    <!-- 数量--按钮 -->
    <button class="sub" @click="num != 0 ? num-- : num = 0">数量--</button>
    <!-- 数量++按钮 -->
    <button class="add" @click="num != 10 ? num++ : num = 10">数量++</button>
    <!-- 展示总价 -->
    <div class="total">合计: {{ getTotal }}</div>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      price: 10,
      num: 0
    };
  },
  methods: {},
  created() { },
  computed: {
    getTotal() {
      let total = 0
      total = this.num * this.price
      return total
    }
  },
  components: {},
  watch: {}
};
</script>
<style lang='scss' scoped></style>

七. filters过滤器

  • 过滤器提供给我们的一种数据处理方式。
  • 过滤器功能不是必须要使用的,因为它所实现的功能也能用计算属性或者函数调用的方式来实现。
  • 例如现在有一个数组 内容不方便直接在页面 {{ }} 中进行修改 这时候就可以使用filters

局部过滤器

  • 只能在当前页面使用
<template>
  <div class='box'>
    在插值表达式中 使用 ___值 | 过滤器___  进行过滤
    <div class="price" v-for="item, i in priceArr" :key="i">单价: {{ item | reviseCont
    }}</div>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      priceArr: [822, 998, 660, 99, 35, 789, 56]
    };
  },
  methods: {},
  created() { },
  computed: {
    getTotal() {
      let total = 0
      total = this.num * this.price
      return total
    }
  },
  components: {},
  watch: {},
  filters: {
    reviseCont(val) {
      return '$' + val
    }
  }
};
</script>
<style lang='scss' scoped>
.price {
  width: 200px;
  border: 1px solid #ccc;
  padding: 10px;
}
</style>
  • 效果如下:

image.png

全局过滤器

  • 可以在项目任意位置使用
  • main.js定义全局过滤器
Vue.filter('filterAll',(val)=>{
  return val+'元'
})
  • 页面直接引用
<template>
  <div class='box'>
     <div class="price" v-for="item, index  in priceArr" :key="index">单价: {{ item | filterAll
    }}</div>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      priceArr: [822, 998, 660, 99, 35, 789, 56]
    };
  },
  methods: {},
  created() { },
  computed: {
    getTotal() {
      let total = 0
      total = this.num * this.price
      return total
    }
  },
  components: {},
  watch: {},
  filters: {
    reviseCont(val) {
      return '$' + val
    }
  }
};
</script>
<style lang='scss' scoped>
.price {
  width: 200px;
  border: 1px solid #ccc;
  padding: 10px;
}
</style>
  • 效果展示:

image.png