Заметки об опыте разработки Vue (постоянно обновляются)

Vue.js

Краткое изложение проблем или знаний, возникших при разработке vue, которое постоянно обновляется…

Последнее обновление: 2019-11-29

1. Интернационализация

Плагин интернационализации: vue-i18n

2. Принудительный разрыв строки и запрещенный разрыв строки

Пусть несколько строк контента отображают одну строку, а избыток представлен...

white-space : nowrap
overflow: hidden
text-overflow : ellipsis

Принудительный перенос, когда содержимое превышает ширину

overflow: hidden;
word-wrap:break-word;
overflow-wrap: break-word;

Примечание: был переименован в в CSS3, лучше писать оба при использовании

3. Отображение изображений с одинаковой шириной и высотой, ширина соответствует ширине экрана, а высота и ширина равны.

<div class="image-header">
  <img :src="food.image"/>
</div>

.image-header
    position: relative
    width:100%
    height: 0
    padding-top : 100%
    img
        position: absolute
        left: 0
        top: 0
        width: 100%
        height: 100%

Фокус находится на родительском элементеheightустановить на 0,padding-topустановить на 100%

4. Инструменты для преобразования времени

/**
 * Created by solo on 2018/6/6.
 */

export function formatDatetime(date, fmt) {
  if(/(y+)/.test(fmt)){
    fmt = fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4-RegExp.$1.length))
  }

  let obj = {
    "M+": date.getMonth() + 1,
    "d+": date.getDay(),
    "h+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds()
  }

  for(let key in obj){
    if(new RegExp(`(${key})`).test(fmt)){
      let str = obj[key] + ''
      fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str))
    }
  }

  return fmt

}


function padLeftZero(str) {
  return ("00" + str).substr(str.length)
}

использовать

let date = new Date(timestamp)
let fmtDate =  formatDatetime(date, 'yyyy-MM-dd hh:mm')

Вы также можете использовать сторонние библиотеки:moment.js,dayjs

5. Привяжите собственное событие к компоненту

<custom @click.native='handleClick'></custom>

просто нужно@clickдобавить после.nativeВы можете напрямую обрабатывать собственное событие клика

6. Передача значений между компонентами в vue

6.1 Передача значений между родительским и дочерним компонентами

  • Родительский компонент передает значения дочерним компонентам напрямую черезpropsпередать по значению
<custom content="hello world"></custom>
  • Дочерний компонент передает значения родительскому компоненту черезemitотправить событие
this.$emit('chooseType', type)

Родительский компонент получает событие:

<custom content="hello world" @chooseType="handleType"></custom>

6.2 Передача значений из неродительско-дочерних компонентов

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

в корневом узлеVueмонтировать пустойVueобъект

Vue.prototype.bus = new Vue();

В компоненте, который должен отправить событие

this.bus.$emit("change", params)

компонент, который получает событие

this.bus.$on("change", (msg) => {
    //do yourself work
})

7. Динамические компоненты

Динамическое переключение отображаемых компонентов

<component :is='type'></component>

data(){
	components:{
        component-one,
        component-two
	}
    return{
        type: 'component-one'
    }
}

<component>Это официальная метка, предоставленная vue путем измененияisУказывает на имя дочернего компонента для динамического переключения компонентов.

8. директива v-once

Визуализировать только элементы и компонентыоднажды. При последующем повторном рендеринге элемент/компонент и все его дочерние элементы будут рассматриваться как статическое содержимое и будут пропущены. Это можно использовать для оптимизации производительности обновления.

<!-- 单个元素 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 有子元素 -->
<div v-once>
  <h1>comment</h1>
  <p>{{msg}}</p>
</div>
<!-- 组件 -->
<my-component v-once :comment="msg"></my-component>
<!-- `v-for` 指令-->
<ul>
  <li v-for="i in list" v-once>{{i}}</li>
</ul>

9. Переходы и анимация

9.1 Переход

.fade-enter-active, .fade-leave-active{
	transition: opacity 2s
}
.fade-enter, .fade-leave-to{
	opacity: 0
}

9.2 Анимация в сочетании с Animate.css

//引入 animate.css
<link rel="stylesheet" type="text/css" href="animate.css">

//布局
<transition enter-active-class="animated bounce" leave-active-class="animated shake">
	<p v-if="show">hello world</p>
</transition>
<button @click='toggleShow'>toggle</button>

определятьenter-active-classа такжеleave-active-classимя класса и должен иметьanimated, напишите, какой анимационный эффект вы хотите во второй позиции

Устранена ошибка, из-за которой в первый раз не отображалась анимация.

<transition 
	appear 
	enter-active-class="animated bounce" 
	leave-active-class="animated shake" 
	appear-active-class="animated bounce">
	<p v-if="show">hello world</p>
</transition>

существует<transition>добавитьappearа такжеappear-active-classВот и все.

9.3 Совместное использование переходов и анимации

<transition 
    name="fade"
    type='transition'
    appear 
    enter-active-class="animated bounce fade-enter-active" 
    leave-active-class="animated shake fade-leave-active" 
    appear-active-class="animated bounce">
    <p v-if="show">hello world</p>
</transition>

существуетenter-active-classа такжеleave-active-classплюс соответствующее имя классаfade-enter-activeа такжеfade-leave-active, а затем определите эффект перехода в стиле.

.fade-enter-active, .fade-leave-active{
	transition: opacity 2s
}
.fade-enter, .fade-leave-to{
	opacity: 0
}

Зависит ли общая продолжительность выполнения анимации от анимации или от перехода? Вы можете указать вручную:

//指定整体动画时间为过渡动画时间
type='transition'

Вы также можете указать общую продолжительность анимации самостоятельно:

//指定动画时长为10秒
:duration="10000"

//分别指定进场时长5秒和出场动画时长10秒
:duration="{enter: 5000, leave: 10000}"

9.4 Переходы нескольких компонентов и элементов

  • Множественные переходы элементов
<div id="app">
	<transition name="fade" mode="out-in">
		<div v-if="show" key="hello">Hello world</div>
		<div v-else key="bye">Bye world</div>
	</transition>
	<button @click="toggleShow">Add</button>
</div>

Элементы нужно добавитьkey, чтобы предотвратить мультиплексирование элементов vue, приводящее к отсутствию эффекта анимации.

Режим переключения может быть указан,mode="out-in": первый вышел, последний пришел,mode="in-out": первый пришел, последний ушел

  • Переходы нескольких компонентов аналогичны переходам нескольких элементов.

9.5 Переход списка в vue

использоватьtransition-groupАтрибуты

<div id="app">
	<transition-group name="fade">
		<div v-for="item in list" :key="item.id">
			{{item.title}}
		</div>
	</transition-group>
	<button @click="add2List">Add</button>
</div>


<style type="text/css" >
	.fade-enter-active, .fade-leave-active{
		transition: opacity 2s
	}
	.fade-enter, .fade-leave-to{
		opacity: 0
	}
</style>

10. src динамическая привязка тега img

1) Изображение с фиксированным путем

Добавьте путь раньшеrequire()

<img :src="bookingManageImg" slot="icon"/>

bookingManageImg(){
    return this.selectedTab === "bookingManage" ? 	require('../assets/manage_focus.png') : require('../assets/manage_normal.png')
},

2) Путь изображения в цикле for не фиксирован

Если вы используете его непосредственно в циклеrequire()Если это так, webpack будет использовать изображение как модуль, поскольку оно загружается динамически, url-loader не сможет разобрать адрес изображения, поэтому он сообщит об ошибке, что модуль не может быть найден.

Решение состоит в использовании сплайсинга:require('../assets/icons/' + item.icon + '.png'), в объекте хранится только имя изображения, а путь к изображению фиксирован, поэтому запишите его напрямую строкой.

Формат данных списка:

const list = [
    {
      name: "美食",
      icon: "food"
    },
    {
      name: "电影",
      icon: "movie"
    },
]

файл макета:

<div class="item" v-for="item in list">
  <img :src="require('../assets/icons/' + item.icon + '.png')" class="icon">
  <div class="name">{{item.name}}</div>
</div>

11. Решение о потере состояния Vuex после обновления страницы

После обновления страницы данные в vuex будут потеряны, что принесет неудобства при отладке. Поместите данные для входа пользователя вsessionStorageво избежание потерь.

const USER_INFO = "userInfo";

export default new Vuex.Store({
  state: {
    userInfo: JSON.parse(sessionStorage.getItem(USER_INFO))
  },
  mutations: {
    setUserInfo(state, userInfo){
      //存储到 sessionStorage 中以防刷新页面后状态丢失
      sessionStorage.setItem(USER_INFO, JSON.stringify(userInfo));
      state.userInfo = userInfo
    }
  }
}

12. Вернитесь, чтобы запомнить положение полосы прокрутки

Подробный анализ смотрите в статье:Vue возвращается, чтобы запомнить детали положения полосы прокрутки

13. Измените заголовок страницы

первый вrouter.js, каждый маршрут плюсmeta, установить заголовок

routes: [
  {
    path: '/login',
    name: 'login',
    component: Login,
    meta:{
      title:'登录'
    }
  },
  {
    path: '/home',
    name: 'home',
    component: Home,
    children: [],
    meta:{
      title:'主页'
    }
  }
]

затем вmain.jsДинамически изменять заголовок с помощью предварительной маршрутизации

router.beforeEach((to, from, next) => {
  /* 路由发生变化修改页面title */
  if (to.meta.title) {
    document.title = to.meta.title;
  }
  next();
})

14. Включить сжатие Gzip при упаковке

Сначала установите плагин webpack

npm install --save-dev compression-webpack-plugin

опять такиvue.config.jsДобавьте следующий код в:

const CompressionPlugin = require("compression-webpack-plugin")

module.exports = {

  // 基本路径
  baseUrl: './',
  // 输出文件目录
  outputDir: 'dist',
  // 启用 Gzip 压缩
	configureWebpack: () => {
    module.exports = {
      configureWebpack:config=>{
        if(progress.env.NODE_ENV === 'production'){
          return{
            plugins: [

              new CompressionPlugin({
                test:/\.js$|\.html$|.\css/, //匹配文件名
                threshold: 10240,//对超过10k的数据压缩
                deleteOriginalAssets: false //不删除源文件
              })
            ]
          }
        }
      },
    }
  },
}

Vue CLI 3 не имеет его по умолчанию.vue.config.js, просто создайте новый в корневом каталоге, расположение такое же, какpackage.jsonтот же уровень.

15. Vue взаимодействует с нативными приложениями Android

У меня есть статья, посвященная двусторонней связи между vue и Android:

Веб-просмотр Android взаимодействует с js (Vue)

16. Как использовать объявленные scss глобальные переменные в стилях

Переменные, объявленные sass, выглядят так:

$color-primary: #409EFF;
$color-success: #67C23A;
$color-warning: #E6A23C;
$color-danger: #F56C6C;
$color-info: #909399;

Обычный эталонный метод

<style scoped lang="scss">
  @import "../../public/css/index";
  .home {
    color: $color-primary;
  }
</style>

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

Это более проблематично и избыточно в коде. Можно использовать более элегантный способ:sass-resources-loader

использоватьsass-resources-loaderНужно два шага:

  1. Установить зависимости

    npm install sass-resources-loader
    
  2. vue.config.jsконфигурация в.

    Здесь мы используем Vue-CLI 3. Поместите код вresourcesЗамените путь своим путем.

    // vue.config.js
    module.exports = {
      chainWebpack: config => {
        const oneOfsMap = config.module.rule('scss').oneOfs.store
        oneOfsMap.forEach(item => {
          item
            .use('sass-resources-loader')
            .loader('sass-resources-loader')
            .options({
              // Provide path to the file with resources
              resources: './path/to/resources.scss',
    
              // Or array of paths
              resources: ['./path/to/vars.scss', './path/to/mixins.scss']
            })
            .end()
        })
      }
    }
    

Подробные инструкции по настройке для других сред см.официальный сайт sass-resources-loader

После настройки вы можете использовать объявленные sass переменные в любом файле.

17. Измените свойства, переданные родительским компонентом через реквизиты в дочернем компоненте.

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

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

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

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

При этом используется «лазейка», которая инкапсулирует значение, которое должно быть передано в объект, и изменяет значение свойства в объекте без предупреждения. Потому что объект по-прежнему является исходным объектом, но значение внутри изменилось.

Родительский компонент выглядит следующим образом. Обратите внимание на данные вvisible: {value: false}является объектом и не может быть записан какvisible: false, появится предупреждение.

<template>
  <child :visible="visible"/>
</template>

<script>
  export default {
    components: {
    	child
    },
    data(){
    	return{
    		visible: {value: false}
    	}
    }
  }
</script>

Подкомпоненты следующие:

<el-dialog :visible.sync="visible.value">

Что меняется, когда дочерний компонент изменяет значениеvisibleв объектеvalueАтрибуты. Таким образом, вы можете напрямую изменить значение родительского компонента через дочерний компонент.

18. Реализация Цзюгунге

Реализуйте аналогичный код Jiugongge:

<template>
  <div class="view-home">
    <div class="category-wrapper">
      <div class="category-name">分类一</div>
      <div class="icons">
        <div class="item" v-for="item in list">
          <img :src="require('../assets/icons/' + item.icon + '.png')" class="icon">
          <div class="name">{{item.name}}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

  const LIST = [
    {name: "电影",icon: "movie"},
    {name: "美食",icon: "food"},
    {name: "美发",icon: "hair"},
    {name: "周边游",icon: "around"},
    {name: "酒店",icon: "hotel"},
    {name: '代购',con: "dg"}
  ];

  export default {
    components: {},
    data() {
      return {
        list: ICON_LIST,
      }
    },
  }
</script>

<style scoped lang="scss">
  .view-home {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: px2rem(10);
    box-sizing: border-box;

    .category-wrapper {
      width: 100%;
      display: flex;
      flex-direction: column;
      background-color: white;

      .category-name {
        font-size: $font-size-normal;
        color: $text-main;
        padding: px2rem(12);
        border-bottom: px2rem(1) solid $border-third;
      }

      .icons {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;

        .item {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          width: 25%;
          padding: px2rem(10) 0;

          .icon {
            width: px2rem(40);
            height: px2rem(40);
          }

          .name {
            font-size: $font-size-small;
            color: $text-normal;
            margin-top: px2rem(10);
          }
        }
      }
    }
  }
</style>

Основные моменты:

  1. Если вы хотите автоматически перенести строку, используйте следующие три строки кода:

    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    
  2. Несколько значков в строке, контролируемых шириной элемента. Если в строке четыре значка, ширина элемента составляет 25 %, а если в строке пять значков, ширина каждого элемента составляет 20 %.

19. Скольжение за пределы ширины

Когда ширина дочернего компонента превышает ширину родительского компонента, реализуется горизонтальное скольжение.
Родительский компонент может быть корневым элементом всего экрана или отдельным элементом. Просто хорошо настройте css.
установить родительский элементclass=parent, дочерний элементclass=child

.parent{
    //其他样式省略,只列出控制横向滑动必须的代码
    display: flex;
    overflow-x: auto;
    overflow-y: hidden; 
    
    .child{
        // 其他样式省略,只列出控制横向滑动必须的代码
        //这句话的意思是不会被压缩大小
        flex-shrink: 0;
    }
}

Добавьте эти строки в свой код CSS, чтобы добиться горизонтального скольжения.

20. Отображать только n строк, лишние обозначаются многоточием

Часто бывает необходимо отобразить только две или три строки, а лишнее обозначается многоточием.
Сфера применения: Поскольку используется свойство расширения CSS WebKit, этот метод подходит для браузеров WebKit и мобильных терминалов;

Примечание:
-webkit-line-clamp используется для ограничения количества строк текста, отображаемого в блочном элементе. Для достижения этого эффекта необходимо объединить другие свойства WebKit.
Общие свойства связывания:
display: -webkit-box: свойство, которое необходимо комбинировать для отображения объекта в виде гибкой блочной модели.
-webkit-box-orient: свойство, которое необходимо комбинировать, чтобы установить или получить расположение дочерних элементов объекта flexbox.

overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

21. В гибкой верстке один элемент выравнивается по правому краю.

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

Известно, что макет родительского элемента

display: flex;
flex-direction: row;
align-items: center;

Есть три способа сделать это:

  1. Добавьте еще один слой div к двум элементам имени и пола и установите этот divflex: 1. Недостатком является то, что существует много слоев вложенности, что немного хлопотно.
  2. Установите значок комментария для этого элемента
    flex: 1;
    text-align: right;
    
  3. Установите значок комментария для этого элемента
    margin-left: auto;
    

Последние два метода относительно просты и рекомендуются.