autocomplete组件 = <input> + <datalist>

 

组件库:bootstrap-vue

doc:https://bootstrap-vue.js.org/docs/components/table/

input组件用的是bootstrap-vue提供的组件,换成别的也一样

实际上,bootstrap-vue最新版本中,提供了datalist相关组件,但由于升版本影响太多既存代码,所以选择了自己写一个

 

AutoComplete.vue

<template src="./autoComplete.html"></template>
<script src="./autoComplete.js"></script>

autoComplete.html

<div class="datelistStyle">
  <b-form-input type="text" list="datalist1"
                :value="seletedText" :options="options"
                @blur="onBlur($event.target)"></b-form-input>
  <datalist id="datalist1">
    <option v-for="item in options">{{item[textField]}}</option>
  </datalist>
</div>

autoComplete.js

export default {
    name: "auto-complete",
    props: {
        value: {
            type: Number
        },
        options: {
            type: Array,
            required: true
        },
        valueField: {
            type: String,
            required: true
        },
        textField: {
            type: String,
            required: true
        }
    },
    data() {
        return {
            seletedText: "",
            textList: []
        }
    },
    watch: {
        options(newVal, oldVal) {
            for (var i = 0; i < this.options.length; i++) {
                if (this.value == this.options[i][this.valueField]) {
                    this.seletedText = this.options[i][this.textField];
                }
            }
        }
    },
    // 这里遇到了一个问题,属性options在mounted里一直都没有值
    // 稍微调查了一下,大概是因为父组件调用子组件是异步请求,这时父组件传入的值还是初始值
    // 最后通过添加watch解决了这个问题
//    mounted() {
//        for (var i = 0; i < this.options.length; i++) {
//            if (this.value == this.options[i][this.valueField]) {
//                this.seletedText = this.options[i][this.textField];
//            }
//        }
//    },
    methods: {
        onBlur: function(e) {
            this.getTextList();
            if (this.textList.indexOf(e.value.trim()) <= -1) {
                e.value = "";
            } else {
                e.value = e.value.trim();
            }
            this.$emit("input", e.value);
            this.getSelectedValue(e.value);
        },
        getTextList: function() {
            if (this.textList.length <= 0) {
                for (var i = 0; i < this.options.length; i++) {
                    this.textList.push(this.options[i][this.textField]);
                }
            }
        },
        getSelectedValue: function(selectedText) {
            for (var i = 0; i < this.options.length; i++) {
                if (selectedText == this.options[i][this.textField]) {
                    this.$emit("input", this.options[i][this.valueField]);
                }
            }
        }
    }
};

对应的css

.datelistStyle input {
  width: 245px;
  display: inline-block;
  height: calc(1.5em + 0.75rem + 2px);
  padding: 0.375rem 1.75rem 0.375rem 0.75rem;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
  color: #495057;
  vertical-align: middle;
  background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
  background-size:8px 10px;
  border: 1px solid #ced4da;
  border-radius: 0.25rem;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
/* 去掉chrome datalist自带的箭头 */
.datelistStyle input::-webkit-calendar-picker-indicator{
  display: none;
  -webkit-appearance: none;
}

--------------------------------------------------------------------------------------

组件调用

html

<auto-complete v-model="selectedId" :options="options"
               valueField="id" textField="name">
</auto-complete>

js

import AutoComplete from '../components/autoComplete/AutoComplete.vue';

export default {
    data() {
        return {
            options: [{id: 1, name: "name1"},
                     {id: 2, name: "name2"}],
            selectedId: 1
        }
    },
    components: {
        AutoComplete
    },
    created: function() {
    },
    methods: {
    }
};

 

Logo

前往低代码交流专区

更多推荐