[Перевод] Обмен технологиями Vue — 7 секретов, о которых вы могли не знать

Vue.js

предисловие

Эта статья представляет собой публичное изложение ценности вклада Криса Фрица в исходный код vue. Я чувствую, что в этом обмене есть много вещей, из которых стоит поучиться. Хотя часть контента — это то, что я делаю на работе, я все же перевожу ppt из великий бог здесь Я надеюсь, что друзья принесут некоторую помощь.

1. Эффективно используйте непосредственный атрибут часов

Это то, что я написал в проекте, а также. Например, когда есть запрос, который нужно снова инициализировать, выполнить его один раз, а затем отслеживать его изменения, многие пишут так:

created(){
    this.fetchPostList()
},
watch: {
    searchInputValue(){
        this.fetchPostList()
    }
}

Мы можем записать вышеизложенное следующим образом:

watch: {
    searchInputValue:{
        handler: 'fetchPostList',
        immediate: true
    }
}

2. Регистрации компонентов стоит поучиться

В общем случае наши компоненты записываются следующим образом:

import BaseButton from './baseButton'
import BaseIcon from './baseIcon'
import BaseInput from './baseInput'

export default {
  components: {
    BaseButton,
    BaseIcon,
    BaseInput
  }
}
<BaseInput  v-model="searchText" @keydown.enter="search" />
<BaseButton @click="search">  <BaseIcon name="search"/></BaseButton>

Обычно есть три шага,

Первым шагом является введение,

Второй шаг регистрации,

Третий шаг - официальное использование,

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

Мы можем использовать webpack для использования метода require.context() для создания нашего собственного контекста (модуля) для автоматического динамического запроса компонентов.

Идея такова: в main.js в папке src все необходимые базовые компоненты запакованы динамически с помощью webpack.

код показывает, как показано ниже:

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

// Require in a base component context
const requireComponent = require.context(
  ‘./components’, false, /base-[\w-]+\.vue$/
)

requireComponent.keys().forEach(fileName => {
  // Get component config
  const componentConfig = requireComponent(fileName)

  // Get PascalCase name of component
  const componentName = upperFirst(
    camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
  )

  // Register component globally
  Vue.component(componentName, componentConfig.default || componentConfig)
})

Таким образом, нам нужен только третий шаг для введения компонентов:

<BaseInput
  v-model="searchText"
  @keydown.enter="search"
/>
<BaseButton @click="search">
  <BaseIcon name="search"/>
</BaseButton>

3. Оптимизируйте внедрение модулей vuex

Для vuex мы выводим хранилище следующим образом:

import auth from './modules/auth'
import posts from './modules/posts'
import comments from './modules/comments'
// ...

export default new Vuex.Store({
  modules: {
    auth,
    posts,
    comments,
    // ...
  }
})

Ввести много модулей, а потом зарегистрироваться в Vuex.Store~~

Упрощенный подход аналогичен описанному выше, но также использует require.context() для чтения файла, код выглядит следующим образом:

import camelCase from 'lodash/camelCase'
const requireModule = require.context('.', false, /\.js$/)
const modules = {}

requireModule.keys().forEach(fileName => {
  // Don't register this file as a Vuex module
  if (fileName === './index.js') return

  const moduleName = camelCase(
    fileName.replace(/(\.\/|\.js)/g, '')
  )
  modules[moduleName] = {
                namespaced: true,
               ...requireModule(fileName),
              }

})

export default modules

Итак, нам просто нужен следующий код:

import modules from './modules'
export default new Vuex.Store({
  modules
})

В-четвертых, ленивая загрузка роутинга

На данный момент, что касается введения vue, я имел обыкновениеТехнические моменты и резюме рефакторинга проекта VueВ разделе также упоминалось, что компоненты могут быть динамически загружены с помощью require или import().

{
  path: '/admin',
  name: 'admin-dashboard',
  component:require('@views/admin').default
}

или

{
  path: '/admin',
  name: 'admin-dashboard',
  component:() => import('@views/admin')
}

Загрузить маршруты.

Пять, обновление ключевого компонента маршрутизатора

Следующая сцена действительно разбила сердца многим программистам... По умолчанию все используют Vue-router для реализации управления маршрутизацией. Предположим, мы пишем сайт блога и требуется перейти с /post-haorooms/a на /post-haorooms/b. Потом мы с удивлением обнаружили, что данные не обновились после того, как страница перескочила? ! Причина в том, что vue-router «интеллектуально» находит, что это один и тот же компонент, а потом решает повторно использовать этот компонент, поэтому метод, который вы написали в созданной функции, вообще не выполняется. Обычное решение состоит в том, чтобы прослушивать изменения в $route для инициализации данных следующим образом:

data() {
  return {
    loading: false,
    error: null,
    post: null
  }
}, 
watch: {
  '$route': {
    handler: 'resetData',
    immediate: true
  }
},
methods: {
  resetData() {
    this.loading = false
    this.error = null
    this.post = null
    this.getPost(this.$route.params.id)
  },
  getPost(id){

  }
}

Ошибка исправлена, но писать это каждый раз слишком некрасиво, верно? Придерживаясь принципа лениться, если можно лениться, мы надеемся написать такой код:

data() {
  return {
    loading: false,
    error: null,
    post: null
  }
},
created () {
  this.getPost(this.$route.params.id)
},
methods () {
  getPost(postId) {
    // ...
  }
}

Решение: добавьте уникальный ключ в router-view, чтобы даже если это общедоступный компонент, при изменении URL-адреса компонент создавался заново.

<router-view :key="$route.fullpath"></router-view>

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

Шесть, единственный корневой элемент компонента

Сценарий следующий:

(Emitted value instead of an instance of Error)
  Error compiling template:

  <div></div>
  <div></div>

  - Component template should contain exactly one root element. 
    If you are using v-if on multiple elements, use v-else-if 
    to chain them instead.

В шаблоне может быть только один div, а не два параллельных div, как указано выше.

Например следующий код:

<template>
  <li
    v-for="route in routes"
    :key="route.name"
  >
    <router-link :to="route">
      {{ route.title }}
    </router-link>
  </li>
</template>

сообщит об ошибке!

Мы можем использовать функцию рендеринга для рендеринга

functional: true,
render(h, { props }) {
  return props.routes.map(route =>
    <li key={route.name}>
      <router-link to={route}>
        {route.title}
      </router-link>
    </li>
  )
}

Семь, упаковка компонентов, проблемы проникновения атрибутов событий

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

//父组件
<BaseInput 
    :value="value"
    label="密码" 
    placeholder="请填写密码"
    @input="handleInput"
    @focus="handleFocus>
</BaseInput>

//子组件
<template>
  <label>
    {{ label }}
    <input
      :value="value"
      :placeholder="placeholder"
      @focus=$emit('focus', $event)"
      @input="$emit('input', $event.target.value)"
    >
  </label>
</template>

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

<input
    :value="value"
    v-bind="$attrs"
    v-on="listeners"
>

computed: {
  listeners() {
    return {
      ...this.$listeners,
      input: event => 
        this.$emit('input', event.target.value)
    }
  }
}

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

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