自定义指令在 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 })
}
}
})
但马上被打脸了,题主反馈报错
报错原因#
- 上述代码假定绑定的
Dom
是渲染在原生input
标签 el-input
是element-ui
自定组件,它的Dom
结构是下面这样
<div class="el-input">
<input type="text" autocomplete="off" placeholder="请输入内容" class="el-input__inner">
</div>
上述情况可在 bind 钩子体内用 el.dataset.pardon = 'test'
证实。换而言之,v-money
在 input
上可用,但在 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>
源码#
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: