Completamento automatico - selezionare l'opzione con un clic del mouse - vuejs

voti
0

Qualche tempo fa ho creato un componente di completamento automatico in vue per un progetto in cui sono coinvolto.

Ma oggi ho rilevato un piccolo bug.

Quando seleziono l'opzione che voglio con il clic del mouse, l'opzione non viene trasmessa, come si può vedere in console.log ()che è nell'esempio. Se clicco su un'altra opzione ancora una volta, quello che apparirà in console.log ()è l'opzione selezionata in precedenza.

Se ho messo un setTimeout( () => {}, 200)già rileva ed emettono l'opzione, ma penso che non è la soluzione migliore per questo caso.

Qualche suggerimento?

esempio

const Autocomplete = {
  name: autocomplete,
  template: #autocomplete,
  props: {
    items: {
      type: Array,
      required: false,
      default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
    },
    isAsync: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  data() {
    return {
      isOpen: false,
      results: [],
      search: ,
      isLoading: false,
      arrowCounter: 0
    };
  },

  methods: {
    onChange() {
      console.log( this.search)
      // Let's warn the parent that a change was made
      this.$emit(input, this.search);
    },
    setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;
    },
    showAll() {
      this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
    },
  },
  computed: {
      filterResults() {
      // first uncapitalize all the things
      this.results = this.items.filter(item => {
        return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
      });
      
     
      return this.results;
    },
  },
  watch: {
    items: function(val, oldValue) {
      // actually compare them
      if (val.length !== oldValue.length) {
        this.results = val;
        this.isLoading = false;
      }
    }
  },
  mounted() {
    document.addEventListener(click, this.handleClickOutside);
  },
  destroyed() {
    document.removeEventListener(click, this.handleClickOutside);
  }
};

new Vue({
  el: #app,
  name: app,
  components: {
    autocomplete: Autocomplete
  }
});
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

.autocomplete {
  position: relative;
  width: 130px;
}

.autocomplete-results {
  padding: 0;
  margin: 0;
  border: 1px solid #eeeeee;
  height: 120px;
  overflow: auto;
  width: 100%;
}

.autocomplete-result {
  list-style: none;
  text-align: left;
  padding: 4px 2px;
  cursor: pointer;
}

.autocomplete-result.is-active,
.autocomplete-result:hover {
  background-color: #4aae9b;
  color: white;
}
<script src=https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js></script>
<div id=app>
  <autocomplete />

</div>

<script type=text/x-template id=autocomplete>
  <div class=autocomplete>
    <input type=text @blur=onChange v-model=search  @click=showAll />
    <ul id=autocomplete-results v-show=isOpen ref=scrollContainer class=autocomplete-results>
      <li class=loading v-if=isLoading>
        Loading results...
      </li>
      <li ref=options v-else v-for=(result, i) in filterResults :key=i @click=setResult(result, i) class=autocomplete-result :class={ 'is-active': i === arrowCounter }>
        {{ result }}
      </li>
    </ul>

  </div>
</script>

È pubblicato 14/02/2020 alle 00:00
fonte dall'utente
In altre lingue...                            


2 risposte

voti
1

Si stava utilizzando onblur evento, ma la sua licenziato quando si fa clic al di fuori e prima voce ascoltatore del onclick, in modo che il valore non è stato aggiornato.

Utilizzare onchange evento ai dati di cattura se utente digita qualcosa nella input e metodo di chiamare onChange () all'interno setResult ().

const Autocomplete = {
  name: "autocomplete",
  template: "#autocomplete",
  props: {
    items: {
      type: Array,
      required: false,
      default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
    },
    isAsync: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  data() {
    return {
      isOpen: false,
      results: [],
      search: "",
      isLoading: false,
      arrowCounter: 0
    };
  },

  methods: {
    onChange() {
      console.log( this.search)
      // Let's warn the parent that a change was made
      this.$emit("input", this.search);
    },
    setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;
      // Fire onChange, because it won't do it on blur
      this.onChange();
    },
    showAll() {
      this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
    },
  },
  computed: {
      filterResults() {
      // first uncapitalize all the things
      this.results = this.items.filter(item => {
        return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
      });
      
     
      return this.results;
    },
  },
  watch: {
    items: function(val, oldValue) {
      // actually compare them
      if (val.length !== oldValue.length) {
        this.results = val;
        this.isLoading = false;
      }
    }
  },
  mounted() {
    document.addEventListener("click", this.handleClickOutside);
  },
  destroyed() {
    document.removeEventListener("click", this.handleClickOutside);
  }
};

new Vue({
  el: "#app",
  name: "app",
  components: {
    autocomplete: Autocomplete
  }
});
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

.autocomplete {
  position: relative;
  width: 130px;
}

.autocomplete-results {
  padding: 0;
  margin: 0;
  border: 1px solid #eeeeee;
  height: 120px;
  overflow: auto;
  width: 100%;
}

.autocomplete-result {
  list-style: none;
  text-align: left;
  padding: 4px 2px;
  cursor: pointer;
}

.autocomplete-result.is-active,
.autocomplete-result:hover {
  background-color: #4aae9b;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <autocomplete />

</div>

<script type="text/x-template" id="autocomplete">
  <div class="autocomplete">
    <input type="text" @change="onChange" v-model="search"  @click="showAll" />
    <ul id="autocomplete-results" v-show="isOpen" ref="scrollContainer" class="autocomplete-results">
      <li class="loading" v-if="isLoading">
        Loading results...
      </li>
      <li ref="options" v-else v-for="(result, i) in filterResults" :key="i" @click="setResult(result, i)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
        {{ result }}
      </li>
    </ul>

  </div>
</script>

Risposto il 14/02/2020 a 00:25
fonte dall'utente

voti
1

blurè l'evento sbagliato usare qui, e credo che tu stia complicando sopra di esso. È sufficiente chiamare il vostro emitin setResult:

setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;     
      this.$emit("input", this.search);
    },
Risposto il 14/02/2020 a 00:44
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more