vue自定义指令

vue自定义指令

Vue 自定义指令有全局注册和局部注册两种方式

全局注册

vue.use()

vue.use()本身就是一个方法,用于安装插件

通过源码看看Vue.use()的逻辑:

export function initUse (Vue: GlobalAPI) {
 Vue.use = function (plugin: Function | Object) {
  const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
  if (installedPlugins.indexOf(plugin) > -1) {
   return this
  }
  const args = toArray(arguments, 1)
  args.unshift(this)
  if (typeof plugin.install === 'function') {
   plugin.install.apply(plugin, args)
  } else if (typeof plugin === 'function') {
   plugin.apply(null, args)
  }
  installedPlugins.push(plugin)
  return this
 }
}
  • 判断插件是否注册;
  • 如果插件自带insatll属性,执行它,同时传递一个Vue构造函数作为第一个参数,以及use中的其他参数;
  • 如果插件本身就是函数,执行它,同时传递一个Vue构造函数作为第一个参数,以及use中的其他参数
  • 记录这个插件已经注册;

Vue.use(plugin)调用之后,插件的install方法就会默认接受到一个参数,这个参数就是Vue,该方法需要在调用 new Vue() 之前被调用。

使用 Vue.use() 注册插件,本质上就是执行了一个 install 方法,install 里的内容由开发者自己定义;插件不管是函数还是install方法 ,第一个参数总是vue对象

Vue.use和Vue.prototype的区别:Vue.use适用于注册vue生态内的插件,Vue.prototype适用于注册生态外的插件;一般Vue.use是有install方法的

install方法

install方法是一个用于全局注册组件、指令或插件的方法

当 install 方法被同一个插件多次调用,插件将只会被安装一次

install方法第一个参数是vue的构造器,第二个参数是可选的选项对象

Vue.derective()

注册全局组件(并不是use方法本身能注册全局组件,是此install方法或函数中的代码逻辑可以实现)

export default {
  install(Vue, option) {
    组件
    指令
    混入
    挂载vue原型
  },
}

通过 Vue.directive( id, [definition] ) 方式注册全局指令。提供install方法,然后在入口文件中进行 Vue.use() 调用

// 定义一个vue指令
Vue.directive('my-directive', {
  //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
  bind(el, binding, vnode, oldVnode) {},
  //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中),需要父节点dom时使用这个钩子
  inserted(el, binding, vnode, oldVnode) {},
  //所在组件的 VNode 更新时调用,**但是可能发生在其子 VNode 更新之前**。指令的值可能发生了改变,也可能   没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
  update(el, binding, vnode, oldVnode) {},
  //指令所在组件的 VNode **及其子 VNode** 全部更新后调用。
  componentUpdated(el, binding, vnode, oldVnode) {},
  // 只调用一次,指令与元素解绑时调用。
  unbind(el, binding, vnode, oldVnode) {},
})

// 注册 (指令函数)
Vue.directive('my-directive', function () {
  // 这里将会被 `bind` 和 `update` 调用
})

一些钩子函数:

bind:

只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作;

el是指令绑定组件对应的dombinding是我们的指令本身,包含指令namevalueexpressionarg等,vnode就是当前绑定组件对应的vnode结点,oldVnode就是vnode更新前的状态

inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值。

componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。

unbind: 只调用一次, 指令与元素解绑时调用

实际使用:自定义一个全局的v-model指令

export const myModel = {
  bind(el, binding, vnode, oldVnode) {
    // 初始化的时候赋值一次
    el.value = vnode.context[binding.expression]
    // 监听input事件
    el.addEventListener('input', (e) => {
      // vnode.context是指令所在组件的上下文环境,可以理解就是指令绑定的值所在的组件实例
      // binding.expression获取绑定的变量
      vnode.context[binding.expression] = e.target.value
    })
    //监听绑定的变量,vnode.context.$watch使用Vue实例上的watch方法
    vnode.context.$watch(binding.expression, (v) => {
      el.value = v
    })
  },
}
export default {
  install(Vue) {
    Vue.directive('myModel', myModel)
  },
}

main.js中进行注册:

import myModel from './derectives/myModel'
Vue.use(myModel)

组件中使用及测试:

    
    
    
  data() {
    return {
      iptVal: 'hello',
    }
  },
  methods: {
    test1() {
      console.log(this.iptVal)
    },
    test2() {
      this.iptVal = 'test'
    },
  },

注册局部自定义指令

组件内定义一个指令,在初始化的时候input自动聚焦

  directives: {
    focus: {
      // 指令的定义
      inserted: function (el) {
        el.focus()
      },
    },
  },

使用:

    

实用的自定义指令

copy指令

const copy = {

  bind(el, { value }) {

    el.$value = value

    el.handler = () => {

      if (!el.$value) {

        // 值为空的时候,给出提示。可根据项目UI仔细设计

        console.log('无复制内容')

        return

      }

      // 动态创建 textarea 标签

      const textarea = document.createElement('textarea')

      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域

      textarea.readOnly = 'readonly'

      textarea.style.position = 'absolute'

      textarea.style.left = '-9999px'

      // 将要 copy 的值赋给 textarea 标签的 value 属性

      textarea.value = el.$value

      // 将 textarea 插入到 body 中

      document.body.appendChild(textarea)

      // 选中值并复制

      textarea.select()

      const result = document.execCommand('Copy')

      if (result) {

        console.log('复制成功') // 可根据项目UI仔细设计

      }

      document.body.removeChild(textarea)

    }

    // 绑定点击事件,就是所谓的一键 copy 啦

    el.addEventListener('click', el.handler)

  },

  // 当传进来的值更新的时候触发

  componentUpdated(el, { value }) {

    el.$value = value

  },

  // 指令与元素解绑的时候,移除事件绑定

  unbind(el) {

    el.removeEventListener('click', el.handler)

  },

}

export default copy

单行文本溢出加title

const ellipsis = {

  inserted: function (el, binding) {

    // 设置超出隐藏,可以优化下,让其支持多行

    // el.style.overflow = 'hidden'

    // el.style.textOverflow = 'ellipsis'

    // el.style.whiteSpace = 'nowrap'

    // 还是设置个全局样式吧

    el.classList.add('one-line-ellipsis')

    // 鼠标移入提示title

    if (el.clientWidth < el.scrollWidth) {

      el.title = el.innerHTML

    }

  },

}

export default ellipsis

批量注册指令

import copy from './copy'

import ellipsis from './ellipsis'

const directives = {

  copy,

  ellipsis,

}

export default {

  install(Vue) {

    Object.keys(directives).forEach((key) => {

      Vue.directive(key, directives[key])

    })

  },

}

Vue.use()注册

import Directives from './derectives/index'

Vue.use(Directives)

你可能感兴趣的:(vue,前端,vue)