前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue专题 05_详解vue生命周期的每个节点

Vue专题 05_详解vue生命周期的每个节点

作者头像
用户9999906
发布2022-09-26 11:36:12
4890
发布2022-09-26 11:36:12
举报
文章被收录于专栏:学编程的GISer

1.引出生命周期

假如现在要实现一个更改透明度的功能:(让这几个字周而复始的消失和出现)

GIF

实现代码:

方法一:普通方法

代码语言:javascript
复制
<body>
  <div id="root">
    <h1 :style="{opacity:opacity}">学编程的GISer</h1>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        opacity: 1,
      },
    });

    setInterval(() => {
      vm.opacity -= 0.01;
      if (vm.opacity <= 0) {
        vm.opacity = 1;
      }
    }, 16);
  </script>
</body>

但是上述代码还不够完美,如果我们想在实例化的Vue对象中实现这个功能,要怎么做呢?看⬇

方法二:先尝试用methods实现(剧透:实现不了):

尝试用methods实现,但是出现bug

要使用方法必须要调用方法,而这个方法中没有return,正好在调用的时候返回的是undefined,在也页面上不会显示,但是发现这样行不通,因为方法里面会修改opacity的值,这样又会重新渲染模板,然后重新调用方法,再修改opacity,再重新渲染模板,调用方法,修改opacity…… 这样会导致方法调用的次数成指数型大爆炸式增长。

方法三:用生命周期函数

生命周期函数\钩子:在某个时间点会自动执行的函数。

引入生命周期函数中的mounted(){}:

代码语言:javascript
复制
<body>
  <div id="root">
    <h1 :style="{opacity:opacity}">学编程的GISer</h1>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        opacity: 1,
      },
      methods: {},
      mounted() {
        setInterval(() => {
          this.opacity -= 0.01;
          if (this.opacity <= 0) {
            this.opacity = 1;
          }
        }, 16);
        console.log(this);
      },
    });
  </script>
</body>

实现该功能:

GIF

解释一下mounted(){}:这个生命周期钩子是在Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)才调用的。

生命周期:

1.又名:生命周期回调函数、生命周期函数、生命周期钩子(Vue会在一个特殊的时刻把生命周期函数出来调用)。

2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。

3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。

4.生命周期函数中的this指向是vm 或 组件实例对象。

2.挂载流程

生命周期的挂载、更新和销毁流程图:

下边会对流程图中的①—⑩进行逐一讲解:

(1)证明①:beforeCreate

此时还没有做数据代理、数据监测

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      beforeCreate() {
        console.log('beforeCreate', this);
        debugger; //断点,使用断点要打开Live Server之后打开控制台,再刷新页面(不开控制台断点卡不进去)
      },
    });
  </script>
</body>

(2)证明②:created

此时已经完成数据代理及数据监测,但是页面上还没有显示出经过Vue编译后的DOM结构

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      beforeCreate() {
        console.log('beforeCreate');
      },
      created() {
        console.log('created', this);
        debugger;
      },
    });
  </script>
</body>

(3)证明③:beforeMounte

证明页面所呈现的是未经Vue编译的DOM结构:

证明此时对DOM操作时不奏效的:

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      beforeCreate() {
        console.log('beforeCreat', this);
      },
      beforeMount() {
        console.log('beforeMount', this);
        document.querySelector('h1').innerHTML = '我更改了DOM';
      },
    });
  </script>
</body>

点击刷新,h1的内容并没有被修改,证明操作DOM无效:

GIF

(4)证明④:mounted

证明此时页面中呈现的都是经过Vue编译的DOM:

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      mounted() {
        console.log('mounted', this);
        debugger;//断点
      },
    });
  </script>
</body>

证明对DOM的操作有效:

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      mounted() {
        console.log('mounted', this);
        //操作DOM:
        document.querySelector('h1').innerHTML = 'DAPAN'
        debugger;
      },
    });
  </script>
</body>

(5)证明⑤

如果没有el:'#root',也没有vm.$mount('#root')

代码语言:javascript
复制
<body>
  <div id="root">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      // el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      beforeCreate() {
        console.log('beforeCreate');
      },
      created() {
        console.log('created');
      },
      beforeMount() {
        console.log('beforeMount');
      },
      mounted() {
        console.log('mounted', this);
      },
    });
    // vm.$mount('#root')
  </script>
</body>

只有前两个打印了出来:

未加el或$mount

加上vm.$mount('#root')之后:

GIF

(6)解释⑥

template:''

注意看图片中的文字哦!

注意:

(1)这里template属性里面套用的标签不能是template标签,也就是说不能把div标签用template替换掉。

(2)vm.$el里面的DOM结构是真实的DOM结构,可以用这个来证明:

代码语言:javascript
复制
mounted:{
console.log('mounted',this.$el.instanceof HTMLElement)//true
}

3.更新流程

(1)证明⑦:beforeUpdate

data中的数据更新时调用。此时数据是新的,但是页面还没来得及更新,即数据和页面尚没有同步

代码语言:javascript
复制
<body>
  <div id="root" :x="n"></div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      template: `
      <div>
        <h1>n值是:{{n}}</h1>
        <button @click="addN">点我n加一</button>
      </div>
      `,
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      beforeUpdate() {
        console.log('beforeUpdate', this.n);
        debugger;
      },
    });
  </script>
</body>

点击按钮,n加一后,此时打印的n值为2,但是页面上显示的n值仍为1:

GIF

此时数据和页面尚未同步

解释:页面初始化的时候并没有运行beforeUpdate,点击按钮,n加1的时候(data中有数据改变的时候)才调用了beforeUpdate;而且此时打印的n值为2,但是此时页面上显示的是1(证明数据和页面尚未同步

(2)证明⑧:updated

代码语言:javascript
复制
<body>
  <div id="root" :x="n"></div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      template: `
    <div>
      <h1>n值是:{{n}}</h1>
      <button @click="addN">点我n加一</button>
    </div>
    `,
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
        },
      },
      updated() {
        console.log('updated', this.n);
        debugger;
      },
    });
  </script>
</body>

数据和页面保持同步:

数据和页面已经同步

4.销毁流程

先来看一下vm.$destroy的官网解释(建立在一个组件化编码的思维方式上):

官网对vm.$destroy的解释

vm被销毁之后并没有解绑原生事件,只会解绑自定义事件

@click=''是原生事件,所以并未销毁

页面演示如下⬇

销毁vm之后,click事件依然可以工作

(1)解释⑨:beforeDestroy

代码语言:javascript
复制
<body>
  <div id="root" :x="n">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
    <button @click="bye">点我销毁vm</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
          console.log('addN');
        },
        bye() {
          vm.$destroy();
        },
      },
      beforeCreate() {
        console.log('beforeCreate', '无法通过vm访问data和methods');
      },
      created() {
        console.log('created', '可以通过vm访问data和methods');
      },
      beforeMount() {
        console.log('beforeMount', 'DOM未经Vue编译');
      },
      mounted() {
        console.log('mounted', 'DOM经过Vue编译');
      },
      beforeUpdate() {
        console.log('beforeUpdate', '页面更新之前');
      },
      updated() {
        console.log('updated', '页面更新完毕');
      },
      beforeDestroy() {
        console.log('beforeDestroy', '马上执行销毁vm的状态');
        this.addN()//测试能否调用addN方法
        console.log(this.n)//测试能否拿到data中的数据
      },
    });
  </script>
</body>

此时可以调用原生的方法addN(),也可以拿到n的值,但是此时对n的操作不再在页面上反映出来:

根据图中的1,2,3,4依次看哦

解释:页面上展示不出更新之后的数据(vm虽然销毁了,可是他的工作成果还在,页面上还能显示之前经过Vue编译的DOM结构,但此时Vue已经不会在帮你管理这个DOM了)其实此时已经调用了addN()方法,但是由于你处在的时间点很尴尬,你是已经在它进入销毁流程的时候里的销毁之前去调用,你在这里对数据进行的所有操作都不会再更新了。事实是只要进入了beforeDestroy你仍可以访问到数据和方法,但是修改数据无法再更新了,更新数据唯独放在beforeDestroy和destroy时,不会再触发更新了,一般在此时做一下关闭定时器、取消订阅消息、解绑自定义事件等首尾工作。

(2)解释⑩:destroy

此时已经解绑了事件监听器

代码语言:javascript
复制
<body>
  <div id="root" :x="n">
    <h1>n值是:{{n}}</h1>
    <button @click="addN">点我n加一</button>
    <button @click="bye">点我销毁vm</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        n: 1,
      },
      methods: {
        addN() {
          this.n++;
          console.log('addN');
        },
        bye() {
          vm.$destroy();
        },
      },
      watch:{
        n(){
          console.log('n变了');
        }
      }
    });
  </script>
</body>

销毁vm之后,监视属性watch不再工作

只剩下了原生的事件可以工作,watch被销毁了

5.总结

一共有8个生命周期钩子(4对)

类比张三的一生:

优化 '更改透明度' 的案例:

实现点击按钮使得透明度不再变换的功能:

方法一:这里有一个小技巧,如下

全局变量的设置技巧

方法二:通过销毁vm实现

代码语言:javascript
复制
<body>
  <div id="root">
    <h1 :style="{opacity:opacity}">学编程的GISer</h1>
    <button @click="stop">停止变换透明度</button>
  </div>
  <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
      el: '#root',
      data: {
        opacity: 1,
      },
      methods: {
        stop() {
          // 销毁vm:
          this.$destroy();
        },
      },
      mounted() {
        this.timer = setInterval(() => {
          this.opacity -= 0.01;
          if (this.opacity <= 0) {
            this.opacity = 1;
          }
          console.log('setInterval');
        }, 16);
        console.log(this);
      },
      beforeDestroy() {
        // 清除定时器:
        clearInterval(this.timer);
      },
    });
  </script>
</body>

大潘的解析:如果只销毁vm,不关定时器的话,即使销毁了vm,定时器也一直在走,耗费内存,故应该把定时器关掉。但是关定时器又有两种方法,一种是在方法stop()里面关掉,另外一种是在beforeDestroy里面关,我们更倾向于第二种方法,因为在实际复杂的开发中,不一定清楚是在哪个时刻的哪个操作销毁了vm,但是不管在哪销毁vm,都会调用beforeDestroy这个生命周期钩子,所以我们在beforeDestroy里面关掉定时器更保险。

总结:

(1)常用的生命周期钩子:

1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。

2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

(2)关于销毁Vue实例

1.销毁后借助Vue开发者工具看不到任何信息。

2.销毁后自定义事件会失效,但原生DOM事件依然有效。

3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

我会在这里分享更多有用的干货知识,点击下边的框框关注哦!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 学编程的GISer 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.引出生命周期
  • 2.挂载流程
    • (1)证明①:beforeCreate
      • (2)证明②:created
        • (3)证明③:beforeMounte
          • (4)证明④:mounted
            • (5)证明⑤
              • (6)解释⑥
              • 3.更新流程
                • (1)证明⑦:beforeUpdate
                  • (2)证明⑧:updated
                  • 4.销毁流程
                    • (1)解释⑨:beforeDestroy
                      • (2)解释⑩:destroy
                      • 5.总结
                      相关产品与服务
                      云开发 CLI 工具
                      云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档