123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- <template>
- <!-- 联想组件 -->
- <div class="association-container" ref="association">
- <el-input
- class="association-input"
- :value="value"
- :placeholder="placeholder"
- :suffix-icon="suffixIcon"
- :clearable="clearable"
- @focus="preSearch.focus = true"
- @blur="onBlur"
- @input="onInput"
- ></el-input>
- <div
- class="pre-search-list"
- :style="{ top: preSearch.top + 'px' }"
- v-show="preSearchListShow"
- @mouseout="preSearch.hover = false"
- @mouseover="preSearch.hover = true"
- >
- <div
- class="pre-search-item ellipsis"
- v-for="(item, index) in preSearch.list"
- :key="index"
- @click="selectSearchItem(item)"
- >
- {{ item.value }}
- </div>
- </div>
- </div>
- </template>
- <script>
- import { Input } from 'element-ui'
- import { debounce } from 'lodash'
- export default {
- name: 'AssociationInput',
- components: {
- [Input.name]: Input
- },
- props: {
- value: {
- type: String,
- default: ''
- },
- // 是否立即触发一次联想
- immediateAssociation: {
- type: Boolean,
- default: false
- },
- fetchAsync: {
- type: Function
- },
- clearable: {
- type: Boolean,
- default: false
- },
- suffixIcon: {
- type: String,
- default: 'el-icon-search'
- },
- placeholder: {
- type: String,
- default: ''
- }
- },
- data() {
- return {
- preSearch: {
- top: 0,
- hover: false,
- focus: false,
- list: []
- }
- }
- },
- computed: {
- preSearchListShow() {
- return (
- this.value.trim().length >= 2 &&
- this.preSearch.list.length &&
- (this.preSearch.focus || this.preSearch.hover)
- )
- }
- },
- created() {
- if (this.immediateAssociation) {
- this.preSearchList()
- }
- },
- mounted() {
- this.calcPreSearchTop()
- },
- methods: {
- calcPreSearchTop() {
- const { association } = this.$refs
- this.preSearch.top = association.clientHeight + 2
- },
- onInput(e) {
- this.$emit('input', e)
- this.preSearchList(e)
- },
- onBlur(e) {
- this.$emit('blur', e)
- this.$nextTick(() => {
- this.preSearch.focus = false
- })
- },
- preSearchList: debounce(async function (e) {
- const params = {
- value: this.value
- }
- if (params.value.length < 2) return
- let list = []
- if (this.fetchAsync) {
- try {
- const cbArr = await this.fetchAsync(params)
- if (Array.isArray(cbArr)) {
- list = cbArr
- }
- } catch (error) {
- console.log(error)
- }
- }
- this.preSearch.list = list
- }, 300),
- selectSearchItem(item) {
- this.$emit('select', item)
- // 选择后马上关闭备选列表
- this.$nextTick(() => {
- this.preSearch.focus = false
- this.preSearch.hover = false
- })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- ::v-deep {
- .el-input__inner {
- width: 326px;
- height: 30px;
- line-height: 30px;
- border-color: #e0e0e0;
- }
- .el-input__icon {
- line-height: 30px;
- }
- }
- .association-container {
- position: relative;
- display: inline-block;
- }
- .pre-search-list {
- padding: 10px 0;
- position: absolute;
- z-index: 6;
- width: 100%;
- background: #fff;
- box-shadow: 0 0 10px rgb(0, 0, 0, 0.1);
- border-radius: 4px;
- overflow: hidden;
- }
- .pre-search-item {
- padding: 0 20px;
- width: 100%;
- font-size: 14px;
- line-height: 34px;
- color: #606266;
- box-sizing: border-box;
- transition: all 0.3s;
- cursor: pointer;
- }
- .pre-search-item:hover {
- color: #1d1d1d;
- background-color: #ececec;
- }
- </style>
|