vue-生命周期,$refs,$nextTick

508 阅读4分钟

Vue实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载 Dom→渲染、更新→渲染、卸载等一系列过程

image-20210511152835915.png

钩子函数

1.钩子函数是Vue框架中内置的一些函数,随着Vue的生命周期阶段,自动执行
2.在特点的时间,执行特定的操作
阶段方法名
初始化beforeCreate-------created
挂载beforeMount------mounted
更新beforeUpdate-----updated
销毁beforeDestroy-----destroyed

vue生命周期--->初始化阶段

//-   beforeCreate:生命周期函数被执行`此时不能访问data和menthods等中的东西`
//-   created:生命周期钩子函数被执行,实例创建`此时能访问data和menthods等中的东西`
<template>
  <div>
    <h1>{{ msg }}</h1>
    <button @click="btn">点我</button>
    <button @click="chexi">销毁/定时器</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "你好,生命周期",
      time: 0,
    };
  },
  methods: {
    btn() {
      this.msg = "hello word!";
    },
    chexi() {
      //销毁当前组件
      this.$destroy();
    },
  },
  //初始化阶段,不能获取data里的数据
  beforeCreate() {
    console.log(this.msg);
  },
  //可以获取data数据,发网络请求
  created() {
    console.log(this.msg);
    //不能获取真实HTML标签
  },
}

挂载阶段

 // 挂载阶段
/*
-   虚拟DOM挂载成真实DOM之前:
-   beforeMount :生命周期钩子函数被执行
-   Create: 把虚拟DOM和渲染的数据一并挂到真实DOM上
-   挂载完毕,mounted:生命周期钩子函数被执行
*/
  //DOM挂载前触发
  beforeMount() {
    console.log("beforeMount", "dom挂载前触发");
    console.log(document.querySelector("h1"));
  },
  mounted() {
    console.log("已经挂载完成了");
    //可以拿到真实HTML标签
    //一般在这个函数中可以操作DOM元素
    //可以发起ajax请求,请求初始数据
    console.log(document.querySelector("h1"));
    //定时器
    // this.time = setInterval(() => {
    //   console.log(123);
    // });
  },

更新阶段

当data里数据改变, 更新DOM之前,beforeUpdate – 生命周期钩子函数被执行`此时获取不到更新的真实dom`
updated – 生命周期钩子函数被执行
  //更新阶段
  //data中变量发生改变时执行的过程
  beforeUpdate() {
    //不能获取到DOM改变后的数据,可以获取DOM改变前的数据
    console.log(document.querySelector("h1").innerHTML);
    console.log("beforeUpdate,DOM数据改变其触发");
  },
  updated() {
    console.log("updated,DOM数据改变后触发");
    //可以获取到DOM改变后的数据
    console.log(document.querySelector("h1").innerHTML);
  },

销毁阶段

$destroy()被调用:比如组件DOM被移除(例v-if)
beforeDestroy:生命周期钩子函数被执行
拆卸数据监视器、子组件和事件侦听器
实例销毁后, 最后触发一个钩子函数
destroyed: 生命周期钩子函数被执行
  //销毁阶段,当$destroy方法被调用的时候触发
  beforeDestroy() {
    //可以用来清除定时器,或者全局的事件
    //当销毁组件的时候,是不会销毁定时器的,需要手动销毁
    console.log("beforeDestroy,实列销毁前触发");
    //清除定时器
    clearInterval(this.time);
  },
  destroyed() {
    console.log("destroyed,实列销毁后触发");
  },

$refs

refs获取dom利用refrefs-获取dom 利用`ref`和`refs`可以用于获取dom元素

<template>
  <div>
      <p>1. 获取原生DOM元素</p>
      <h1 id="h" ref="myH">我是一个孤独可怜又能吃的h1</h1>
  </div>
</template>

<script>
// 目标: 获取组件对象
// 1. 创建组件/引入组件/注册组件/使用组件
// 2. 组件起别名ref
// 3. 恰当时机, 获取组件对象
export default {
    mounted(){
        console.log(document.getElementById("h")); // h1
        console.log(this.$refs.myH); // h1
    }
}
//通过id获取ref都可以获取原生dom标签
</script>

<style>

</style>

$refs-获取组件对象

获取组件对象,调用组件里的方法

//子组件demo
<template>
  <div>
      <p>我是Demo组件</p>
  </div>
</template>

<script>
export default {
    methods: {
        fn(){
            console.log("demo组件内的方法被调用了");
        }
    }
}
</script>

父组件获取子组件的组件对象,调用方法 $nextTick使用

/*
点击count++, 马上通过"原生DOM"拿标签内容, 无法拿到新值
*/
<template>
  <div>
      <p>1. 获取原生DOM元素</p>
      <h1 id="h" ref="myH">我是一个孤独可怜又能吃的h1</h1>
      <p>2. 获取组件对象 - 可调用组件内一切</p>
      <Demo ref="de"></Demo>
         <p>3. vue更新DOM是异步的</p>
      <p ref="myP">{{ count }}</p>
      <button @click="btn">点击count+1, 马上提
  </div>
</template>

<script>
// 目标: 获取组件对象
// 1. 创建组件/引入组件/注册组件/使用组件
// 2. 组件起别名ref
// 3. 恰当时机, 获取组件对象
import Demo from './Child/Demo'
export default {
    components: {
        Demo
    },
    data(){
        return {
           count: 0
        },
    mounted(){
        console.log(document.getElementById("h")); // h1
        console.log(this.$refs.myH); // h1

        let demoObj = this.$refs.de;
        demoObj.fn()
    },
   methods: {
        btn(){
            this.count++; // vue监测数据更新, 开启一个DOM更新队列(异步任务)
            console.log(this.$refs.myP.innerHTML); // 0

            // 原因: Vue更新DOM异步
            // 解决: this.$nextTick()
            // 过程: DOM更新完会挨个触发$nextTick里的函数体
             this.$nextTick(() => {
                console.log(this.$refs.myP.innerHTML); // 1
            })
        }
    }
}
</script>
//ref定义值,通过$refs.值 来获取组件对象,就能继续调用组件内的变量

$nextTick使用.gif

<template>
  <div>
      <input ref="myInp" type="text" placeholder="这是一个输入框" v-if="isShow">
      <button v-else @click="btn">点击我进行搜索</button>
  </div>
</template>

<script>
// 目标: 点按钮(消失) - 输入框出现并聚焦
// 1. 获取到输入框
// 2. 输入框调用事件方法focus()达到聚焦行为
export default {
    data(){
        return {
            isShow: false
        }
    },
    methods: {
        async btn(){
            this.isShow = true;
            // this.$refs.myInp.focus()
            // 原因: data变化更新DOM是异步的
            // 输入框还没有挂载到真实DOM上
            // 解决:
            // this.$nextTick(() => {
            //     this.$refs.myInp.focus()
            // })
            // 扩展: await取代回调函数
            // $nextTick()原地返回Promise对象
            await this.$nextTick()
            this.$refs.myInp.focus()
        }
    }
}
</script>

数据请求在created和mouted的区别

created是在组件实例一旦创建完成的时候立刻调用,这时候页面dom节点并未生成mounted是在页面dom节点渲染完毕之后就立刻执行的触发时机上created是比mounted要更早的两者相同点:都能拿到实例对象的属性和方法讨论这个问题本质就是触发的时机,放在mounted请求有可能导致页面闪动(页面dom结构已经生成),但如果在页面加载前完成则不会出现此情况建议:放在create生命周期当中

面试题

1.Vue的nextTick的原理是什么

1.为什么需要nextTick,vue是异步修改DOM的,并且不鼓励开发之直接接触DOM,但有什么业务需要必须对数据更改--刷新后的DOM做相应的处理,这时候就可以用Vue.nextTick(callback)这个api
2.理解原理前的准备,首先需要指定时间循环中宏任务和微任务这两个概念。常见的宏任务有:script , setTimeout , setInterval , setImmediate
常见的微任务有:process , nextTick(Nodejs) , promise.then() 
MutationObserve([API] 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动)
3.理解ntxtTick的原理正式vue通过异步列控制DOM更新和nextTick回调函数先后执行的方式

2.vue生命周期总共分几个阶段

Vue实例从创建过程到销毁过程,就是生命周期。也就是从开始创建,初始化数据,编译模板,挂载DOM-->渲染、更新-->渲染、卸载等一系列过程,称为Vue的生命周期

1.beforeCreadte:\在实例化初始化之后,数据观测(data observer)和event/watcher事件配置之前被调用

2.created:在实例创建完成后被立即调用。在这一步,实例已完成以下配置:数据观测(data observer),属性和方法的运算,watch/event事件回调。然而,挂载阶段还没开始

3.beforeMount:在挂载开始之前被调用,相关的render函数首次被调用

4.mounted:el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。如果root实例挂载了一个文档内原生,当mounted被调用时,vm.$el也在文档内

5.beforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。这里适合在更新之前访问现有的DOM。比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行

6.updated:由于数据更改导致的虚拟DOM中学渲染和打补丁,在这之后就会调用这个钩子。

7.activated:keep-alive组件激活时调用。该钩子在服务器端渲染期间不被调用

8.deactivated:keep-alive组件停用时调用。该钩子在服务器端渲染期间不被调用。

9.beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10.destroyed:Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解除绑定,所有的事件监听会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11.errorCaptured(2.5.0+新增):当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数,错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子开源返回false以阻止该错误继续向上传播

第一次加载页面会触发哪几个钩子函数

当页面第一次加载时会触发beforeCreate , created , beforeMount , mounted这几个钩子函数