«Фронтенд-инжиниринг» — три способа инкапсуляции сторонних компонентов Vue

Vue.js внешний фреймворк

предисловие

При инкапсуляции сторонних компонентов часто возникает проблема, как использовать сторонние компоненты через инкапсулированные компоненты.Attributes(Атрибуты),Events(настраиваемое событие),Methods(метод),Slots(слот).

Конечно, решить эту проблему несложно, решение ее обычными методами неизбежно приведет к нудной и монотонной работе, а код инкапсулированного компонента не очень читабелен.

В этой статье будут представлены три метода использования сторонних компонентов.Attributes(Атрибуты),Events(настраиваемое событие),Slots(слоты), что касается использования сторонних компонентовMethodsТехнику (метода) еще предстоит оптимизировать, поэтому ее называют трехзубым топором.

1. Используйте свойства сторонних компонентов

image.png

Компонент поля ввода el-input, который инкапсулирует elementUI, называется myInput.disabledатрибут, чтобы отключить поле ввода, как этого добиться? обычные школьники так делают

//myInput.vue
<template>
  <div>
    <el-input v-model="inputVal" :disabled="disabled"></el-input>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: String,
      default: '',
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    inputVal: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      }
    }
  }
}
</script>

Через некоторое время я добавлю другие свойства компонента el-input в компонент myInput. Компонент el-input имеет в общей сложности 27 мульти-свойств, так что мне делать? не только громоздкий, но и плохо читаемый. ,Можно использовать$attrsШаг за шагом, давайте сначала посмотримattrsофициальное определение .

$attrs: содержит бездействие в родительской областиpropРаспознанные (и полученные) привязки атрибутов (кроме класса и стиля). Когда компонент не объявляет никакихprop, все привязки родительской области (кроме класса и стиля) включены сюда, и к ним можно получить доступ черезv-bind="$attrs"Пропустить внутренние компоненты

//myInput.vue
<template>
  <div>
    <el-input v-model="input" v-bind="$attrs"></el-input>
  </div>
</template>

Этого недостаточно, мы должныinheritAttrsпараметры установлены наfalse, почему, посмотримinheritAttrsОфициальное определение опциона ясно.

Привязки атрибутов родительской области, которые по умолчанию не считаются реквизитами, будут «отступать» и применяться к корневому элементу дочернего компонента как обычные атрибуты HTML. Это может не всегда вести себя так, как ожидается, при написании компонентов, которые обертывают целевой элемент или другой компонент. установивinheritAttrsдляfalse, это поведение по умолчанию будет удалено. и через$attrsВы можете заставить эти атрибуты действовать, а можете передатьv-bindЯвно привязан к некорневым элементам. Примечание. Этот параметр не влияет на привязки классов и стилей.

Проще говоря, положитьinheritAttrsУстановить какfalse, чтобы избежать добавления свойств, установленных для компонента myInput, в div корневого элемента компонента myInput.

//myInput.vue
<template>
  <div>
    <el-input v-model="input" v-bind="$attrs"></el-input>
  </div>
</template>
<script>
export default {
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      default: '',
    },
  },
  computed: {
    inputVal: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      }
    }
  }
}
</script>

После этой настройки свойства компонента el-input можно использовать непосредственно в компоненте myInput, независимо от того, сколько свойств добавляется к последующему компоненту el-input.

2. Используйте пользовательские события сторонних компонентов

image.png

Если вы используете пользовательское событие для компонента el-input в компоненте myIpput, вашей первой реакцией может бытьthis.$emit.

//myInput.vue
<template>
  <div>
    <el-input v-model="input" v-bind="$attrs" @blur="blur"></el-input>
  </div>
</template>
<script>
export default {
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      default: '',
    },
  },
  computed: {
    inputVal: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      }
    }
  },
  methods: {
    blur() {
      this.$emit('blur')
    }
  }
}
</script>
<myInput v-model="value" @blur="handleBlur"></myInput>

В компоненте el-input есть 4 кастомных события, что не так уж и много. А вдруг вы встретите сторонние компоненты с большим количеством кастомных ивентов? Добавляете их по одному, что добавит кучу ненужных методов. использовать$listenersШаг за шагом, давайте сначала посмотрим$listenersофициальное определение .

$listeners: содержит прослушиватель событий v-on в родительской области (без декоратора .native). Его можно передать внутренним компонентам через v-on="$listeners" .

//myInput.vue
<template>
  <div>
    <el-input v-model="input" v-bind="$attrs" v-on="$listeners"></el-input>
  </div>
</template>

Затем добавьте компонент el-input в компонент myInput.v-on="$listeners", вы можете использовать пользовательские события компонента el-input в компоненте myInput.

3. Слоты для использования сторонних компонентов

image.png

Что, если слот, определенный в компоненте el-input, используется в компоненте myIpput? В этом методе не так много хитростей: сколько слотов определено сторонними компонентами, нужно использовать при инкапсуляцииslotЭтикетка раскрыта. Например, чтобы открыть слот префикса в компоненте el-input, код выглядит следующим образом:

//myInput.vue
<template>
  <div>
    <el-input v-model="input" v-bind="$attrs" @blur="blur">
      <template #prepend>
        <slot name="prepend"></slot>
      </template>
    </el-input>
  </div>
</template>

В-четвертых, использование сторонних компонентов

image.png

использоватьrefДля этого сначала добавьте компонент el-input в компонент myInput.ref="elInput"Атрибуты,

//myInput.vue
<template>
  <div>
    <el-input ref="elInput></el-input>
  </div>
</template>
<script>
export default {
  mounted(){
     this.elInput = this.$refs.elInput;
  }
}
</script>

Здесь следует обратить внимание на родительский и дочерний компоненты.mountedВремя выполнения компонента el-input, поскольку общий компонент el-input вводится глобально и импортируется синхронно.mountedбудет лучше, чем компонент myInputmountedСначала выполнить, чтобы его можно было выполнить в компоненте myInput.mountedсредняя ручкаthis.$refs.elInputНазначается компоненту myInputthisОдин ресурс включен.

То, как компонент myInput использует компонент el-input, делится на две ситуации, связанные с введением компонента myInput.

Если компонент myInput вводится синхронно

<template>
  <div>
    <myInput ref="myInput"></myInput>
  </div>
</template>
<script>
import myInput from './myInput.vue';
export default {
  data() {
    return {
    }
  },
  components: {
    myInput,
  },
  mounted() {
    //调用el-input组件的focus方法
    this.$refs.myInput.elInput.focus();
  }
}
</script>

Если компонент myInput вводится асинхронно

<template>
  <div>
    <myInput ref="myInput"></myInput>
  </div>
</template>
<script>
export default {
  data() {
    return {
    }
  },
  components: {
    myInput: () => import('./myInput.vue')
  },
  mounted() {
    //调用el-input组件的focus方法
    setTimeout(() => {
       this.$refs.myInput.elInput.focus();
    })
  }
}
</script>