首页 > 解决方案 > vuetify 自动完成允许芯片之间的未知项目

问题描述

我正在尝试修改https://vuetifyjs.com/en/components/autocompletes#example-scoped-slots上的示例代码,以允许任意内容与芯片之间的任何自动完成项目不匹配(因此用户可以在消息中标记其他用户类似于 slack 和 facebook)

例如,用户可以输入“Sandra”,然后选择“sandra adams”,然后输入“foo”,然后输入另一个空格并开始输入“John”,然后自动完成功能将再次弹出并允许用户选择“John史密斯”。

我已经浏览了文档中的所有属性,并且似乎不支持此内置功能。

我尝试在显示自动完成选项时使用自定义过滤来忽略消息的不相关部分,但自动完成似乎在失去焦点时会删除非芯片内容,并且我看不到允许我阻止此行为的属性。

不确定 autcomplete 是否是要使用的东西,或者我是否最好破解组合框来满足这个要求,因为这个示例似乎更接近我正在尝试做的事情https://vuetifyjs.com/en/components /combobox#example-no-data,但后来我相信我失去了自动完成附带的 ajax 功能。

标签: vue.jsvuetify.js

解决方案


您可以通过将自动完成的异步搜索与组合框相结合来实现这一点。

例如:

new Vue({
  el: '#app',
  data: () => ({
    activator: null,
    attach: null,
    colors: ['green', 'purple', 'indigo', 'cyan', 'teal', 'orange'],
    editing: null,
    descriptionLimit: 60,
    index: -1,
    nonce: 1,
    menu: false,
    count: 0,
    model: [],
    x: 0,
    search: null,
    entries: [],
    y: 0
  }),
   computed: {
      fields () {
        if (!this.model) return []

        return Object.keys(this.model).map(key => {
          return {
            key,
            value: this.model[key] || 'n/a'
          }
        })
      },
      items () {
        return this.entries.map(entry => {
          const Description = entry.Description.length > this.descriptionLimit
            ? entry.Description.slice(0, this.descriptionLimit) + '...'
            : entry.Description

          return Object.assign({}, entry, { Description })
        })
      }
    },

  watch: {
    search (val, prev) {
    
        // Lazily load input items
        axios.get('https://api.publicapis.org/entries')
          .then(res => {
          console.log(res.data)
            const { count, entries } = res.data
            this.count = count
            this.entries = entries
          })
          .catch(err => {
            console.log(err)
          })
          .finally(() => (this.isLoading = false))
          
      /*if (val.length === prev.length) return

      this.model = val.map(v => {
        if (typeof v === 'string') {
          v = {
            text: v,
            color: this.colors[this.nonce - 1]
          }

          this.items.push(v)

          this.nonce++
        }

        return v
      })*/
    },
     model (val, prev) {
        if (val.length === prev.length) return

        this.model = val.map(v => {
          if (typeof v === 'string') {
            v = {
              Description: v
            }

            this.items.push(v)

            this.nonce++
          }

          return v
        })
      }
  },

  methods: {
    edit (index, item) {
      if (!this.editing) {
        this.editing = item
        this.index = index
      } else {
        this.editing = null
        this.index = -1
      }
    },
    filter (item, queryText, itemText) {
      const hasValue = val => val != null ? val : ''

      const text = hasValue(itemText)
      const query = hasValue(queryText)

      return text.toString()
        .toLowerCase()
        .indexOf(query.toString().toLowerCase()) > -1
    }
  }
})
<link href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons' rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js" integrity="sha256-mpnrJ5DpEZZkwkE1ZgkEQQJW/46CSEh/STrZKOB/qoM=" crossorigin="anonymous"></script>

<div id="app">
<v-app>
<v-content>
        <v-container>
<v-combobox
    v-model="model"
    :filter="filter"
    :hide-no-data="!search"
    :items="items"
    :search-input.sync="search"
    hide-selected
    label="Search for an option"
    :allow-overflow="false"
    multiple
    small-chips
    solo
    hide-selected
    return-object
    item-text="Description"
    item-value="API"
    :menu-props="{ closeOnClick: false, closeOnContentClick: false, openOnClick: false, maxHeight: 200 }"
    dark
  >
   <template slot="no-data">
      <v-list-tile>
        <span class="subheading">Create</span>
        <v-chip
          label
          small
        >
          {{ search }}
        </v-chip>
      </v-list-tile>
    </template>
    <template
      v-if="item === Object(item)"
      slot="selection"
      slot-scope="{ item, parent, selected }"
    >
      <v-chip
        :selected="selected"
        label
        small
      >
        <span class="pr-2">
          {{ item.Description }}
        </span>
        <v-icon
          small
          @click="parent.selectItem(item)"
        >close</v-icon>
      </v-chip>
    </template>
    <template
      slot="item"
      slot-scope="{ index, item, parent }"
    >
      <v-list-tile-content>
        <v-text-field
          v-if="editing === item.Description"
          v-model="editing"
          autofocus
          flat
          hide-details
          solo
          @keyup.enter="edit(index, item)"
        ></v-text-field>
        <v-chip
          v-else
          dark
          label
          small
        >
          {{ item.Description }}
        </v-chip>
      </v-list-tile-content>
    </template>
  </v-combobox>
  </v-container>
  </v-content>
  </v-app>
</div>


推荐阅读