Подробно объясните три основные концепции компонентов vue.

JavaScript Vue.js

предисловие

В этой статье в основном представлены три основные концепции Vue: атрибуты, события и слоты, как их использовать, а также некоторые важные детали, которые легко упустить из виду. Если вы читаете компоненты, написанные другими, вы также можете расширить эти три части, что поможет вам быстро понять все функции компонента.

image.png

Пожалуйста, нажмите на код этой статьиGitHub Blog, это мелко на бумаге, давайте начнем вводить больше кода!

1. Свойства

1. Пользовательские свойства реквизита

Prop определяет, какие настраиваемые свойства имеет этот компонент, и основные функции компонента также определяются им. При написании общих компонентов реквизиты желательно записывать в виде объектов, чтобы вы могли установить тип, значение по умолчанию или значение пользовательских свойств проверки для каждого свойства.Это очень важно при разработке компонентов, но многие люди игнорируют это и используют его. Массив использования реквизита, такие компоненты часто не являются строгими.

// 父组件
 <props name='属性'
           :type='type'
           :is-visible="false"
           :on-change="handlePropChange"
           :list=[22,33,44]
           title="属性Demo"
           class="test1"
           :class="['test2']"
           :style="{ marginTop: '20px' }" //注意:style 的优先级是要高于 style
           style="margin-top: 10px">
  </props>
// 子组件
  props: {
    name: String,
    type: {
   //从父级传入的 type,它的值必须是指定的 'success', 'warning', 'danger'中的一个,如果传入这三个以外的值,都会抛出一条警告
      validator: (value) => {
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    onChange: {
    //对于接收的数据,可以是各种数据类型,同样也可以传递一个函数
      type: Function,
      default: () => { }
    },
    isVisible: {
      type: Boolean,
      default: false
    },
    list: {
      type: Array,
      // 对象或数组默认值必须从一个工厂函数获取
      default: () => []
    }
  }

Из вышеприведенного примера можно сделать вывод, что реквизиты могут явно определять одни или несколько данных, а для полученных данных они могут быть разных типов данных,Также можно передать функцию. Связь родитель-потомок через общие свойства; связь потомок-родитель через функциональные свойства

2.inheritAttrs

这是2.4.0 新增的一个API,默认情况下父作用域的不被认作 props 的特性绑定将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。可通过设置 inheritAttrs 为 false,这些默认行为将会被去掉。 Уведомление:Этот параметр не влияет на привязки классов и стилей.. В предыдущем примере, если атрибут title не объявлен в реквизитах подкомпонента, он по умолчанию будет висеть на корневом элементе подкомпонента, как показано на следующем рисунке:

3. Разница между данными и реквизитом

  • Та же точка

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

  • разница

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

Реквизиты называются статическими данными.В их соответствующих экземплярах, когда тип определен во время инициализации на основе одностороннего потока данных Vue, его тип данных не может быть изменен во время передачи данных, и это не разрешено непосредственно в дочерних компонентах. манипулировать переданными данными реквизита, вам необходимо изменить данные в переданном источнике другими способами. Что касается того, как изменить, мы углубимся в детали:

4. Однонаправленный поток данных

Это понятие появляется в компонентной коммуникации. Данные реквизита передаются через данные или литералы родительского компонента или компонента более высокого уровня. Прямые манипуляции не допускаются для изменения данных реквизита в соответствующих экземплярах, но необходимы другие средства для изменения данных в источнике передачи. Итак, если мы иногда хотим изменить переданный реквизит, каковы способы?

  • Способ 1: переход к опции данных

Скопируйте проп в данные дочернего компонента, данные можно изменить

export default {
  props: {
    type: String
  },
  data () {
    return {
      currentType: this.type
    }
  }
}

Получите данные типа в свойствах через currentType в опции данных, что эквивалентно выполнению операции присваивания для currentType=type, не только получая данные currentType, но и изменяя данные currentType.

  • Метод 2: использование вычисляемых свойств
export default {
  props: {
    type: String
  },
  computed: {
    normalizedType: function () {
      return this.type.toUpperCase();
    }
  }
}

Хотя два вышеуказанных метода могут косвенно модифицировать значение props в дочернем компоненте, если дочерний компонент захочет модифицировать данные и обновить их синхронно с родительским компонентом, это не поможет. В некоторых случаях нам может понадобиться выполнить «двустороннюю привязку» к опоре, в этом случае рекомендуются следующие два метода:

  • Способ 3: использование .sync
// 父组件
<template>
  <div class="hello">
    <div>
      <p>父组件msg:{{ msg }}</p>
      <p>父组件数组:{{ arr }}</p>
    </div>
    <button @click="show = true">打开model框</button>
    <br />
    <demo :show.sync="show" :msg.sync="msg" :arr="arr"></demo>
  </div>
</template>

<script>
import Demo from "./demo.vue";
export default {
  name: "Hello",
  components: {
    Demo
  },
  data() {
    return {
      show: false,
      msg: "模拟一个model框",
      arr: [1, 2, 3]
    };
  }
};
</script>
// 子组件
<template>
  <div v-if="show" class="border">
    <div>子组件msg:{{ msg }}</div>
    <div>子组件数组:{{ arr }}</div>
    <button @click="closeModel">关闭model框</button>
    <button @click="$emit('update:msg', '浪里行舟')">
      改变文字
    </button>
    <button @click="arr.push('前端工匠')">改变数组</button> 
  </div>
</template>
<script>
export default {
  props: {
    msg: {
      type: String
    },
    show: {
      type: Boolean
    },
    arr: {
      type: Array //在子组件中改变传递过来数组将会影响到父组件的状态
    }
  },
  methods: {
    closeModel() {
      this.$emit("update:show", false);
    }
  }
};

props.gif

Родительский компонент передает значения msg и show реквизитам дочернего компонента, оба из которых используют модификатор .sync для двусторонней привязки. Однако, хотя .sync хорош, он также имеет ограничения, такие как:

1)Не может быть использован с выражениями(Такие какv-bind:title.sync="doc.title + '!'"он недействителен); 2)нельзя использовать с литеральными объектами(Такие какv-bind.sync="{ title: doc.title }"не работает должным образом).

  • Способ 4. Оберните данные родительского компонента в объект и передайте его дочернему компоненту.

Это связано с тем, что объекты и массивы передаются по ссылке в JavaScript, поэтому для поддержки типа массива или объекта изменение самого объекта или массива в дочернем компоненте повлияет на состояние родительского компонента. Например, в приведенном выше примере массив arr, переданный из родительского компонента, изменяется в дочернем компоненте, тем самым изменяя состояние родительского компонента.

5. Добавлять и не добавлять v-bind при передаче данных дочерним компонентам?

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

v-bind:msg = 'msg'

Это для передачи данных через v-bind и передаваемые данные не являются литералом.Разбор в двойных кавычках является выражением, а также это могут быть данные и методы, определенные в экземпляре (фактически, это относится к переменной).

msg='катание на лодке по волнам'

В этом режиме без v-bind можно передать только один литерал, и этот литерал ограничен типом String, строковым типом. Затем, если вы хотите передавать данные через литералы,Если вы хотите передать тип, отличный от String, вы должны добавить v-bind перед именем реквизита., который выполняется внутри экземпляра. Если на стороне экземпляра нет этого свойства и метода, по умолчанию используется соответствующий тип данных.

:msg='11111' //Number 
:msg='true' //Bootlean 
:msg='()=>{console.log(1)}' //Function
:msg='{a:1}' //Object

2. События

1. Управление событиями и данными

Процессы, управляемые событиями, с собственным JavaScript обычно выглядят так:

  • Сначала найдите узел, которым нужно управлять через определенный селектор -> добавьте соответствующий прослушиватель событий к узлу.
  • Затем пользователь выполняет событие (щелчок, ввод, возврат и т. д.) -> вызов JavaScript для изменения узла.

Эта модель не представляет проблемы для бизнеса, но она будет менее идеальной с точки зрения затрат на разработку и эффективности, особенно когда бизнес-система становится все больше и больше. С другой стороны, эффективность поиска и модификации узлов изначально низка, поэтому возникает модель, управляемая данными.

Основная идея Vue — управление данными. Так называемое управление данными означает, что представление генерируется на основе данных.Когда мы изменяем представление, мы не будем напрямую манипулировать DOM, а будем изменять данные.Процесс выглядит следующим образом:

Пользователь выполняет операцию -> обратная связь с ВМ для обработки (что может привести к изменениям Модели) -> изменяется уровень ВМ, и данные в соответствующем месте страницы обновляются напрямую через отношение привязки

Это можно понять просто: data-driven не управляет узлами, а напрямую обновляет страницы через виртуальный абстрактный слой данных. В основном из-за этого фреймворки, управляемые данными, могут работать быстрее (потому что нет необходимости выбрасывать узлы) и могут применяться к крупным проектам.

2. События модификатора

События Vue делятся на обычные события и события-модификаторы Здесь мы в основном вводим события-модификаторы.

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

<custom-component>组件内容</custom-component>

если ваш ответ<custom-component @click="xxx">, это неверно. @click здесь — это пользовательский щелчок по событию, а не собственный щелчок по событию. Привязка собственного клика выглядит следующим образом:

<custom-component @click.native="xxx">组件内容</custom-component>

Модификаторы событий неотделимы от фактического процесса разработки.Общими модификаторами событий являются следующие:

  • модификатор формы

1).lazy

По умолчанию,v-modelкаждый разinputСинхронизируйте значение поля ввода с данными после запуска события. можете добавитьlazyмодификатор, который переводится как использованиеchangeСобытия синхронизируются. Это подходит для сценариев, когда представление обновляется после того, как курсор уходит после ввода всего.

2).trim

Если вы хотите автоматически фильтровать начальные и конечные пробельные символы, введенные пользователем, вы можете добавить модификатор trim в v-model:

<input v-model.trim="msg">

Этот модификатор может отфильтровать сцену, в которой вы случайно нажимаете пробел после ввода пароля. должны знать о том,Он может фильтровать только начальные и конечные пробелы! Первая и последняя, ​​середина фильтроваться не будут.

3).number

Если вы хотите автоматически преобразовывать введенное пользователем значение в числовой тип, вы можете добавить модификатор числа в v-model:

<input v-model.number="value" type="text" />

number.gif

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

  • модификатор события
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

3. Слот

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

1. Слоты прицела

Давайте рассмотрим слоты с ограниченной областью действия на примере списка задач. Если при выборе элемента текст становится желтым (как показано на рисунке ниже), как этого добиться?slot.gif

// 父组件
<template>
  <div class="toList">
    <input v-model="info" type="text" /> <button @click="addItem">添加</button>
    <ul>
      <TodoItem v-for="(item, index) in listData" :key="index">
        <template v-slot:item="itemProps"> // 这是个具名插槽
        // 其中itemProps的值就是子组件传递过来的对象
          <span
            :style="{
              fontSize: '20px',
              color: itemProps.checked ? 'yellow' : 'blue'
            }"
            >{{ item }}</span
          >
        </template>
      </TodoItem>
    </ul>
  </div>
</template>
<script>
import TodoItem from "./TodoItem";
export default {
  components: {
    TodoItem
  },
  data() {
    return {
      info: "",
      listData: []
    };
  },
  methods: {
    addItem() {
      this.listData.push(this.info);
      this.info = "";
    }
  }
};
</script>
// 子组件
<template>
  <div>
    <li class="item">
      <input v-model="checked" type="checkbox" />
      <slot name="item" :checked="checked"></slot> // 将checked的值传递给父组件
    </li>
  </div>
</template>
<script>
export default {
  data() {
    return {
      checked: false
    };
  }
};
</script>

Стоит отметить: синтаксис объекта v-bind:style интуитивно понятен — он очень похож на CSS, но на самом деле является объектом JavaScript. Имена свойств CSS могут быть названы в CamelCase или разделены тире (кебаб-регистр, не забудьте заключить их в кавычки).

2. Новый синтаксис v-slot

В версии 2.6.0 мы представили новый унифицированный синтаксис для именованных слотов и слотов с заданной областью (т.е.v-slotинструкция). он заменяетslot а также slot-scope. Давайте подумаем над вопросом:Будут ли слоты с одинаковыми именами объединены или заменены?

  • Версия Vue2.5, слияние общих слотов, замена слотов прицела
  • Версия Vue2.6, все замены (см. пример ниже)

Мы представляем новый синтаксис слота по умолчанию, именованный слот и выделенный слот в версии Vue2.6 с примером:

// 父组件
<template>
  <div class="helloSlot">
    <h2>2.6 新语法</h2>
    <SlotDemo>
      <p>默认插槽:default slot</p>
      <template v-slot:title>
        <p>具名插槽:title slot1</p>
        <p>具名插槽:title slot2</p>
      </template>
      <template v-slot:title>
        <p>new具名插槽:title slot1</p>
        <p>new具名插槽:title slot2</p>
      </template>
      <template v-slot:item="props">
        <p>作用域插槽:item slot-scope {{ props }}</p>
      </template>
    </SlotDemo>
  </div>
</template>
<script>
import Slot from "./slot";
export default {
  components: {
    SlotDemo: Slot
  }
};
</script>
// 子组件
<template>
  <div>
    <slot />
    <slot name="title" />
    <slot name="item" :propData="propData" />  // propData这个属性名可以任意取
  </div>
</template>
<script>
export default {
  data() {
    return {
      propData: {
        value: "浪里行舟"
      }
    };
  }
};
</script>

slot

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

Справочная статья