vuetify自动完成让芯片间的未知物品

问题描述 投票:0回答:2

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

因此,例如,用户可以键入“桑德拉”,然后选择“桑德拉·亚当斯”,然后键入“富”,然后键入一个空格,然后开始输入“约翰”和autcomplete会再次弹出,并允许用户选择“约翰史密斯”。

我已经通过在文档中的所有属性和似乎没有成为这一内置支持。

我尝试使用自定义筛选显示自动完成选项时,忽略该消息的不相关部分,而自动完成,似乎除去非芯片的内容,当它失去焦点,我无法查看属性,让我阻止这种行为。

不知道,如果autcomplete是东西使用,或者我会过得更好黑客组合框来满足这一要求,因为这似乎样品接近什么,我tryng做https://vuetifyjs.com/en/components/combobox#example-no-data,但我相信,我失去了Ajax功能附带automcomplete。

vue.js vuetify.js
2个回答
2
投票

您可以通过组合异步检索与组合框的自动完成来实现这一目标。

例如:

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>

0
投票

所以我最终建立一个renderless组件与vuetify兼容,因为它通过默认插槽,并认为任何类型的标签(textarea的,具有类型的文本,或者CONTENTEDITABLE输入),该贡支持,并允许你把任意VUE将被用来建立通过作用域插槽贡菜单项。

在未来可能会试图把它包装成一个小NPM包,谁想要以声明方式利用了VUE tribute.js以更灵活的方式比VUE贡使,但现在这里是我的概念证明

InputWithMentions.vue

<script>
import Tribute from "tributejs"
// eslint-disable-next-line 
import * as css from "tributejs/dist/tribute.css"
import Vue from "vue"

export default {
    mounted() {
       let menuItemSlot = this.$scopedSlots.default

        let tribute = new Tribute({
          menuItemTemplate: item => 
          {
              let menuItemComponent =  
                new Vue({
                    render: function (createElement) { 
                        return createElement('div', menuItemSlot({ menuItem: item }))
                    }
                })

                menuItemComponent.$mount()
                return menuItemComponent.$el.outerHTML
          },
           values: [
                {key: 'Phil Heartman', value: 'pheartman'},
                {key: 'Gordon Ramsey', value: 'gramsey'}
          ]})

          tribute.attach(this.$slots.default[0].elm.querySelectorAll('textarea, input[type=text], [contenteditable]'))
    },
    render(createElement) {
        return createElement('div', this.$slots.default)
    }
}
</script>

User.vue

   <InputWithMentions>
          <v-textarea
            box
            label="Label"
            auto-grow
            value="The Woodman set to work at once, and so sharp was his axe that the tree was soon chopped nearly through.">
          </v-textarea>
          <template slot-scope="{ menuItem }">
                <v-avatar size="20" color="grey lighten-4">
                  <img src="https://vuetifyjs.com/apple-touch-icon-180x180.png" alt="avatar">
                </v-avatar>
                {{ menuItem.string }}
          </template>
     </InputWithMentions>
© www.soinside.com 2019 - 2024. All rights reserved.