接手的项目中多处使用了一个按照设计稿样式的搜索框,为了提高复用率,对其进行封装。
以此文章做工作记录
按照项目的需要,要实现的功能比较简单:
代码关键点:
v-model
正常工作众所周知v-model
是输入框双向绑定的语法糖,本质上是
:value="value" @input="value = $event.target.value"
组件使用v-model,也就是相当于给组件绑定了一个value值,和一个input事件。
因此在组件内接收即可:
export default {
name:"SearchInput",
props:{
value: [String, Number]
}
}
然后对组件内的input标签绑定好value值,这里的@input直接$emit
触发外部的input事件,并且传入参数$event
。
v-bind="$attrs"
用于值的绑定穿透,能直接把没有在props声明的其他绑定值,直接传递到内部的el-input框,只要有这个,直接在组件外面绑定的placeholder值,class值都会直接同步到这里。
v-on="$listeners"
同理,指的是事件的绑定穿透,另外还有$scopedSlots
插槽穿透,这里并不需要所以不拓展说明。
<el-input
:value="value"
@input="$emit('input', $event)"
v-bind="$attrs"
>
el-input>
这样外部的v-model就可以正常工作了。
按照项目原本的需求,补充自定义的样式,还有el-input的插槽。
至于清空输入的按钮,按照设计稿,没有使用原生的clearable属性,而是添加作为el-input的suffix
插槽。
<i slot="prefix"><img :src="CommonImg.search" alt="">i>
<i slot="suffix" v-if="empty" class="el-icon-close" @click="handleClear">i>
<el-button slot="append" v-if="hasBtn" type="primary" @click="$emit('enter',value)">搜索el-button>
搜索按钮根据外部传入的参数决定:
props:{
value: [String, Number],
hasBtn:Boolean
}
清空输入图标的出现按照当前是否有输入决定
由于vue的单向数据流,不提倡在子组件内部直接修改父组件的参数,因此清空输入不是给value
清空,而是是触发外部的函数来进行清除。
watch:{
value(newValue){
if(newValue !== ''){
this.empty = true;
}else{
this.empty = false;
}
},
},
methodes:{
//清除输入
handleClear() {
this.$emit('input', '');
this.$emit('change', '');
this.$emit('clear');
},
}
这里根据需要添加了一些操作和回调…
此外,组件内还可以更改外界v-model绑定的变量
虽然默认绑定值是value
,事件是input
但可以在vc配置里面的model属性,修改为checked
和change
等用于其他作用。
<template>
<div>
<el-input
:value="value"
@input="$emit('input', $event)"
v-bind="$attrs"
@mouseenter="hovering = true"
@mouseleave="hovering = false"
@focus="handleFocus"
@blur="handleBlur"
@keyup.native.enter="handleEnter"
>
<i slot="prefix"><img :src="CommonImg.search" alt="">i>
<i slot="suffix" v-if="empty" class="el-icon-close" @click="handleClear">i>
<el-button slot="append" v-if="hasBtn" type="primary" @click="$emit('enter',value)">搜索el-button>
el-input>
div>
template>
<script>
import {CommonImg} from '@/assets'
export default {
name:"SearchInput",
props:{
value: [String, Number],
hasBtn:Boolean
},
data(){
return {
CommonImg,
hovering: false,
focused: false,
empty:false,
}
},
watch:{
value(newValue){
if(newValue !== ''){
this.empty = true;
}else{
this.empty = false;
}
},
},
methods:{
handleFocus(event) {
this.focused = true;
this.$emit('focus', event);
},
handleBlur(event) {
this.focused = false;
this.$emit('blur', event);
},
handleEnter(){
// 这里可以包一个防抖 handleEnter:debounce(function(){ ... })
if(this.value === '') return;
this.$emit('enter',this.value)
},
handleClear() {
this.$emit('input', '');
this.$emit('change', '');
this.$emit('clear');
},
},
}
script>
<style lang="less" scoped>
//...样式自定义
style>
点击搜索按钮,使用回车进行查询的类型:
<SearchInput v-model="warningInfoSearchInput"
placeholder="请输入任务名称检索" hasBtn
@enter="warningInfoSearch"/>
输入内容就查询的类型:
<SearchInput placeholder="请输入关键字检索"
v-model="searchInfo" @input="changeSearchInfo" />