问题:实现input搜索框实时检索的功能,支持回车或选中后生成tag标签,公司设计出功能需求后,在市场上没找到差不多类似的,只能手撸一个了
解决方法:
1、参考网上文章:input中回车生成标签实现及分析_vue input中回车生成标签-优快云博客
但是会出现 appendchild 添加的li元素点击事件失效问题,使用事件委托也无法解决,最后采用for of 循环标签处理完成,细节部分还需要优化,比如外部传入组件的下拉联想数组可以替换,模糊搜索时判定laber名称返回value值等等
效果图

话不多说直接上代码
<template>
<!-- class="h32InputRadius" -->
<div class="TagInput">
<el-select
v-model="tagsArr"
multiple
collapse-tags
ref="selectw"
@focus = 'selectFocus()'
placeholder="请选择">
</el-select>
<el-dialog :title="title" :visible.sync="voidVisible" width="480px" append-to-body>
<!-- 外层div -->
<div class="arrbox" @click="onclick">
<div style="display: flex;justify-content: start;align-items: start;flex-wrap: wrap">
<!-- 标签 -->
<div v-for="(item,index) in tagsArr" :key="index" class="spanbox">
<span class="tagspan">{{item}}</span>
<i class="el-tag__close el-icon-close" @click="removeTag(index,item)"></i>
</div>
<!-- 输入框 -->
<div>
<input
:placeholder="placeholder"
v-model="currentval"
@keyup.enter="addTags"
:style="inputStyle"
class="inputTag blueInput"
ref="inputTag"
type="text"
/>
<ul id="list">
<li index="1" v-for="(v,i) in data" :key="i" class="oLi" @click="liSelect(v)">{{ v }}</li>
</ul>
</div>
</div>
<!-- 清除按钮,总数显示 -->
<div class="bottom">
<div>{{ tagsArr.length }}</div>
<div :style="{color:tagsArr.length>0?'#7EC050':'#999'}" style="cursor: pointer;" @click="tagsArr = []">清除</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<JcButton type="normal" @click="submit()">确 定</JcButton>
</span>
</el-dialog>
</div>
</template>
<script>
import JcButton from './JcButton.vue'
export default {
name: 'TagInput',
props: {
parentArr: {
type: Array,
default () {
return []
}
},
limit: { // 最多生成标签数
type: Number,
default: 100
},
placeholder: {
type: String,
default: '请输入'
},
title:{
type:String,
default:'选择客户'
}
},
components: {
JcButton
},
created () {
if (this.parentArr.length) {
this.tagsArr = this.parentArr
}
},
data () {
return {
voidVisible:false,
currentval: '',
tagsArr: [],
inputLength: '',
data:[]
}
},
watch: {
tagsArr () {
this.$emit('change', this.tagsArr)
},
currentval (val) {
console.log(val);
// 实时改变input输入框宽度,防止输入内容超出input默认宽度显示不全
this.inputLength = this.$refs.inputTag.value.length * 12 + 20;
let fruits = ["中国","日本","美国","俄罗斯","加拿大","英国","澳大利亚","西班牙","德国","孟买加","阿拉伯","印度","印度尼西亚"];
this.data = this.searchByIndexOf(val, fruits);//模糊搜索,返回数组中存在的数据
},
parentArr () {
this.tagsArr = this.parentArr.length ? this.parentArr : []
}
},
computed: {
inputStyle () {
let style = {};
style.width = `${this.inputLength}px`;
return style;
},
},
mounted() {
this.tagsArr = this.parentArr;
},
methods: {
removeTag (index, item) {
this.tagsArr.splice(index, 1)
},
addTags() {
if (this.tagsArr.length === this.limit) {
this.$emit('on-limit', true);
return;
}
if (this.tagsArr.indexOf(this.currentval) > -1) {
this.$message.warning('该标签已存在')
this.$emit('on-repeat', true);
return;
}
// 格式校验
// let reg = /^[1-9]+[0-9]*$/
// if (!reg.test(this.currentval)) {
// alert('格式不正确!');
// this.currentval = '';
// return;
// }
// 当输入值用,或空格隔开时
if(this.currentval.indexOf(",") != -1){
this.currentval.split(',').forEach(element => {
// 如果输入的数据存在,则跳过不添加
if (this.tagsArr.indexOf(element) > -1) {
}else{
// 去除前后空格,空项不添加
if(element == ' '){
}else{
this.tagsArr.push(element.trim())
}
}
});
}else if(this.currentval.indexOf(" ") != -1){
this.currentval.split(' ').forEach(element => {
// 如果输入的数据存在,则跳过不添加
if (this.tagsArr.indexOf(element) > -1) {
}else{
// 去除前后空格,空项不添加
if(element == ' '){
}else{
this.tagsArr.push(element.trim())
}
}
});
}else{
// 去除前后空格,空项不添加
if(this.currentval == ' ' || this.currentval == ''){}else{
this.tagsArr.push(this.currentval.trim());
}
}
this.currentval = '';
},
onclick() {
this.$nextTick(()=>{
this.$refs.inputTag.focus();
})
},
selectFocus(){
this.voidVisible = true
this.$refs.selectw.visible = false;
},
submit(){
this.addTags()
this.voidVisible = false
},
//模糊查询:利用字符串的indexOf方法
searchByIndexOf(keyWord, list){
if(!(list instanceof Array)){
return ;
}
if(keyWord == ""){
return [];
}else{
var len = list.length;
var arr = [];
for(var i=0;i<len;i++){
//如果字符串中不包含目标字符会返回-1
if(list[i].indexOf(keyWord)>=0){
arr.push(list[i]);
}
}
return arr;
}
},
liSelect(value){
this.currentval = value
this.addTags()
},
}
}
</script>
<style lang="less">
.TagInput{
width: 100%;
font-size:0;
height: 32px;
.el-select{
width: 100%;
height: 32px !important;
.el-input.el-input--suffix{
font-size:0;
height: 32px !important;
.el-input__inner{
height: 32px !important;
}
.el-input__suffix{
height: 32px !important;
line-height: 32px !important;
}
}
}
}
.el-dialog {
.el-dialog__header {
padding: 28px 24px 16px !important;
border-bottom: none !important;
.el-dialog__title {
font-size: 18px !important;
color: #1d2129 !important;
}
.el-dialog__close {
font-size: 18px !important;
color: #1d2129 !important;
}
}
.el-dialog__body {
padding: 0 24px 14px !important;
padding-top: 0px !important;
/* 外层div */
.arrbox {
height: 194px;
width: 100%;
box-sizing:border-box;
background-color: white;
border: 1px solid #dcdee2;
border-radius: 4px;
font-size: 12px;
text-align: left;
padding-left: 5px;
word-wrap: break-word;
overflow: hidden;
overflow-y: auto;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
// align-items: center;
.bottom{
height: 18px;
display: flex;
justify-content: space-between;
align-items: center;
div{
font-size: 13px;
color: #999999;
}
}
}
/* 标签 */
.spanbox {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
margin: 4px 8px 4px 0;
padding: 3px 6px;
background-color: #f7f7f7;
border: 1px solid #e8eaec;
border-radius: 3px;
.el-tag__close.el-icon-close {
color: #A7AFB8;
-ms-flex-negative: 0;
flex-shrink: 0;
cursor: pointer;
margin-left: 5px;
}
.el-tag__close.el-icon-close:hover{
color: #333;
}
.tagspan {
position: relative;
display: inline-block;
color: #333333;
font-size: 13px;
cursor: pointer;
opacity: 1;
vertical-align: middle;
overflow: hidden;
transition: 0.25s linear;
}
}
/* input */
.inputTag {
font-size: 13px;
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0;
width: auto;
min-width: 300px;
vertical-align: top;
height: 32px;
color: #495060;
line-height: 32px;
}
}
.el-textarea__inner {
margin-top: 0px !important;
}
}
.blueInput{
position: absolute;
}
/* 搜索下拉框*/
#list {
// list-style: none;
// margin: 0;
// padding: 0;
width:300px;
height: 115px;
overflow-y: auto;
overflow-x: hidden;
display: inline-block;
position: relative;
top: 32px;
left: 0;
}
ul#list li {
margin: 0;
padding: 10px;
cursor: pointer;
}
ul#list li:hover {
background-color: #e8eaec;
width:300px;
}
</style>
2万+





