Навыки Vue, приобретенные в Vue-Element-Admin

Vue.js
Прочитав исходный код Vue-Element-Admin, я получил несколько советов при написании системы управления фоном, например, посмотреть, насколько элегантен код босса, как босс инкапсулирует бизнес-компоненты и как босс планирует систему управления фоном. Архитектура проекта и т.д. # svg icon ## Входящие атрибуты и события во время вторичной инкапсуляции Когда `v-on="$listeners"` инкапсулирует компоненты, могут быть переданы нераспознанные события. `v-bind="$attrs"` может передавать нераспознанные атрибуты

layout

Vuex централизованно управляет состоянием

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

Адаптация мобильного терминала

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

Различать внутренние маршруты и внешние ссылки

динамические компонентыv-bindУникальный метод письма

<component :is="type" v-bind="linkProps(to)">
<slot />
</component>
methods: {
  linkProps(to) {
    if (this.isExternal) {
      return {
        href: to,
        target: '_blank',
        rel: 'noopener'
      }
    }
    return {
    	to: to
    }
  }
}

Вкладка История

1. Горизонтальную полосу прокрутки можно прокручивать колесиком мыши.
2. Всплывающее меню правой кнопкой мыши.
3. Полоса прокрутки может прокручиваться до определенной позиции

Обработка горизонтальной полосы прокрутки

компонент панели прокрутки, прослушивающий события колесика мыши,

<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
<slot />
</el-scrollbar>

Изменить горизонтальное смещение полосы прокрутки

handleScroll(e) {
  const eventDelta = e.wheelDelta || -e.deltaY * 40
  const $scrollWrapper = this.scrollWrapper
  $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
}

контекстное меню

@contextmenu.prevent.native

прокрутить до указанной позиции

Манипулировать домом без jquery
const container=this.container = this.refs.scrollContainer.el<br/>constel<br />const containerWidth = $container.offsetWidth

moveToTarget(currentTag) {
      const $container = this.$refs.scrollContainer.$el
      const $containerWidth = $container.offsetWidth
      const $scrollWrapper = this.scrollWrapper
      const tagList = this.$parent.$refs.tag

      let firstTag = null
      let lastTag = null

      // find first tag and last tag
      if (tagList.length > 0) {
        firstTag = tagList[0]
        lastTag = tagList[tagList.length - 1]
      }

      if (firstTag === currentTag) {
        $scrollWrapper.scrollLeft = 0
      } else if (lastTag === currentTag) {
        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
      } else {
        // find preTag and nextTag
        const currentIndex = tagList.findIndex(item => item === currentTag)
        const prevTag = tagList[currentIndex - 1]
        const nextTag = tagList[currentIndex + 1]

        // the tag's offsetLeft after of nextTag
        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing

        // the tag's offsetLeft before of prevTag
        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing

        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
        }
      }
    }

RgihtPanel

установлен на корпусе

insertToBody() {
  const elx = this.$refs.rightPanel
  // 或是  const elx = this.$
  const body = document.querySelector('body')
  body.insertBefore(elx, body.firstChild)
}

Метод создания пакета

import Vue from 'vue'
function create(Component, props) {
  const vm = new Vue({
    render(h) {
    return h(Component, {props})
	}
}).$mount();
  document.body.appendChild(vm.$el);
  const comp = vm.$children[0];
  comp.remove = () => {
  document.body.removeChild(vm.$el);
  vm.$destroy();
	}
	return comp;
}
export default create;

Нажмите на формулировку слоя маски, чтобы закрыть

evt.target.closest определяет, является ли область, по которой щелкнули, маской

closeSidebar(evt) {
const parent = evt.target.closest('.rightPanel')
if (!parent) {
this.show = false
window.removeEventListener('click', this.closeSidebar)

Анимация перехода при переключении маршрута

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
  transition: all .5s;
}

.fade-transform-enter {
  opacity: 0;
  transform: translateX(-30px);
}

.fade-transform-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

индикатор выполнения страницы

import NProgress from 'nprogress'; // progress bar
import 'nprogress/nprogress.css'; // progress bar style

NProgress.configure({ showSpinner: false }); // NProgress Configuration

router.beforeEach((to, from, next) => {
  // token start
  NProgress.start();
  next();
  NProgress.done();
});

разрешения на уровне кнопок

Пользовательская директива v-permission

Логика: Передаем разрешение кнопки, получаем разрешение текущего пользователя, определяем есть ли разрешение пользователя в разрешении кнопки, если нет, значит разрешения нет, удаляем DOM кнопки.

верх

плавная прокрутка

Исходный код не прост для понимания, и с помощью Interval я сам его оптимизировал, и принял метод сглаживания кадра анимации к верху

backToTop() {
  if (this.isMoving) return
  const scrollTop = window.pageYOffset
  if (scrollTop > this.backPosition) {
    window.requestAnimationFrame(this.backToTop)
    window.scrollTo(0, scrollTop - scrollTop / 20)
  }
}

библиотека иконок svg

  1. Зарегистрируйте компонент диаграммы svg глобально
  2. Автоматически импортировать ресурсы SVG
require.context('./svg', false, /\.svg$/)

Динамически загружать скрипты

Редактор уценки

плагин tui-editor
Элемент конфигурации отдельного управления js

Sticky

Прислушайтесь к прокрутке и используйте API getBoundingClientRect(), чтобы получить размер элемента и его положение относительно области просмотра.
Когда высота меньше, чем переданный stickyTop, установите фиксированную позицию элемента.

handleScroll() {
  const width = this.$el.getBoundingClientRect().width
  this.width = width || 'auto'
  const offsetTop = this.$el.getBoundingClientRect().top
  if (offsetTop < this.stickyTop) {
    this.sticky()
    return
  }
  this.handleReset()
},
sticky() {
  if (this.active) {
    return
  }
  this.position = 'fixed'
  this.active = true
  this.width = this.width + 'px'
  this.isSticky = true
},

кнопка эффект волны воды

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

Примечание. Мониторинг и отвязка событий кликов

.....
if (!el[context]) {
    el[context] = {
      removeHandle: handle
    }
  } else {
    el[context].removeHandle = handle
  }

  return handle
}

export default {
  bind(el, binding) {
    el.addEventListener('click', handleClick(el, binding), false)
  },
  update(el, binding) {
    el.removeEventListener('click', el[context].removeHandle, false)
    el.addEventListener('click', handleClick(el, binding), false)
  },
  unbind(el) {
    el.removeEventListener('click', el[context].removeHandle, false)
    el[context] = null
    delete el[context]
  }
}

Диаграмма

resize mixin

Поместите в миксин монитор обработки ресайза вьюпорта, обратите внимание на отвязку события ресайза

лист

Фильтр записи

<el-table-column label="Status" class-name="status-col" width="100">
  <template slot-scope="{row}">
    <el-tag :type="row.status | statusFilter">
      {{ row.status }}
    </el-tag>
	</template>
</el-table-column>  

filters: {
    statusFilter(status) {
      const statusMap = {
        published: 'success',
        draft: 'info',
        deleted: 'danger'
      }
      return statusMap[status]
    },
    typeFilter(type) {
      return calendarTypeKeyValue[type]
    }
  },