Коллекция практических навыков Vue

задняя часть внешний интерфейс GitHub Vue.js

предисловие

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

Эта статья не охватывает罕见APIМетоды использования и т. д. Большая часть контента основана на некоторой практике работы с Vue. Из-за предполагаемого оппортунизма это может привести к некоторым побочным эффектам, которые не соответствуют спецификациям, пожалуйста, используйте его в соответствии с требованиями проекта.

  1. Метод, используемый несколькими страницами, помещается вvue.prototypeНа будет очень удобно

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

    import port from './xxxx/xxxx/post'
    

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

    // 假设正常是这样
    import port from '../xxxx/xxxx/post'
    // 目录加深一级,就变成这样
    import port from '../../xxxx/xxxx/post'
    // 再加深一级的样子
    import port from '../../../xxxx/xxxx/post'
    

    Конечно, в настоящее время мы можем использовать псевдонимы@/xxxx/post, но по-прежнему нужна ссылка на каждую страницу. Тогда давайте посмотрим, используяvue.prototypeНасколько это удобно? Во-первых, вы должныvueвходной файл (vue-cliДля сгенерированного проекта по умолчанию/src/main.js) и выполните следующие настройки

     import port from './xxxx/xxxx/post'
    
     vue.prototype.$post = post   
    

    Таким образом, мы можем иметь всеvueИспользуется в компонентах (страницах)this.post()метод, какvueкак собственный сын

    Совет: повесьте метод наprototypeПри подъеме лучше добавить$префикс, чтобы избежать конфликтов с другими переменными

    еще раз: не устанавливайте слишком много методов дляprototype, монтировать только некоторые очень часто используемые

  2. Данные, на которые необходимо ответить, должны быть установлены первыми при получении данных интерфейса.

    Часто ли вы сталкивались с такой ситуацией?При зацикливании списка нам нужно присвоить элементу списка атрибут, управляющий отображением, например, можно ли его удалить, был ли он выбран и т. Интерфейс обычно не возвращает это поле, потому что оно принадлежит чисто внешнему отображению и не имеет ничего общего с бэк-эндом.Например, данные, выдаваемые бэкэндом, выглядят следующим образом

    [
      {name: 'abc', age: 18},
      {name: 'def', age: 20},
      {name: 'ghi', age: 22},
    ]
    

    Предположим, что приведенные выше данные представляют собой список студентов.

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

    Если мы сначала добавим галочку к каждому элементу массива при получении данных, мы сможем решить эту проблему.Мы предполагаем, что данные, которые мы получаем,res.list

    res.list.map(item => { 
      item.isTicked = false
    })
    

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

  3. Инкапсулировать на глобальной основеpromiseМетод асинхронного запроса

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

    axios({
      method: 'post',
      url: '/user/12345',
      data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
      }
    })
     .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });
    

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

    function post (url,param) {
        return axios({
          method: 'post',
          url: url,
          data: param
          ... axios 的其他配置
        })
    }
    
    

    Совет: оказалось, что я использовал дополнительный слой обещания, чтобы обернуть его, что слишком много для простых нужд.Я чувствую, что пользователи Nuggets@日月为易。указать

    В сочетании с первым пунктом мы можем произвольноvueПример использования вот так

    let param = {
      firstName: 'Fred',
      lastName: 'Flintstone'
    }
    this.post('/user/12345',param)
    .then(...)
    .catch(...)
    

    Он намного проще оригинала? если ваш проект поддерживаетasync await, вы также можете использовать

    let param = {
      firstName: 'Fred',
      lastName: 'Flintstone'
    }
    let res  = await this.post('/user/12345',param)
    console.log(res) // res 就是异步返回的数据
    
    

    tip: awaitКлючевые слова должны быть в被 async 修饰的函数里面使用

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

    vueСуществует множество способов передачи значений между родительским и дочерним компонентамиjavascriptФункция ссылочного типа также достигает другой цели передачи по значению.

    Предположим, есть такое требование, родительский компонент должен передать 3 значения дочернему компоненту, а затем после изменения в дочернем компоненте ему нужно сразу ответить родительскому компоненту.this.$emitСобытие генерируется, а затем родительский компонент прослушивает соответствующее событие.Однако хорошо иметь дело с одним или двумя данными.Если данных слишком много, это будет утомительно. С тем же успехом мы могли бы обернуть передаваемые данные в объект/массив, а затем передать их дочернему компоненту.

    <subComponent :subData="subData"></subComponent>
    
    data () {
      return {
        subData: {
          filed1: 'field1',
          filed2: 'field2',
          filed3: 'field3',
          filed4: 'field4',
          filed5: 'field5',
        }
      }
    }
    

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

    Совет: во-первых, я лично считаю, что делать это немного не по спецификации.Если у вас не так много данных, просто послушно используйте их.this.$emitНу, во-вторых, эти данные нужно строить при определенных условиях, что применимо далеко не во всех случаях.

  5. Параметры асинхронного запроса находятся вdataОн хорошо сконструирован и завернут в объект, что будет намного удобнее

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

     <input type="text" v-model="field1">
     <input type="text" v-model="field2">
     <input type="text" v-model="field3">
     ....
     <input type="text" v-model="fieldn">
    
    data () {
     return {
       field1: 'value1',
       field2: 'value2',
       field3: 'value3',
       ...
       fieldn:'valuen'
     }
    }
    

    Затем при отправке данных следующим образом:

     var param = {
       backend_field1: this.field1,
       backend_field2: this.field2,
       backend_field3: this.field3,
       ...
       backend_fieldn: this.fieldn
     }
     this.post(url,param)
    

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

        <input type="text" v-model="queryParam.backend_field1">
        <input type="text" v-model="queryParam.backend_field2">
        <input type="text" v-model="queryParam.backend_field3">
        ....
        <input type="text" v-model="queryParam.backend_fieldn">
       ```
      
       ```javascript
       data () {
        return {
          queryParam:{
            backend_field1: 'value1'
            backend_field2: 'value2'
            backend_field3: 'value3'
            ...
            backend_fieldn: 'valuen'
          }
        }
       }
       ```
       然后提交数据的时候这样:
       ```javascript
        this.post(url,this.queryParam)
       ```
    是的,这样做也是有局限性的,比如你一个数据在 2 个地方共用,比如前端组件绑定的是一个数组,你需要提交给后端的是 2 个字符串(例:`element ui` 的时间控件),不过部分特殊问题稍微处理一下,也比重新构建一个参数简单不是吗?
    
    
    
  6. dataКогда в нем много данных, добавляйте примечание к каждому из них, что сделает его понятным, когда вы будете оглядываться назад.

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

    data () {
     return {
       field1: 'value1',  // 控制xxx显示
       field2: 'value2',  // 页面加载状态
       field3: [],        // 用户列表
       ...
       fieldn: 'valuen'   // XXXXXXXX
     }
    }
    
  7. Для сложного логического контента попробуйте разбить его на компоненты.

    Предположим, у нас есть такой сценарий:

    <div>
       <div>姓名:{{user1.name}}</div>
       <div>性别:{{user1.sex}}</div>
       <div>年龄:{{user1.age}}</div>
       ...此处省略999个字段...
       <div>他隔壁邻居的阿姨家小狗的名字:{{user1.petName}}</div>
    </div>
    <-- 当然,显示中我们不会傻到不用 v-for,我们假设这种情况无法用v-for -->
    <div>
        <div>姓名:{{user2.name}}</div>
        <div>性别:{{user2.sex}}</div>
        <div>年龄:{{user2.age}}</div>
        ...此处省略999个字段...
        <div>他隔壁邻居的阿姨家小狗的名字:{{user2.petName}}</div>
    </div>
    

    В этом случае мы могли бы также извлечь код [пользователя] в компонент: Предположим, следующий код вcomUserInfo.vue

    <template>
     <div>
       <div>姓名:{{user.name}}</div>
       <div>性别:{{user.sex}}</div>
       <div>年龄:{{user.age}}</div>
       ...此处省略999个字段...
       <div>他隔壁邻居的阿姨家小狗的名字:{{user.petName}}</div>
     </div>
    </template>
    
    <script >
    export  default {
     props:{
       user:{
         type:Object,
         default: () => {}
       }
     }
    }
    </script>
    

    Затем исходную страницу можно изменить на эту (исключая компоненты импорта и регистрации, предполагая, что зарегистрированное имяcomUserInfo):

    <comUserInfo :user="user1"/>
    <comUserInfo :user="user2"/>
    

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

  8. Если вы меняете только одно значение родительского компонента в дочернем компоненте, попробуйте$emit('input'), изменится напрямуюv-model

    Наша обычная связь между родительским и дочерним компонентами осуществляется через родительский компонент.propsПередайте его дочернему компоненту, дочерний компонент передаетthis.$emit('eventName',value)Уведомить родительский компонент о привязке@eventNameвышеуказанный метод для выполнения соответствующей обработки. Но здесь есть исключение,vueПо умолчанию он будет прослушивать компонентinputсобытие и присвоить значение, переданное от подкомпонента к текущей привязке кv-modelзначение на

    Обычное использование — родительский компонент

    <template>
      <subComponent :data="param" @dataChange="dataChangeHandler"></subComponent>
    </template>
    
    <script >
      export default {
        data () {
          return {
            param:'xxxxxx'
          }
        },
        methods:{
          dataChangeHandler (newParam) {
            this.param = newParam
          }
        }
      }
    </script>
    

    Обычное использование — дочерние компоненты

    <script >
      export default {
        methods:{
          updateData (newParam) {
            this.$emit('dataChange',newParam)
          }
        }
      }
    </script>
    

    использовать значение по умолчаниюinputсобытие - родительский компонент

    <template>
      <subComponent  v-model="param"></subComponent>
    </template>
    

    использовать значение по умолчаниюinputСобытия — дочерние компоненты

    <script >
      export default {
        methods:{
          updateData (newParam) {
            this.$emit('input',newParam)
          }
        }
      }
    </script>
    

    Таким образом, мы можем сохранить код обработки места в родительском компоненте,vueавтоматически обработает это для вас

    совет: этот метод подходит только для изменения одного значения, а дочернему компоненту достаточно просто передать значение родительскому компоненту, и никаких других дополнительных операций (таких как обновление списка) не требуется.

    добавить одинthis.$emit('update:fidldName',value)Метод (благодаря пользователям Nuggets@日月为易。указал)Конкретное использование заключается в следующем:

    родительский компонент

        <subComponent field1.sync="param1" field2.sync="param2"></subComponent>
    

    Подсборка

    <script >
      export default {
        methods:{
          updateData1 (newValue) {
            this.$emit('update:field1',newValue)
          },
          updateData2 (newValue) {
            this.$emit('update:field2',newValue)
          }
        }
      }
    </script>
    

    Этот метод лично считаю более подходящим для обновления данных, которые не могут быть привязаны кv-modelВ случае, если данные для передачи в обоих направлениях больше 1 (1 тоже можно использовать, но лично я рекомендуюinputкстати, это зависит от личных предпочтений), но не во многих случаях.

  9. conponentsпомещатьVue optionsвершина

    Я не знаю, есть ли у вас такой опыт: импорт компонентов, а затем их использование на странице, ок, сообщается об ошибке, почему? Забыли зарегистрировать компоненты, почему вы часто забываете регистрировать компоненты? потому что нормальныйvueСтруктура экземпляра выглядит следующим образом:

    import xxx form 'xxx/xxx'
    export default {
      name: 'component-name',
      data () {
        return {
          // ...根据业务逻辑的复杂程度,这里省略若干行
        }
      },
      computed: {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      created () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      mounted () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      methods () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
    }
    

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

    позже я положилcomponentsнастроиться на первую

    import xxx form 'xxx/xxx'
    export default {
      components: {
        xxx
      },
      // 省略其他代码
    }
    

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

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

    Я видел много кода, в том числе свой собственный, и написал одну-две сотни строк кода в жизненном цикле, например: когда страница загружается, все вещи, которые должны быть сделаны, написаны наcreatedВнутри весь код плохо читается, и вы понятия не имеете, что делали, когда загружалась страница, В настоящее время мы могли бы также инкапсулировать эту логику в методы, а затем вызывать их непосредственно в жизненном цикле:

    created () {
      // 获取用户信息
      this.getUserInfo()
      // 获取系统信息
      this.getSystemInfo()
      // 获取配置
      this.getConfigInfo()
    },
    methods:{
      // 获取用户信息
      getUserInfo () {...},
      // 获取系统信息
      getSystemInfo () {...},
      // 获取配置
      getConfigInfo () {...},
    }
    

    Позволяет ли это легко увидеть с первого взгляда, что вы делаете, когда страница загружается?

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

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

    vueЭто сама по себе структура, управляемая данными. Изменения в данных могут передаваться обратно в представление в режиме реального времени. Если вы хотите контролировать попытку на основе данных, сотрудничайте при нормальных обстоятельствах.computedВзяв его, можно решить большинство проблем, а за изменениями в представлении мы вообще можем следитьinput changeи другие события для достижения цели мониторинга в реальном времени, Так что очень мало нужно использоватьwatchПо крайней мере, я не использовал его в дюжине или около того проектов, в которых я был недавно.watchКонечно, не тоwatchоднозначно бесполезен,vueДолжны быть его причины для предоставления этого API, и есть некоторые потребности, которые действительно нужно использовать, но я думаю, что его следует использовать редко.Если вы считаете, что вам нужно использовать его везде, тогда я думаюВ девяти случаях из десятитебе стоит познакомитьсяcomputedа такжеvueдругойapiохватывать

наконец

Адрес этой статьи на githubНе стесняйтесьstar,follow, и непроизвольноеissue

Кроме того,githubЕсть несколько других руководств и компонентов о внешнем интерфейсе на Заинтересованная детская обувь может посмотреть, ваша поддержка-моя самая большая мотивация.