vue自定义指令实现v-model

概要

指令是vue中非常重要的内容,了解指令的用法可以更好的服务于业务场景,方便高效,本文主要介绍指令的基本概念和用法,简单模拟v-model实现的功能。

自定义指令

除了内置指令,Vue.js 也允许注册自定义指令。自定义指令提供一种机制将数据的变化映射为 DOM 行为。
可以用 Vue.directive(id, definition) 方法注册一个全局自定义指令,它接收两个参数,指令 ID 与定义对象。也可以用组件的 directives 选项注册一个局部自定义指令。

钩子函数

定义对象可以提供几个钩子函数(都是可选的):

  • bind:只调用一次,在指令第一次绑定到元素上时调用。

  • update: 在 bind 之后立即以初始值为参数第一次调用,之后每当绑定值变化时调用,参数为新值与旧值。

  • unbind:只调用一次,在指令从元素上解绑时调用。

例如

Vue.directive('my-directive', {
  bind: function () {
    // 准备工作
    // 例如,添加事件处理器或只需要运行一次的高耗任务
  },
  update: function (newValue, oldValue) {
    // 值更新时的工作
    // 也会以初始值为参数调用一次
  },
  unbind: function () {
    // 清理工作
    // 例如,删除 bind() 添加的事件监听器
  }
})

在注册之后,便可以在 Vue.js 模板中这样用(记着添加前缀 v-):

<div v-my-directive="someValue"></div>

当只需要 update 函数时,可以传入一个函数替代定义对象:

Vue.directive('my-directive', function (value) {
  // 这个函数用作 update()
})

指令实例属性

所有的钩子函数将被复制到实际的指令对象中,钩子内 this 指向这个指令对象。这个对象暴露了一些有用的属性:

  • el: 指令绑定的元素。
  • vm: 拥有该指令的上下文 ViewModel。
  • expression: 指令的表达式,不包括参数和过滤器。
  • arg: 指令的参数。
  • name: 指令的名字,不包含前缀。
  • modifiers: 一个对象,包含指令的修饰符。
  • descriptor: 一个对象,包含指令的解析结果。

示例:

<div id="demo" v-demo:hello.a.b="msg"></div>
Vue.directive('demo', {
  bind: function () {
    console.log('demo bound!')
  },
  update: function (value) {
    this.el.innerHTML =
      'name - '       + this.name + '<br>' +
      'expression - ' + this.expression + '<br>' +
      'argument - '   + this.arg + '<br>' +
      'modifiers - '  + JSON.stringify(this.modifiers) + '<br>' +
      'value - '      + value
  }
})
var demo = new Vue({
  el: '#demo',
  data: {
    msg: 'hello!'
  }
})

结果:

name - demo
expression - msg
argument - hello
modifiers - {"b":true,"a":true}
value - hello!

用自定义指令实现v-model类似的功能

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

Vue.directive('input', {
  bind: function (el, binding, vnode) {
    const { value, expression } = binding
    const { context } = vnode
    el.value = value

    el.oninput = (e) => {
      const value = e.target.value
      context[expression] = value
    }
  },
  update: function () {}
})

new Vue({
  render: h => h(App),
}).$mount('#app')

测试:

<template>
  <div id="app">
    <input type="text" v-input="value1">
    <br>
    value:{{ value1 }}
  </div>
</template>

<script>

export default {
  name: 'App',
  data () {
    return {
      value1: 'test'
    }
  }
}
</script>

以上实现了数据的双向绑定,当然我们可以使用参数和修饰符实现更加复杂的功能,有兴趣的同学可以学习一下。

posted @ 2022-02-10 21:15  Elwin0204  阅读(928)  评论(1编辑  收藏  举报