Четыре «лучших метода» для семейства ведер vue

Vue.js

предисловие

Прежде чем читать эту статью, я хотел бы сказать всем Amway одну вещь:

Vue.js 组件编码规范

Когда вы видите эти очки в черной оправе, вы о чем-то думаете?

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

Кроме того, «лучшие практики» (обратите внимание на кавычки) в этой статье — это все слова одной семьи, которые могут быть неправильными. Добро пожаловать, чтобы обсудить и сделать кирпичи.

Практика 1: Как классифицировать компоненты

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

view

Как следует из названия, представление относится к странице, и вы также можете назвать его страницей. Его определение: он соответствует определенному маршруту и ​​указан в конфигурации vue-router. представление — это контейнер страницы и точка входа для других компонентов. Он может взаимодействовать с хранилищем vuex и распределять данные по общим компонентам.

global component

Глобальные компоненты, существующие в виде виджетов. Например, тост, предупреждение и т. д. Его характеристика в том, что он глобальный, вложен непосредственно в корень и не принадлежит ни одному представлению. Глобальный компонент также взаимодействует с хранилищем vuex.Он использует модуль только в состоянии.Данные в этом состоянии специально используются для управления отображением и отображением компонента gloabl, не путать с состоянием, используемым другими бизнес-сущностями .
Если другие компоненты хотят изменить его, они могут отправить соответствующую мутацию напрямую. Для прослушивания его изменений (таких как глобальное подтверждение, после подтверждения, запуск разных операций в разных компонентах) используйте глобальную шину событий (event bus).

simple component

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

complex component

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

Внутри красного прямоугольника на рисунке находится экземпляр сложного компонента. Это элемент большого списка, отображающий много данных, и при нажатии нескольких кнопок в левом нижнем углу всплывает соответствующее всплывающее окно, во всплывающем окне есть сложные формы, которые необходимо заполнить. в и отправлено... Логика, можно сказать, довольно сложная. Если в это время мы еще застряли в способе общения простых компонентов, И Лай протягивает руку и ест и открывает рот, и ничего не делает, то:
1. Все реквизиты передаются родительским компонентом один за другим, если нужно вывести десятки или даже десятки данных, то родительский компонент<template>Код внутри недостаточно хорош?
2. Все бизнес-процессы должны быть $emit для обработки родительским компонентом, затем родительский компонент<script>Код внутри недостаточно хорош?
Таким образом, для такого сложного компонента мы должны позволить ему иметь некоторую «автономность». Вы можете пропустить родительский компонент, самостоятельно общаться с vuex, получать состояние и отправлять мутации и действия, разве вы не очень довольны?

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

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

Практика 2: Как изящно изменить реквизит

Давайте посмотрим на каштан 🌰
Предположим, есть компонент для модального диалога. Чтобы иметь возможность открывать модальное окно, родительский компонент передает свойства модальному окну, чтобы управлять его отображением и скрытием, с именем visible, типом является логическим и привязывает инструкцию v-if вне модального окна. Итак, вопрос в том, если мы нажмем кнопку закрытия внутри модального окна, чтобы закрыть себя, что мы должны написать?
Конечно, самый традиционный способ — создать событие в модальном окне, установить прослушиватель в родительском компоненте, а затем изменить значение. Однако этот метод, несомненно, очень навязчив и увеличивает объем кода без всякой причины. Кнопка закрытия находится внутри модального окна. Это мое личное дело, чтобы закрыть себя. Могу ли я не позволить родительскому компоненту позаботиться об этом?
Некоторые студенты говорили, что модифицируйте видимость прямо внутри модального окна.this.visible = false, не так ли?
Не совсем. Если вы сделаете это, вы увидите следующую кучу ошибок:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.

Vue ясно говорит вам, что как подкомпонент вы должны обезопасить себя, и вам не разрешено изменять реквизиты, переданные вам вашим отцом.
так что нам делать?

метод первый

Давайте подумаем об этом, если не разрешено изменять значение props, как насчет того, чтобы изменить ... свойства porps?
Оказывается, это возможно.
Мы можем установить тип видимого выше как Object, а видимость модального окна зависит от visible.value. Когда модальное окно хочет закрыться, простоthis.visible.value = falseВот и все. Этот метод выглядит довольно удобным, но на самом деле это оппортунистический метод. В приведенной выше спецификации кодирования компонентов Amway Vue.js явно указано, что реквизиты являются атомарными, то есть поля в реквизитах должны быть простыми строками, числами или логическими значениями. Причина этого:

  • Сделайте API компонента понятным и интуитивно понятным.
  • Использование только примитивных типов и функций в качестве реквизита делает API компонента ближе к собственным элементам HTML(5).
  • Другие разработчики лучше понимают значение и функцию каждой опоры.
  • Передача слишком сложных объектов делает невозможным определение того, какие свойства или методы используются пользовательскими компонентами, что затрудняет рефакторинг и сопровождение кода.

Поэтому мы меняем visible на Object, что противоречит спецификации.

Способ второй

В vue есть существующий механизм, который очень похож на существующие требования, а именно v-model. В форме каждый ввод подобен дочернему компоненту. Значение, связанное с v-моделью во внешнем слое, может быть отражено во входных данных, а также может быть изменено само значение входных данных.
На самом деле v-model — это просто синтаксический сахар,v-model="xxx", что эквивалентно:value="xxx" @input="val=>xxx=val". Затем мы можем использовать эту функцию v-модели для достижения наших целей. Нам просто нужно бросить событие ввода внутри модального окна.this.$emit('input', false), может закрыться.
Этот метод относительно прост и не нарушает спецификацию, но легко запутать людей, думая, в какой форме здесь выполнять операцию.
Есть ли лучший способ для нас?

Способ третий

Если вы были в контакте с vue с тех пор, как основная версия — 1, то вы можете знать модификатор под названием .sync. Если вы начали с версии 2.0, вы, скорее всего, не знакомы с ней. Это потому, что vue удалил его в версии 2.0, но, к счастью, после версии 2.3оно вернулось.
Этот модификатор просто адаптирован к нашим потребностям. Сам по себе это синтаксический сахар, похожий на v-model, все, что нам нужно сделать, это вызвать событие обновления, в котором значение нужно изменить внутри компонента.this.$emit('update:foo', newValue). Ни один из них не нарушает нормы и достаточно ясен, чтобы быть, возможно, лучшим решением. Единственным недостатком является то, что есть небольшое требование к версии.

Практика 3: Как инкапсулировать интерфейс запроса

Данные — это ядро ​​SPA, а источником данных является интерфейс. Как элегантно и эффективно запрашивать данные через интерфейс — это проблема, о которой должны заботиться разработчики. На практике я инкапсулирую интерфейс так:

Сверху вниз, объясняйте по порядку.
Первый слой — компонент.
Второй слой — это действие в vuex, мы называем действие в компоненте базовой операцией.
Третий уровень — это API. Здесь мы предопределяем каждый интерфейс. Включая URL-адрес, тип, тип содержимого интерфейса и жестко запрограммированные параметры запроса. В действии мы вызываем интерфейс запроса API.
Четвертый уровень — это request, который является общедоступным методом нашего запроса, который используется для конкретного http-клиента. Инкапсулируйте и внедрите процесс обработки запросов единого интерфейса.
Пятый уровень — это различные http-клиенты, представленные axios.
В основном мы кодируем третий и четвертый слои, то есть API и запрос. В написании апи нет никакой сложности, и мы в основном говорим о коде запроса. В этой части кода нам нужно обратить внимание на следующие аспекты.

  • обработка загрузки. Если время запроса относительно велико, пропустите глобальную загрузку, чтобы сообщить об этом пользователю.
  • Обработка ошибок. Существует два вида ошибок. Первый заключается в том, что HTTP-запрос напрямую возвращает код ошибки. Во-вторых, хотя возвращаемое значение запроса равно 200, в возвращаемом результате отображается ошибка. Например, в возвращенном jsonsuccess: false. Для обоих типов ошибок мы должны поймать и обработать их.
  • Обработка согласованности API. Параметры, принимаемые http-клиентом, являются специфическими.В качестве примера возьмем axios, параметром запроса get является params, а параметром запроса post является data. Из-за этой разницы уровень запроса должен сгладить его, а уровень API не должен заботиться об этом при определении интерфейса.

Ниже приведен пример кода для справки.

  if (opt.method === 'post') {
    axiosOpt.data = opt.payload
  } else if (opt.method === 'get') {
    axiosOpt.params = opt.payload
  }
  if (opt.withFile) {
    Object.assign(axiosOpt, { headers: {
      'Content-Type': 'multipart/form-data'
    }})
  }

  // 全局请求的 loading,当请求 300 ms 后还没返回,才会出现 loading
  const timer = setTimeout(() => {
    store.dispatch('showLoading', {
      text: '加载数据中'
    })
  }, 300)

  try {
    // 开始请求
    const result = await axios(axiosOpt)
    // 如果 300 ms 还没到,就取消定时器
    clearTimeout(timer)
    store.dispatch('closeLoading')

    if (result.status === 200 && result.statusText === 'OK') {
      if (result.data.success) {
        return result.data.results || true
      } else {
        // 请求失败的 toast
        store.dispatch('showAlert', {
          type: 'error',
          text: `请求失败${result.data.message ? `,信息:${result.data.message}`: ''}`
        })
        return false
      }
    } else {
      return false
    }
  } catch(e) {
    clearInterval(timer)
    // 请求失败的 toast
    store.dispatch('closeLoading')
    store.dispatch('showAlert', {
      type: 'error',
      text: '请求失败'
    })
    return false
  }

Практика 4: Как решить, когда запрашивать данные

В SPA в каждом представлении много данных, которые нужно получить через интерфейсные запросы, если их не получить, то на странице будет много пробелов. Выше мы обсудили, как инкапсулировать запросы к интерфейсу, следующий шаг — решить, когда запрашивать данные инициализации, то есть где писать код. На практике есть два идеальных тайминга.

beforeRouteEnter/Update

vue-router предоставляет два вышеупомянутых хука жизненного цикла, которые будут срабатывать при вводе маршрута и при изменении маршрута. Эти два хука прописаны в представлении.

router.beforeEach

vue-router также предоставляет глобальный метод beforeEach.При изменении любого маршрута он будет перехвачен этим методом.Мы можем добавить в этот метод свой собственный код для унифицированной обработки. Например, для всех действий, запрошенных инициализацией представления, мы можем назвать их определенными именами, такими как _init в качестве суффикса и т. д. В методе beforeEach мы отслеживаем хранилище, соответствующее текущему представлению, находим действие с именем _init и отправляем его.
Вышеуказанные два метода имеют свои особенности.
Для первого преимущество заключается в том, что код сбора данных и конкретное представление связаны вместе, и мы можем четко видеть процесс сбора данных внутри представления. Минус в том, что каждый раз при добавлении страницы внутри нее нужно писать кучу кода инициализации, что увеличивает объем кода. для последнего. Преимущество в том, что код унифицирован и регулярен, и используется метод конфигурации, который можно написать один раз, не добавляя каждый раз дополнительный код. Недостатком является то, что он относительно непонятен, а код инициализации отделен от самого представления.
Что касается вопроса о том, как выбрать между двумя вышеупомянутыми методами, я склонен использовать последний для крупных проектов и первый для небольших проектов.

Other Tips

  • Больше использования микширования, можно извлекать общие части на уровне компонентов, уменьшать избыточность, отличный механизм.
  • Использование большего количества констант не имеет ничего общего с самим vue, но может значительно повысить надежность кода.
  • Если ссылка переходит внутрь проекта, используйте more вместо написания href тега a.
  • Не используйте манипулирование домом. Но если вам нужно, например, вы хотите получить свойство scrollTop dom, используйте $ref вместо селектора.
  • Это все, что я могу придумать, добро пожаловать, чтобы обсудить и добавить больше.

Автор: Front-end Team Lilac Garden - Президент ㍿