到目前为止,我们已经接触到了 vue 官方的指令有:

  • v-textv-htmlv-oncev-slot
  • v-bindv-on
  • v-ifv-else-ifv-show
  • v-forv-model

  除此之外 vue 还允许开发者自定义指令,来满足自己的个别需求。

应用:权限管理

# 一、自定义指令

# 1、简介

官方描述:

有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

vue 指令分析:

  以v-show指令为例,它就是一个 vue 操作 DOM 元素的 display 属性而实现的一个语法糖。

从某种角度来讲,vue 指令就是对 一些原生 DOM 操作进行封装,方便后续使用

# 2、代码体验

  使用指令的方式操作 DOM,简单实现如下:

除了 elm 之外,其它参数都应该是只读的,切勿进行修改。

<div id="app">
  v-text指令:<span v-text="msg1"></span> <br /><br />

  v-textBig指令:<span v-redtext="msg2"></span>
</div>

<script type="text/JavaScript">
  new Vue({
    el: '#app',
    data: {
      msg1: 'vue的指令',
      msg2: '自定义的指令'
    },
    directives: {
      redtext(elm,binding) {
        // 1、参数介绍
        // elem参数:当前使用的真实DOM元素
        // binding参数:绑定包含数据变量的信息的一个对象
        console.log(elm instanceof HTMLElement)
        console.log(binding.value)

        // 2、功能实现
        elm.innerHTML = binding.value
        elm.style.color = "red"
      }
    }
  });
</script>

体会:

  • 使用 vue 提供的两个参数就可以对原始 DOM 进行操作
  • 指令命名建议不要出现大写(我使用 redText 就报错了 🤔)

# 3、钩子函数 ✍

  上面是一个自定义指令的简写(bind 和 updata 构造函数的简写),并不是完整写法。

有些情况,使用前面函数式的写法是不可以实现目标效果的。

  下面,就分析一些各个钩子函数的使用:

<div id="app">
  <button @click="keyValue = keyValue + 'd '">更新数据</button>
  <br />
  <input type="text" v-focus:value="keyValue" />
  <br />
  内容:{{keyValue}}
</div>

<script type="text/JavaScript">
  new Vue({
    el: '#app',
    data: {
      keyValue:''
    },
    directives: {
      focus: {
        // 过程一:自定义指令和DOM元素绑定时(一上来)
        bind(elm,binding){
          console.log("绑定成功")

          elm.value = binding.value
        },
        // 过程二:对应的DOM元素插入页面时(父节点存在)
        inserted(elm,binding){
          console.log("DOM元素成功渲染,执行……")

          elm.focus()
        },
        // 过程三:对应的DOM元素重新解析时
        update(elm,binding) {
          console.log("DOM元素重新解析成功")

          elm.value = binding.value
        },
      }
    }
  });
</script>

# 4、全局自定义指令

  要设置全局的话,其实和过滤器、组件注册等类似

提示

换个角度思考:若使用私有的,自定义指令优点将很难发挥出来

在后续的组件化开发中,自定义指令大多数使用的是全局模式

// 简写形式
Vue.directive('color', function (el, binding){
    el.style.color = binding.value
})

// 完整形式
Vue.directive('color', {
  bind (el, binding) {
    el.style.color = binding.value
  }

  update (el, binding) {
    el.style.color = binding.value
  }
})

# 二、生命周期函数

  既然上面我们讲到了钩子函数,那就不得不讲一下 vue 的生命周期钩子了。

每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。

  那我们可不可以像自定义中一样,在其功能实现的各个阶段进行操作呢?

生命周期钩子的函数,就提供了让用户可以在不同阶段添加自己的代码的机会

# 1、代码引入(mounted)

提示

  生命周期钩子的 this 上下文指向调用它的 Vue 实例

<script>
  new Vue({
    el: '#app',
    mounted() {
      console.log(this) // vue实例
    }
  })
</script>

  下面我们实现一个小小的功能:DOM 页面一渲染完毕,就自动开始执行某些操作。

分析实现:

  如果使用原生 js 的话,我第一时间相对的就是使用立即执行函数。但在 vue 中,我会转而思考可不可以用 bottom 触发事件回调的方式代替;最佳方案还得是 vue 的生命周期钩子

# 2、解决想法

  • 立即执行函数
<div id="timer"></div>

<script>
  ;(function () {
    let timeLeft = 60
    const countdownID = setInterval(function () {
      if (timeLeft <= 0) {
        clearInterval(countdownID)
        document.getElementById('timer').innerHTML = '时间到'
      } else {
        document.getElementById('timer').innerHTML = timeLeft + ' 秒'
      }
      timeLeft -= 1
    }, 1000)
  })()
</script>
  • 事件回调(但是问题改变了 🤔)
<div id="app">
  <button @click="startCountdown">开始倒计时</button>
  <div id="timer">{{ timeLeft }}秒</div>
</div>

<script type="text/JavaScript">
  new Vue({
    el: '#app',
    data: {
      timeLeft: 60,
    },
    methods: {
      startCountdown() {
        const countdownID = setInterval(() => {
          if (this.timeLeft <= 0) {
            clearInterval(countdownID)
            document.getElementById('timer').innerHTML = '时间到'
          } else {
            this.timeLeft--
          }
        }, 1000)
      }
    }
  });
</script>

# 3、vue 解决

  如果使用 vue 的生命周期钩子,上面的两种效果我们都可以实现

  • 自动触发(mounted 钩子)
<div id="app">
  <div id="timer">{{ timeLeft }}秒</div>
</div>

<script type="text/JavaScript">
  new Vue({
    el: '#app',
    data: {
      timeLeft: 60,
    },
    mounted() {
      const countdownID = setInterval(() => {
        if (this.timeLeft <= 0) {
          clearInterval(countdownID)
          document.getElementById('timer').innerHTML = '时间到'
        } else {
          this.timeLeft--
        }
      }, 1000)
    },
  })
</script>
  • 手动停止

methods 中 和 钩子函数中 的定时器 id 共用怎么办? —— 挂载 👏 到 vm 示例上

<div id="app">
  <button @click="stopCountdown">暂停</button>
  <button @click="startCountdown">启动</button>
  <div id="timer">{{ timeLeft }}秒</div>
</div>

<script type="text/JavaScript">
  new Vue({
    el: '#app',
    data: {
      timeLeft: 60,
      timeTemp: 0
    },
    methods: {
      stopCountdown() {
        this.timeTemp = this.timeLeft
        clearInterval(this.countdownID)
      },
      startCountdown() {
        this.timeLeft = this.timeTemp
        this.countDown()
      },

      countDown() {
        // 将id值挂载到vm🚩实例上
        this.countdownID = setInterval(() => {
          this.timeLeft--
          if (this.timeLeft <= 0) clearInterval(this.countdownID)
        }, 1000)
      }
    },
    mounted() {
      this.countDown()
    },
  })
</script>
更新于 : 8/7/2024, 2:16:31 PM