前言
假如有個(gè)需求,輸入框在輸完內(nèi)容后進(jìn)行判斷是否為純空格,如果是純空格,就要清空輸入框,對(duì)于el-form
組件的表單驗(yàn)證,在rules
中的required
為true
時(shí),純空格也能檢驗(yàn)通過,于是開始對(duì)el-input組件進(jìn)行二次封裝。
1、一般說到二次封裝,很多人是這樣封裝的,我以前也是:
- 父級(jí)
main.vue
<template>
<my-input v-model="value"></my-input>
</template>
<script>
import MyInput from './my-input.vue;
export default {
components: {
MyInput
},
data() {
return {
value: ''
}
}
}
</script>
- 子組件
my-input.vue
<template>
<el-input></el-input>
</template>
你會(huì)發(fā)現(xiàn)這個(gè)輸入框你不能輸入任何東西,因?yàn)樽咏M件my-input并沒有支持任何傳參,于是接著改:
<template>
<el-input :value="value" @input="handleInput" @change="handleChange"></el-input>
</template>
<script>
export default {
props() {
value: [String, Number]
},
methods: {
handleInput() {
this.$emit('input', $event)
},
handleChange(value) {
//處理純空格
if (Object.prototype.toString.call(value) === '[object String]' && value.trim() === '') {
this.$emit('input', '')
}
}
}
}
</script>
如果要全部輸入框都支持“不允許輸入純空格”,就將它封裝成全局組件,看似完美,但是你會(huì)發(fā)現(xiàn),el-input組件除了可以進(jìn)行值的雙向綁定,它還支持size、readonly、disabled...等18個(gè)屬性,7個(gè)事件,于是接著寫一大堆“中間代碼”來繼承原有el-input的各種屬性、事件。
2、改進(jìn): 利用 v-bind="$attrs"
和 v-on="$listeners"
來“繼承” el-input
組件的屬性和事件
<template>
<el-input v-bind="$attrs" v-on="$listeners" @change="handleChange"></el-input>
</template>
<script>
export default {
methods: {
handleChange(value) {
if (Object.prototype.toString.call(value) === '[object String]' && value.trim() === '') {
this.$emit('input', '')
}
}
}
}
</script>
如果將這樣的組件覆蓋原有的el-input,那就會(huì)出問題,它并不支持插槽...,有想翻桌子的沖動(dòng)。那么,有沒有一種只想改我想改的部分,其它的不動(dòng),不需要自己手寫代碼去“繼承”呢?
3、使用 extends 選項(xiàng)對(duì)組件進(jìn)行擴(kuò)展
- 雛形
<template>
//這里復(fù)制element-ui中el-input的源碼,太長了,不好展示
</template>
<script>
import { Input } from 'element-ui'
export default {
extends: Input,
created() {
this.$on('change', (value)=> {
if (Object.prototype.toString.call(value) === '[object String]' && value.trim() === '') {
this.$emit('input', '')
}
})
}
}
</script>
這樣就能對(duì)組件各種改改改;
template里面的內(nèi)容是復(fù)制過來的,一般不需要改動(dòng),如果需要改的話當(dāng)然也可以這么做。
- 改進(jìn)
如果不需要template
,那就寫在“*.js”
文件中
import Vue from 'vue';
import ElementUI from 'element-ui';
Vue.component('el-input', {
extends: ElementUI.Input,
created() {
this.$on('change', (value)=> {
if (Object.prototype.toString.call(value) === '[object String]' && value.trim() === '') {
this.$emit('input', '')
}
})
}
})
這下簡潔多了!
- 局部組件
<template>
<div>
內(nèi)容...
<my-input></my-input>
</div>
</template>
<script>
import { Input } from 'element-ui'
export default {
components: {
myInput: {
extends: Input,
...
}
}
}
</script>