vue2中的@hook怎么使用

作者:有用网 阅读量:214 发布时间:2024-01-02
关键字 vue

这篇文章主要讲解了“vue2中的@hook怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue2中的@hook怎么使用”吧!

    前言

    @hook是什么?用来监听组件生命周期的回调函数。

    这和生命周期函数mounted,created,updated有什么区别?

    区别1:@hook 会在对应的生命周期函数执行后执行。

    区别2:@hook 可以在父组件监听子组件的生命周期运行情况。

    vue2中的@hook怎么使用

    从这段vue源代码中我们能看到hook的部分调用逻辑,

    vm.$emit('hook:' + hook)
    其实就是在调用我们写的
    @hook:mounted="xxx"
    ,@hook这个api却没有在官方文档中出现,所以鲜有人知道它的存在和用法。

    几种用法

    用法一 将放在多个生命周期的逻辑,统一到一个生命周期中

    通常写法

    export default {
      components: {},
      data: () => {
        return {
          name: 'dx',
        };
      },
      created() {
        console.log('created')
      },
      beforeMount() {
        console.log('beforeMount')
      },
      mounted() {
        console.log(this.name);
        // 每一个小时刷新一次页面
        setInterval(() => {
          location.reload()
        }, 60 * 60 * 1000);
      },
    }

    @hook的用法

    export default {
      components: {},
      data: () => {
        return {
          name: 'dx',
        };
      },
      created() {
        console.log('created');
        this.$on('hook:beforeMount', () => {
          console.log('beforeMount');
        });
        this.$on('hook:mounted', () => {
          console.log(this.name); // this 就是组件实例自己
          // 每一个小时刷新一次页面
          setInterval(() => {
            location.reload();
          }, 60 * 60 * 1000);
        });
      },
    };

    注意

    1. 按照生命周期执行的先后周期,我们只能mounted生命周期里,写这之后的生命周期,而不能写

      hook:beforeMount
    2. this.$on
      第二个回调函数的
      this
      指的是当前组件实例本身,无论这个回调函数是否是箭头函数。

    用法二 监听子组件生命周期运行的情况

    通常写法

    // 父组件
    <Children @buttonRender="ButtonRender"/>
    
    export default {
      name: 'Parents',
      components: {
      	Children
      },
      data: () => {
        return {
          name: 'dx',
        };
      },
      methods: {
        ButtonRender() {
          console.log('渲染完成')
        }
      }
    }
    // 子组件
    export default {
      name: 'Children',
      components: {},
      data: () => {},
      methods: {},
      mounted() {
      	this.$emit('buttonRender')
      }
    }

    @hook的写法

    <Children @hook:mounted="ButtonRender"/>
    
    export default {
      name: 'Parents',
      components: {
      	Children
      },
      data: () => {
        return {
          name: 'dx',
        };
      },
      methods: {
        ButtonRender() {
          console.log('渲染完成')
        }
      }
    }

    注意

    1. @hook的写法可以不需要在子组件里面编写其它代码

    2. 从vue源码中可以发现 vm.$emit('hook:' + hook) 这里虽然调用了hook但没有返回参数,也就是说,上面代码中ButtonRender没有默认参数。

    3. 同样承接着2来说,由于ButtonRender没有默认参数,所以我们无法在ButtonRender函数中获取子组件Children的实例。

    为了解决3的问题,我尝试着想到一种方法,利用ref获取子组件的实例,将子组件的实例拿到父组件的this中。ButtonRender中的this就是父组件实例,和寻常methods中的函数没区别。

    <Children ref="child1" @hook:mounted="ButtonRender"/>
    export default {
      name: 'Parents',
      components: {
      	Children
      },
      data: () => {
        return {
          name: 'dx'
        };
      },
      mounted() {},
      methods: {
        ButtonRender() {
          console.log(this.$refs.child1) // this.$refs.child1就是子组件Children的实例了
          console.log('渲染完成')
        }
      }
    };

    但是,我们都知道,vue ref的绑定都是挂载完成之后,所以这个方法也只能用在

    @hook:mounted
    @hook:updated
    等mounted之后执行的生命周期中,而不能用在 比如
    @hook:beforeMount
    中。

    运用场景

    场景一

    许多时候,我们不得不在不同的生命周期中执行某些逻辑,并且这些逻辑会用到一些通用的变量,这些通用变量按照之前的方式,我们不得不存在data中。

    <script>
    export default {
      data() {
        return {
            timer:null
          }
      }
      mounted () {
        this.timer = setInterval(() => {
    	// todo
        }, 1000);
      }
      beforeDestroy () {
        clearInterval(this.timer)
      }
    }
    </script>

    优化后,就不存在这个问题,是不是很好用。

    <script>
    export default {
      mounted () {
        const timer = setInterval(() => {
    	// todo
        }, 1000);
        this.$once('hook:beforeDestroy', function () {
            clearInterval(timer)
        })
      }
    }
    </script>

    场景二

    如果属于同一业务的逻辑要在不同的生命周期中执行,下面这样会更利于阅读和维护。

    export default {
      created() {
        this.$on('hook:mounted', () => {
          挂载时执行一些业务A相关逻辑
        })
        this.$on('hook:updated', () => {
          挂载时执行一些业务A相关逻辑
        })
        this.$once('hook:beforeDestroy', () => {
          挂载时执行一些业务A相关逻辑
        })
      }
    }

    场景三

    想要监听别人封装好的组件(第三方组件)的生命周期,你不可能去第三方子组件的生命周期中写代码。

    比如 element-ui 的button组件,在子组件渲染完成后,我想做某些逻辑变更。

    <el-button type="primary" @hook:mounted="ButtonRender" :disabled="disabled">{{name}}</el-button>
    
    export default {
      name: 'Parents',
      data: () => {
        return {
          name: 'dx',
          disabled: true
        };
      },
      methods: {
        ButtonRender() {
          this.disabled = false
          this.name = 'yx'
        }
      }
    }

    所有生命周期执行的顺序

    第一次渲染

    父beforeCreate
    父 hook:beforeCreate
    父created
    父 hook:created
    父beforeMount
    父 hook:beforeMount
    子beforeCreate
    子hook:beforeCreate
    子created
    子hook:created
    子beforeMount
    子hook:beforeMount
    子mounted
    子hook:mounted
    父mounted
    父 hook:mounted

    更新时

    父beforeUpdate
    父hook:beforeUpdate
    子beforeUpdate
    子hook:beforeUpdate
    子updated
    子hook:updated
    父updated
    父hook:updated

    组件摧毁时

    父beforeDestroy
    父hook:beforeDestroy
    子beforeDestroy
    子hook:beforeDestroy
    子destroyed
    子hook:destroyed
    父destroyed
    父hook:destroyed

    以上内容涉及到vue父子组件生命周期执行顺序的知识,但对于@hook:xxx来说,在xxx执行后就会立即执行@hook:xxx


    #发表评论
    提交评论