javascript - Eveniment blur pentru componenta personalizată Vue


Ce am
Un DropDown personalizat cu un câmp de text pentru filtrare deasupra. DropDown-ul poate fi deschis independent de câmpul de text pentru filtrare.

Ceea ce vreau
Comportamentul dorit ar fi ca meniul derulant să se închidă atunci când câmpul de filtrare își pierde focusul și, de asemenea, când dau click cu mouse-ul în afara meniului derulant, astfel încât meniul derulant să își piardă focusul.

Ceea ce am încercat

  • Leagă-te de evenimentul blur pe elementul meu div rădăcină în control, care nu se declanșează deloc.
  • De asemenea, nu am putut găsi nimic despre metodele componentelor interne pe care aș putea să le suprascriu.

Cod

  <div @blur="onRootLostFocus">
    ...
  </div>

  ...
  ...
  ...

  onRootLostFocus() {
    console.log('LostFocus');
    this.deactivateSearchPanel();
    this.deactivateSelectionPanel();
  }

Soluție

Am ratat faptul că un div are nevoie de tabindex="0" pentru a putea fi focalizat, acest lucru mi-a rezolvat problema

Răspuns #1

Ceva de genul acesta?

Răspuns: Trebuie să setezi tabindex="0" pentru a-l face focalizabil.

Aici un dropdown personalizat cum ai putea să-l faci:

Vue.component("dropdown", {
   props: ["value"],
   data(){
      return {
         open: false,
         options: ["BMW", "Fiat", "Citroen", "Audi", "Tesla"]
      }
   },
   methods: {
      toggleDropdown() {
         this.open = !this.open;
      },
      closeDropdown(){
         this.open = false;
      },
      selectOption(option) {
         this.$emit("input", option);
      }
   },
   template: `<div class="dropdown">
   <div @blur="closeDropdown" tabindex="0" ref="dropdown" @click="toggleDropdown" class="select">
   {{ value }}
   </div>
   <div class="options" :style="{'max-height': open ? '300px' : '0px'}">
      <div v-for="option in options" @mousedown="selectOption(option)" class="option">
         {{ option }}
      </div>
   </div>
</div>`
})

new Vue({
   el: "#app",
   data: {
      selectedCar: "BMW"
   }
})
.dropdown {
   width: 200px;
   position: relative;
}

.select {
   height: 40px;
   position: absolute;
   left: 0;
   width: 100%;
   background: green;
   display: flex;
   justify-content: center;
   align-items: center;
   color: white;
   cursor: pointer;
}
.option {
   width: 100%;
   height: 40px;
   background: darkgreen;
   color: white;
   display: flex;
   justify-content: center;
   align-items: center;
   cursor: pointer;
}
.option:hover {
   background: green;
}
.options {
   overflow: hidden;
   transition: max-height 200ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"> <p>
   {{ selectedCar }}</p>
   <dropdown v-model="selectedCar" />
  
</div>