The preface

It has been almost a month since the last article was published. Recently, due to the project, I have been busy, so I have been cut off. But don’t care about these small details and get to the point.

In order, this is the turn of the Select dropdown selector, which I briefly glance at is really quite complex, so the Select may take several articles to share this, anyway, I looked at the code is not difficult to do not know things are really much ah. A single select.vue is nearly 1000 lines, and the total can be more than 2000 lines, but there are many points worth learning.

Structure analysis

The select component contains navigation-mixin.js, option-group.vue, option.vue, select-dropdown.vue, select.vue and other files

As usual we’ll do it in three ways but this time we’ll do it in multiple ways, and we’ll also look at the select code with some questions

In order to understand more thoroughly, the main content of this chapter is to share some of the main things

Dom structure

 <div class="el-select">
    // Use the el-tag format to display multiple selections of text
    <div class="el-select__tags">
      <span>// There are two tags: one is to show the first of the current multiple selections // the other is to show the form of +1 (official website basic multiple selections of the first appearance)<el-tag></el-tag>
        <el-tag></el-tag>
      </span>// Loop through each selected TAB<transition-group @after-leave="resetInputHeight" v-if=! "" collapseTags">
        <el-tag></el-tag>
      </transition-group>// A textable query box<input type="text" class="el-select__input">
    </div>// Echo during a single option<el-input ref="reference" v-model="selectedLabel" type="text">
          <template slot="prefix" v-if="$slots.prefix">
               <slot name="prefix"></slot>
          </template>// Clear and down arrow buttons<template slot="suffix">The two little buttons here use show and if, respectively<i v-show=! "" showClose" ></i>
               <i v-if="showClose"></i>
          </template>
     </el-input>// Drop down menu<el-select-menu>
        <el-scrollbar>// Drop down each option<el-option></el-option>
          <slot></slot>
        </el-scrollbar>// Empty or loading<template>
          <slot></slot>
          <p></p>
        </template>
        
      </el-select-menu>
  </div>
Copy the code

In fact, as long as the outer several large tags are divided into categories, through the corresponding class and those attributes of the logical judgment can be seen to see what each corresponding Dom tag is.

Usage function and problem analysis

First, function usage

  • Basic usage
  • There are disable options
  • Disabled state
  • You can clear radio options
  • Based on alternative
  • Custom Templates
  • grouping
  • searchable
  • The remote search
  • Create entries

Ii. Problem analysis

  • How to handle communication between parent and child components?
  • How is the drop-down component implemented?

Data properties and events

I will not separate data attributes and events and write whatever I need, because there is too much code and it adds up to thousands of lines!!Copy the code

Basic usage

The Dom available to the base usage

       <el-input
           v-model="selectedLabel"
           :placeholder="currentPlaceholder"
           :autocomplete="autoComplete || autocomplete"
           :size="selectSize"
           :disabled="selectDisabled"
           :readonly="readonly"
           :validate-event="false"
           :class="{ 'is-focus': visible }"
           :tabindex="multiple && filterable ? '-1' : null"
           @focus="handleFocus"
           @blur="handleBlur"
           @keyup.native="debouncedOnInputChange"
           @keydown.native.down.stop.prevent="navigateOptions('next')"
           @keydown.native.up.stop.prevent="navigateOptions('prev')"
           @keydown.native.enter.prevent="selectOption"
           @keydown.native.esc.stop.prevent="visible = false"
           @keydown.native.tab="visible = false"
           @paste.native="debouncedOnInputChange"
           @mouseenter.native="inputHovering = true"
           @mouseleave.native="inputHovering = false"
       >
           <template slot="prefix" v-if="$slots.prefix">
               <slot name="prefix"></slot>
           </template>
           <template slot="suffix">
               <i v-show=! "" showClose" :class="['el-select__caret', 'el-input__icon', 'el-icon-' + iconClass]"></i>
               <i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click="handleClearClick"></i>
           </template>
       </el-input>

       <transition name="el-zoom-in-top" @before-enter="handleMenuEnter" @after-leave="doDestroy">
           <el-select-menu ref="popper" :append-to-body="popperAppendToBody" v-show="visible && emptyText ! == false">
               <el-scrollbar
                   tag="ul"
                   wrap-class="el-select-dropdown__wrap"
                   view-class="el-select-dropdown__list"
                   ref="scrollbar"
                   :class="{ 'is-empty': ! allowCreate && query && filteredOptionsCount === 0 }"
                   v-show="options.length > 0 && ! loading"
               >
                   <el-option :value="query" created v-if="showNewOption"> </el-option>
                   <slot></slot>
               </el-scrollbar>
               <template v-if="emptyText && (! allowCreate || loading || (allowCreate && options.length === 0))">
                   <slot name="empty" v-if="$slots.empty"></slot>
                   <p class="el-select-dropdown__empty" v-else>
                       {{ emptyText }}
                   </p>
               </template>
           </el-select-menu>
       </transition>

Copy the code

What actions and effects are in the basic usage!

  • First of all, it must be the action when I click on the input box that I didn’t see hereclickEvent, then element is usedfocusEvents replaceclickThe event
    // Manual focus method
    handleFocus(event) {
        if (!this.softFocus) {
        // Determine whether the automatic dropdown property is set (for unsearchable Select, the options menu automatically appears after the input box gets focus)
        // Or whether it is filterable
            if (this.automaticDropdown || this.filterable) {
                // Visible is true to display focused styles and display dropdown components
                this.visible = true; 
                if (this.filterable) {
                    // The menu focus is true
                    this.menuVisibleOnFocus = true; }}// Pass the corresponding Focus event to the user
            this.$emit("focus", event);
        } else {
            this.softFocus = false; }},Copy the code
  • Take a look back at the Dom of the drop-down component

<el-select-menu ref="popper" :append-to-body="popperAppendToBody" v-show="visible && emptyText ! == false">
    <el-scrollbar
        tag="ul"
        wrap-class="el-select-dropdown__wrap"
        view-class="el-select-dropdown__list"
        ref="scrollbar"
        :class="{ 'is-empty': ! allowCreate && query && filteredOptionsCount === 0 }"
        v-show="options.length > 0 && ! loading"
    >
        <el-option :value="query" created v-if="showNewOption"> </el-option>
        <slot></slot>
    </el-scrollbar>
    <template v-if="emptyText && (! allowCreate || loading || (allowCreate && options.length === 0))">
        <slot name="empty" v-if="$slots.empty"></slot>
        <p class="el-select-dropdown__empty" v-else>
            {{ emptyText }}
        </p>
    </template>
</el-select-menu>
Copy the code
  • Here,el-select-menuThe component code is relatively simple
<div class="el-select-dropdown el-popper" :class="[{ 'is-multiple': $parent.multiple }, popperClass]" :style="{ minWidth: minWidth }">
        <slot></slot>
</div>
Copy the code

You can see that this is the overall structure of the drop-down box and then everything else is displayed in slots and then added to the body node, positioned above or below the input box by position, and can be adjusted depending on the position of the input box. Here Element implements some of its functionality through a number of third-party libraries. In el select-menu, vue-popper is used. In VUe-popper, popper-Manager is introduced. At the same time vue-popper introduces the third-party positioning library popper.js

'vue-popper' : popup manager used to manage component popups, when to create, where to create, when to destroy, and how to destroy 'popup' : popup manager used to open and close popups: Used to manage all the Modal layer 'popper.js' in the page: third-party library used to locate pop-upsCopy the code

  • And then el-ScrollBar which in this case is its own wrapped scrollbar component

  • In the end, all that’s left is the code on El-Option

 <li
    @mouseenter="hoverItem"
    @click.stop="selectOptionClick"
    class="el-select-dropdown__item"
    v-show="visible"
    :class="{ selected: itemSelected, 'is-disabled': disabled || groupDisabled || limitReached, hover: hover, }"
>
    <slot>
        <span>{{ currentLabel }}</span>
    </slot>
</li>
Copy the code

Here we see that the dropdown selection is li by Li and the UI is created using the render function in the El-Scrollbar

The El-Scrollbar here can be taken out separately