Инкапсуляция компонентов должна научиться реализовывать синтаксический сахар v-модели.

Vue.js
Инкапсуляция компонентов должна научиться реализовывать синтаксический сахар v-модели.

Привет всем, яКагуя такая милая. В этой статье будет описано, как реализовать его на пользовательском общедоступном компоненте.v-model, Это очень помогает в разработке общедоступных компонентов в реальных проектах!

цель обучения

При самостоятельной инкапсуляции компонентов, особенно при взаимодействии таких компонентов, как поля ввода, раскрывающиеся поля выбора и т. д., как правило, при привязке значений вы используетеv-model,использоватьv-modelГлавное преимущество в том, что нет необходимости запоминать конкретныеpropИмя поля может быть привязано к значению в компоненте, что снижает стоимость использования компонента.

Ведь хорошая общественная составляющая, прежде всегоAPIДизайн должен быть понятным и простым в использовании.

Во-вторых, мы должны постаратьсяПовторная логическая обработкаПоместите его в подкомпонент, что сделает инкапсуляцию компонента более значимой.

Конечно, через изучение этой статьи, даже если это не интерактивный компонент,Подойдет любой компонентдостичь таким образомv-model.

Давайте узнаем, как инкапсулировать общие компонентыv-model.

Основные понятия v-модели

v-modelфактически$emit('input')так же какprops:valueКомбинированный синтаксический сахар, если в компоненте выполняются эти два условия, его можно использовать в компоненте.v-model.

Хотя есть некоторые отличия в некоторых интерактивных компонентах,Например:

checkboxа такжеradioиспользоватьprops:checkedсвойства и$emit('change')мероприятие.

selectиспользоватьprops:valueсвойства и$emit('change')мероприятие.

Однако, помимо перечисленных выше, другие$emit('input')так же какprops:value.

Внедрение цифрового шагомера

Теперь, когда вы знаетеv-modelКонкретный принцип реализации, давайте попробуем самостоятельно инкапсулировать цифровой шагомер, который в основном состоит из двух кнопок увеличения и уменьшения и поля ввода.

Новый компонент

Создать новыйNumberInputкомпоненты

<template>
  <div>
    <button>-1</button>
    <input type="text" />
    <button>+1</button>
  </div>
</template>

<script>
  export default {
    name: "NumberInput"
  }
</script>

props:value

Сначала напишите первое условие,props:value, Так как это цифровой шагомер, поэтомуvalueТип должен быть числовым и должен быть параметром, который необходимо передать.

<input type="number" :value="value" />

props:{
  value:{
    type: Number,
    default: 0,
    require: true
  }
}

Конечно, написать сюда, будет проблема, т.к.propsЕсть одна характеристика, т.Однонаправленный поток данных, для понимания потока данных.

вы также можете назвать этоОдносторонняя привязка нисходящего канала, что эквивалентно значению родительского компонента, проходящего черезpropsПри передаче дочернему компоненту изменение значения в родительском компоненте будет передано дочернему компоненту, а изменение этого значения в дочернем компоненте не может быть передано родительскому компоненту.(Хотя возможно, консоль выдаст предупреждение, а это официально не рекомендуется)

Вы можете представить себе водопад сверху вниз. Родительский компонент находится сверху, а дочерний компонент снизу. Этот поток воды может течь только сверху вниз, но не снизу вверх. Это неправильно, и брат Ньютон не не согласен.

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

$emit('input')

упомянутый вышеОднонаправленный поток данныхЕсть точка вне следуетизменить внутри дочернего компонентаprops.

Значит, нам нужно переписать его по-другому, определив переменнуюcurrentValue, чтобы избежать для подкомпонентовpropsПрямая модификация , все для<input>Модификация поля ввода выполняется с помощью этогоcurrentValueзаписать.

<input type="number" :value="currentValue" />

props:{
  value:{
    type: Number,
    default: 0
    require: true
  }
},
data(){
  return{
    currentValue: this.value
  }
}

В это время мы сначала модифицируемcurrentValueзначение, затем передать$emit('input')чтобы уведомить родительский компонент, что нашvalueИзмените значение родительского элементаpropsЗначение изменяется, а затем значение в дочернем компоненте обновляется через односторонний поток данных родительского компонента. чтобы избежать подкомпонентов вpropsпрямая модификация.

<input type="number" :value="currentValue" @input="changeValue" />

methods:{
  changeValue(e){
    this.currentValue = parseInt(e.target.value);
    this.$emit('input', this.currentValue);
  }
}

Теперь этого прекрасно избегаютОднонаправленный поток данныхПроблема, поставленнаяcurrentпеременные для записи значений и избегайтеpropsпрямая модификация. потом$emit('input')Пусть значение, связанная в родительском компоненте, будет измененаОдносторонняя привязка нисходящего канала, измененный родительским компонентомprops

Потом точно так же аккумуляторы слева и справа тоже очень просто, и это тоже правильноcurrentValueизменение значения плюс$emit('input')коробка передач.

<button @click="increase(-1)">-1</button>
<button @click="increase(1)">+1</button>

methods:{
  increase(value){
    this.currentValue+= value;
    this.$emit('input', this.currentValue);
  }
}

На данный момент остается еще один важный шаг, которыйwatchмонитор

watchмонитор

Когда компонент инициализируется изvalueПолучите значение один раз и измените его непосредственно, когда родительский компонентv-modelПри привязке значения дляvalueОсобенно важен своевременный мониторинг.

Итак, наконец, мы должны добавить еще один шагwatchмонитор.

watch:{
  value(newVal){
    this.currentValue = newVal;
  }
},

До сих порv-modelКомпоненты упакованы.

Итак, полный код выглядит следующим образом

<template>
  <div>
    <button @click="increase(-1)">-1</button>
    <input type="number" :value="currentValue" @input="changeValue" />
    <button @click="increase(1)">+1</button>
  </div>
</template>

<script>
  export default {
    name: "NumberInput",
    props:{
      value:{
        type: Number,
        default: 0,
        require: true
      }
    },
    data(){
      return{
        currentValue: this.value
      }
    },
    watch: {
      value(newVal){
        this.currentValue = newVal;
      }
    },
    methods:{
      changeValue(e){
        this.currentValue = parseInt(e.target.value);
        this.$emit('input', this.currentValue);
      },
      increase(value){
        this.currentValue+= value;
        this.$emit('input', this.currentValue);
      }
    }
  }
</script>

<style lang="stylus" scoped>

</style>

Использование компонентов

<NumberInput v-model="number"></NumberInput>

import NumberInput from "./NumberInput";

export default {
  components:{NumberInput},
  data(){
    return{
      number: 10
    }
  }
}

Вывод в конце статьи

Любой компонент может быть реализованv-model.

реализоватьv-modelОсновные пункты следующие:

  • props:value

    используется для контроляv-modelСвязанное значение.

  • currentValue

    из-за单向数据流причина, нужно использоватьcurrentValueИзбегайте подкомпонентов дляpropsпрямая операция.

  • $emit('input')

    используется для контроляv-modelоперации изменения значения, все дляpropsКогда значение изменяется, родительский компонент должен быть уведомлен.

  • watchмонитор

    Когда компонент инициализируется изvalueПолучите значение один раз и измените его непосредственно, когда родительский компонентv-modelПри привязке значения дляvalueсвоевременный мониторинг.

Пасхалки в конце статьиmodel

Например, некоторые люди говорят, что я просто не хочу использоватьprops:valueтак же как$emit('input'), я хочу изменить имя, то в это время,modelможет помочь вам сделать это.

Потому что эти два имени имеют другое использование в некоторых собственных элементах формы.

export default {
  model: {
    prop: 'number',
    event: 'change'
  },
}

В данном случае это использованиеprops:numberтак же как$emit('change').