自定义指令在 el-input 节点上无效解决方案

本文旨在解决自定义千分位指令在el-input上初始化失效的问题

问题简述

旨在解决社区问答 自定义指令修改底层 dom 元素,没有效果

页面首次加载后

要达成的效果

初始化时是没有效果的,但是 input丢失焦点时有效

解决思路

通常想用的是过滤器,但考虑到非普通值,是input节点值的处理,于是自然用起了自定义指令的钩子函数bind,通过它给节点绑定事件,处理格式化(XEUtils是一个工具库,章末给出链接),更改input.value

bind:只调用一次,指令第一次绑定到元素时调用,可进行初始化设置

    Vue.directive('money', {
        // 初始化设置
        bind: function (el, binding, vnode, oldVnode) {
            el.value = XEUtils.commafy(el.value, { digits: binding.arg })
            el.onblur = () => {
                el.value = XEUtils.commafy(el.value, { digits: binding.arg })
            }
        }
    })

但马上被打脸了,题主反馈报错

报错原因

  1. 上述代码假定绑定的 Dom 是渲染在原生 input 标签
  2. el-inputelement-ui自定组件,它的Dom结构是下面这样
<div class="el-input">
    <input type="text" autocomplete="off" placeholder="请输入内容" class="el-input__inner">
</div>

上述情况可在bind钩子体内用 el.dataset.pardon = 'test'证实。换而言之,v-moneyinput上可用,但在el-input上无效,因其绑定的是div 而非 input元素。

Dom布局

   <div id="app">
        <h1>{{ money }}</h1>
        <p>v-money:2 vue指令可见值:<input v-model=" money" v-money:2></p>
        <p>thds(1)千分位过滤器: {{ money | thds(1) }}</p>
        <el-input v-model="money" placeholder="请输入内容" autosize v-money:2></el-input>
    </div>

关键

渲染树,子节点渲染完成回溯父树,重复直到根,然后替换#app节点内容
bind只在指令绑定节点时被调用一次,它不能保证子节点ok了。好在vue提供了

inserted:被绑定元素插入父节点时调用

换而言之,若在渲染期,子节点编译完成后插入父,然后父节点编译,直到根。因此可以这样干,让v-money指令兼容el-input,而不仅仅是input

   Vue.directive('money', {
        inserted: function (el, binding) {
            // 指令作用在 element-input 节点,对应原生 div.el-input (真实input节点的父节点)
            if (el.tagName.toLocaleUpperCase() !== 'INPUT') {
                el = el.getElementsByTagName('input')[0]
            }
            el.value = XEUtils.commafy(el.value, { digits: binding.arg })
            el.onblur = () => {
                el.value = XEUtils.commafy(el.value, { digits: binding.arg })
            }
        }
    })

全局过滤器

    // 过滤器参数 通常与格式化,与值相关
    Vue.filter('thds', function (value, digits) {
        if (!value) return ''
        return XEUtils.commafy(value, { digits })
    })

资源

    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/xe-utils"></script>

源码

el-input 自定义千分位指令 v-money

本作品采用《CC 协议》,转载必须注明作者和本文链接
pardon110
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
开发者 @ 社科大
文章
102
粉丝
12
喜欢
82
收藏
38
排名:102
访问:4.6 万
私信
所有博文