Vue的自定义指令和生命周期函数

470 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

自定义指令

现有一个输入框:

<div id="app">
  <input type="text" id="it">
</div>

若是想在刷新页面后自动获取输入框的焦点,该如何实现呢?

其实非常简单,可以调用输入框的 focus 函数:

<div id="app">
  <input type="text" id="it">
</div>

<script>
  document.getElementById('it').focus();
</script>

但Vue不推荐我们直接操作DOM,所以我们可以将其转化为自定义的指令:

<div id="app">
  <input type="text" v-focus>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  // 自定义指令
  Vue.directive('focus', {
    // 当指令绑定到指定元素上时调用此函数,只执行一次
    bind(el) {  // el即为绑定该指令的元素

    },
    // 当元素插入到DOM时调用此函数,只执行一次
    inserted(el) {
      el.focus();
    },
    // 当元素更新时调用此函数,执行多次
    updated(el) {

    }
  });
</script>

这里需要注意,自定义指令通过 Vue.directive 进行设置,它需要两个参数,第一个参数为指令的名称,第二个参数为一个对象,在该对象内需要定义指令生效的三个周期函数,周期函数的入参中可以获取到绑定该指令的元素,然后调用 focus 获取焦点即可。

\

在使用该指令时也需要注意,必须在自定义的指令名前加上 v- 前缀。

\

那么自定义指令该如何实现传值呢:

<div id="app">
  <input type="text" v-color="'red'">
</div>

自定义一个v-color指令,并根据传递的参数值设置输入框的字体颜色, 实现如下:

<script>
  // 自定义指令
  Vue.directive('color', {
    // 当指令绑定到指定元素上时调用此函数,只执行一次
    bind(el,binding) {  // el即为绑定该指令的元素
      el.style.color = binding.value;
    },
    // 当元素插入到DOM时调用此函数,只执行一次
    inserted(el) {
    },
    // 当元素更新时调用此函数,执行多次
    updated(el) {

    }
  });
</script>

通过周期函数的第二个参数 binding ,我们能够获取到很多信息,其中value属性即为指令设置的值,将该值设置到样式中即可。

\

刚才定义的是全局指令,我们也可以定义只属于某个Vue实例本身的私有指令,与过滤器类似,只需在Vue实例中定义即可:

<script>
  var app = new Vue({
    el: '#app',
    data: {
    },
    directives: {
      // 自定义私有指令
      'color': {
        // 当指令绑定到指定元素上时调用此函数,只执行一次
        bind(el, binding) {  // el即为绑定该指令的元素
          el.style.color = binding.value;
        },
        // 当元素插入到DOM时调用此函数,只执行一次
        inserted(el) {
        },
        // 当元素更新时调用此函数,执行多次
        updated(el) {
        }
      }
    }
  });
</script>

Vue还提供了一种更简便的方式来自定义指令:

<script>
  Vue.directive('Vue', function (el,binding) {
    el.style.color = binding.value;
  });
</script>

但这种方式只会生效于bind和updated周期函数,它等同于将函数中的代码在bind和updated函数中均粘贴一份。

Vue实例的生命周期

Vue实例从创建、运行到销毁期间,总是伴随着各种各样的事件,这些事件统称为生命周期,生命周期大体被分为三类:

  1. 创建期间的生命周期
  2. 运行期间的生命周期
  3. 销毁期间的生命周期

其中创建期间的生命周期函数又有以下几个:

  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好data和methods属性
  • created:实例已经在内存中创建好,此时data和methods也已经创建好,但还没有编译模板
  • beforeMount:此时已经完成了模板的编译,但是还未加载到页面中
  • mounted:将已经编译好的模板挂载到页面指定的容器中显示

运行期间的生命周期函数:

  • beforeUpdate:状态更新之前执行此函数,此时data中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还未重新渲染DOM
  • updated:实例更新完毕后调用此函数,此时data中的状态值和界面上显示的数据都已经完成了更新,界面已经重新渲染

销毁期间的生命周期:

  • beforeDestroy:实例销毁之前调用,实例仍然完全可用
  • destroyed:实例销毁之后调用,调用完成后,Vue实例指示的所有东西都会解除绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

\

先来测试一下beforeCreate函数:

<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'success'
    },
    methods: {
      show() {
        console.log('执行了show函数...');
      }
    },
    // Vue实例完全被创建好之前执行此函数
    beforeCreate() {

      console.log('执行了beforeCreate函数---' + this.msg);// 无法访问msg数据
      this.show();// 无法调用show函数
    },
  });
</script>

由于此时Vue实例并没有被完全创建好,所以Vue实例中的data和methods属性均无法访问,执行结果如下:

再看created函数:

<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'success'
    },
    methods: {
      show() {
        console.log('执行了show函数...');
      }
    },
    // Vue实例完全被创建好之后渲染模板之前调用此函数
    created() {
      console.log('执行了created函数---' + this.msg);
      this.show();
    },
  });
</script>

此时Vue实例已经完全创建好,当然就可以访问data和methods了,执行结果如下:

beforeMount函数:

<div id="app">
  <p id="p">{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'success'
    },
    methods: {
      show() {
        console.log('执行了show函数...');
      }
    },
    // 模板编译完成后页面加载之前执行此函数
    beforeMount() {
      console.log('执行了beforeMount函数---' + document.getElementById('p').innerText);
    },
  });
</script>

该函数在模板编译完成后页面加载之前执行,所以我们获取到p标签的数据是还未加载数据的内容,执行结果:

mounted函数:

<script>
  // 页面加载完成后执行此函数
  mounted() {
    console.log('执行了mounted函数---' + document.getElementById('p').innerText);
  },
</script>

该函数在页面加载完成后执行,所以它能够获取到页面渲染后的真正数据,执行结果:

当mounted函数执行完成后,就表示Vue实例被真正地创建完成了。

\

再来看看运行期间的生命周期函数,首先是beforeUpdate函数:

<div id="app">
  <p id="p">{{msg}}</p>
  <input type="button" value="修改msg值" @click="msg='Fail'">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'success'
    },
    methods: {
      show() {
        console.log('执行了show函数...');
      }
    },
    // data数据更新后但界面更新之前执行此函数
    beforeUpdate() {
      console.log('执行了beforeUpdate函数---');
      console.log('页面上的数据---' + document.getElementById('p').innerText);
      console.log('data中的数据---' + this.msg);
    },
  });
</script>

在该页面上显示了一个p标签,并能通过点击按钮修改data中的数据值,此时执行结果:

当点击按钮后,该函数获取到的页面数据仍然是success,而data中的数据发生了变化,这说明该函数在页面重新渲染之前会执行,但此时data中的数据是最新的。

\

updated函数:

<script>
  updated() {
    console.log('执行了updated函数---');
    console.log('页面上的数据---' + document.getElementById('p').innerText);
    console.log('data中的数据---' + this.msg);
  }
</script>

执行结果:

该函数在页面重新渲染之后执行,所以页面和data中获取到的数据都是最新的。

\

最后是销毁阶段的生命周期函数,其中beforeDestroy函数是在销毁之前被执行的,在该函数中仍然可以使用Vue实例中的属性,此时还没有真正地销毁Vue实例,只有在destroyded函数执行完成后才真正地销毁了Vue实例。