既昨天的内容继续往下。

四、Watch(熟悉)

watch的作用可以监控一个值的变换,并调用因为变化需要执行的方法。可以通过watch动态改变关联的状态。

简单点说,就是实时监听某个数据的变化。

1、普通监听

 <template>
   <div class="home">
     <input type="text" v-model="msg">
     <h3>{{msg}}</h3>
   </div>
 </template>
 ​
 <script>
 export default {
   name: 'Home',
   data(){
     return {
       msg: "你好,世界"
     }
   },
   watch: {
     msg(val, oldVal){
       console.log(val, oldVal)
     }
   }
 }
 </script>

2、立即监听

如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。

 <template>
   <div class="home">
     <input type="text" v-model="num">
   </div>
 </template>
 ​
 <script>
 export default {
   name: "Home",
   data() {
     return {
       num: 20
     };
   },
   watch: {
     num: {
       handler(val, oldVal) {
         console.log(val, oldVal);
       },
       // 组件注入页面时就立即监听
       immediate: true
     }
   }
 };
 </script>

immediate需要搭配handler一起使用,其在最初绑定时,调用的函数也就是这个handler函数。

3、深度监听

当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

 <template>
   <div class="home">
     <h3>{{obj.age}}</h3>
     <button @click="btnClick">按钮</button>
   </div>
 </template>
 ​
 <script>
 export default {
   name: 'Home',
   data(){
     return {
       obj: {
         name: "Lucy",
         age: 13
       }
     }
   },
   methods: {
     btnClick(){
       this.obj.age = 33;
     }
   },
   watch: {
     obj: {
       handler(val, oldVal){
         console.log(val.age, oldVal.age)        //  33   33
       },
       deep: true
     }
   }
 }
 </script>

注意:

1、如果监听的数据是一个对象,那么 immediate: true失效;

2、一般使用于对引用类型的监听,深度监听,如监听一个Object,只要Object里面的任何一个字段发生变化都会被监听,但是比较消耗性能,根据需求使用,能不用则不用。

3、因为上面代码obj是引用数据类型,val, oldVal指向一致,导致看到的结果一样。

4、deep优化

 <template>
   <div class="home">
     <h3>{{obj.age}}</h3>
     <button @click="btnClick">按钮</button>
   </div>
 </template>
 ​
 <script>
 export default {
   name: "Home",
   data() {
     return {
       obj: {
         name: "Lucy",
         age: 13
       }
     };
   },
   methods: {
     btnClick() {
       this.obj.age = 33;
     }
   },
   watch: {
     // 通过点语法获取对象中的属性,然后转为字符串,即是对深度监听的优化
     "obj.age": {
       handler(val, oldVal) {
         console.log(val, oldVal);
       },
       deep: true,
       immediate: true,      // 此时监听的数据不是一个对象,可以使用immediate
     }
   }
 };
 </script>

5、Watch与Computed的区别

  • watch中的函数是不需要调用的,computed内部的函数调用的时候不需要加()

  • watch(属性监听),监听的是属性的变化,而computed(计算属性),是通过计算而得来的数据

  • watch需要在数据变化时执行异步或开销较大的操作时使用,而对于任何复杂逻辑或一个数据属性,在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性computed。

  • computed 属性的结果会被缓存,且computed中的函数必须用return返回最终的结果

  • watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;

6、Watch与Computed的使用场景

  • computed    

    • 当一个结果受多个属性影响的时候就需要用到computed

    • 最典型的例子: 购物车商品结算的时候

  • watch

    • 当一个数据的变化需要有往外操作的时候就需要用watch

    • 搜索数据

  • 总结:

    • 一个值的结果受其他值的影响,用computed

    • 一个值的变化将时刻影响其他值,用watch

五、Mixins混入(掌握)

mixins就是定义一部分公共的方法或者计算属性,然后混入到各个组件中使用,方便管理与统一修改。同一个生命周期,混入对象会比组件的先执行。

1、导出mixins

在src下创建 mixins/index.js,写入:

 export const MixinsFn = {
     created() { 
         console.log("这是mixins触发的created")
     }
 }

2、引用mixins

 <template>
   <div class="about">
     <h1>This is an about page</h1>
   </div>
 </template>
 <script>
 import { MixinsFn } from '@/mixins/index.js'
 export default {
   created(){
     console.log("这是about触发的created")
   },
   mixins: [MixinsFn]
 }
 </script>

我们会发现,mixins中的createdabout中的created 优先执行。

六、ref与$refs(掌握)

vue中获取页面里的某个元素(标签或组件),可以给它绑定ref属性,有点类似于给它添加id名。然后通过refs来进行绑定这个元素

1、简单使用

 <template>
  <div class="">
      <h3 ref="title">{{msg}}</h3>
      <button @click="btnclick">按钮</button>
  </div>
 </template>
  
 <script>
 export default {
   data() {
     return {
       msg: "你好"
     };
   },
   methods: {
     btnclick() {
       console.log(this.$refs.title);        // 得到h3标签
     }
   }
 };
 </script>
  
 <style lang = "less" scoped>
 </style>

2、子组件中的数据获取及方法调用

子组件:

 <template>
  <div class="">
      <h4>{{num}}</h4>
  </div>
 </template>
  
 <script>
 export default {
   data() {
     return {
       num: 100
     };
   },
   methods: {
       subFn(){
           console.log('子组件中的方法')
       }
   }
 };
 </script>
  
 <style lang = "less" scoped>
 </style>

父组件:

<template>
 <div class="">
     <Sub ref="sub" />
     <button @click="btnclick">按钮</button>
 </div>
</template>
 
<script>
import Sub from '../components/Sub'
export default {
  methods: {
    btnclick() {
      console.log(this.$refs.sub.num);	// 100
      this.$refs.sub.subFn();						// '子组件中的方法'
    }
  },
  components: {
      Sub
  }
};
</script>
 
<style lang = "less" scoped>
</style>

七、(重点)KeepAlive

<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

KeepAlive用于处理组件缓存。有什么用呢?想象一个业务场景:

在Login页面填写完手机号,发现未注册,需要跳去Register页面完成注册,再返回Login页面填写密码,进行登录,此时如果在Login页面没有保存好手机号,那么跳回来时,用户又得重新输入手机号。为了解决这样的需求,我们需要借助keep-alive。

这里,我们新创建两个页面, You.vueMe.vue ,并且都实现累加功能。

1、修改App.vue

// 将原本的:
<router-view/>

// 修改为:
<keep-alive>
  <router-view/>
</keep-alive>

这样,我们实现了整个项目中每个页面的缓存,显然我们不想这么做,我们只想针对某些页面,这时,我们修改一下:

<keep-alive>
	<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />

注意:

<keep-alive> 是用在其一个直属的子组件被开关的情形。如果你在其中有 v-for 则不会工作。

那这里的 $route.meta.keepAlive 存在于哪里呢?

2、Router中的meta

这是写在路由文件中的字段,我们去 router/index.js 中,将我们要缓存的 Me.vue 页面加上meta:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  	...,
    {
      path: '/me',
      name: 'Me',
      component: () => import('../views/Me.vue'),
      meta: {
        keepAlive: true
      }
    },
    {
      path: '/you',
      name: 'You',
      component: () => import('../views/You.vue')
    }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

 

八、Vue生命周期

什么是生命周期: 从Vue创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期。

 

生命周期钩子函数:就是生命周期事件的别名;

 

初始

beforeCreate:实例刚刚在内存中被创建出来,此时还没有初始化 datamethods 属性。

created:实例已经在内存中创建好,此时 datamethods 已经创建好,此时还没有开始编译模板

挂载

beforeMount:此时已经完成了模板编译,但是还没有挂载到页面中;

mounted:这个时候已经把编译好的模板挂载到页面指定的容器里;

beforeMount: data 的数据可以访问和修改,而且此时的模板已经编译好了,还没有更新到页面中

mounted: 此时编译的模板更新到页面中了

更新

beforeUpdate:状态更新之前执行此函数,此时的 data 中的数据是最新,但是界面上显示的还是旧的,因为此时还没有开始重新渲染DOM节点;

updated:实例更新完毕之后调用此函数,此时data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了;

beforeUpdate: 此时修改输入框的内容,data中的数据已经更新了,但是页面上显示的还是旧数据;

updated:此时 data 的内容已经更新,页面显示的也是最新的数据。

<template>
  <div>
    <p ref="run">{{ num }}</p>
    <button @click="num++">按钮</button>
  </div>
</template>

<script>
import Comp from "@/components/Comp7Ch.vue";
export default {
  data() {
    return {
      num: 20,
      isC: true,
    };
  },
  components: {
  },
  methods: {
    fn() {
      console.log("这是函数");
    },
  },
  beforeCreate() {
    // 组件创建之前执行的函数,(数据、方法、标签都获取不到)
    console.log("1.1--beforeCreate", this.num, this.fn, this.$refs.run);
  },
  created() {
    //   发起异步请求,获取数据

    // 组件创建之后执行的函数,(数据、方法已经可以获取,标签获取不到)
    console.log("1.2--created", this.num, this.fn, this.$refs.run);
  },
  beforeMount() {
    // 组件挂载数据之前执行的函数,(数据、方法已经可以获取,标签获取不到)
    console.log("2.1--beforeMount", this.num, this.fn, this.$refs.run);
  },
  mounted() {
    // 组件挂载数据之后执行的函数,(数据、方法、标签都可以获取得到)
    console.log("2.2--mounted", this.num, this.fn, this.$refs.run);
  },
  beforeUpdate() {
    // 界面更新之前的函数
    console.log("3.1--beforeUpdate", this.num, this.fn, this.$refs.run);
  },
  updated() {
    // 界面更新之后的函数
    console.log("3.2--update", this.num, this.fn, this.$refs.run);
  },
};
</script>
 
<style lang = "less" scoped>
</style>

 

销毁

beforeDestroy:实例销毁之前调用,在这一步,实例让然完全可用。

destroyed:实例销毁后调用,调用后,Vue实例指向的所以东西会被解绑,所有的事件监听器会被移除,所有的子实力也会被销毁。

新建一个名为:Comp7Ch.vue的子页面:

<template>
    <div>
        这是comp7的子组件
    </div>
</template>

<script>
export default {
    data () {
        return {
        }
    },
    beforeDestroy() {
        // 组件销毁之前执行这个函数,   回收 和清理工作,   比如清除定时器,清除全局事件
        console.log("4.1---beforeDestroy");
    },
    destroyed() {
        console.log("4.2---destroyed");
    },
}
</script>
 
<style lang = "less" scoped>
    
</style>

在刚刚那个页面进行引入,观察他的页面销毁时执行的顺序与内容:

<template>
  <div>
    <p ref="run">{{ num }}</p>
    <button @click="num++">按钮</button>
    <Comp v-if="isC" />
    <button @click="isC = !isC">按钮2</button>
  </div>
</template>

<script>
import Comp from "@/components/Comp7Ch.vue";
export default {
  data() {
    return {
      num: 20,
      isC: true,
    };
  },
  components: {
    Comp,
  },
    ......
Logo

前往低代码交流专区

更多推荐