Впереди высокая энергия, это последняя волна боевых навыков Vue, это бесполезно и потрясающе.

JavaScript Vue.js

Светящаяся чаша вина и винограда, если вы хотите пить продукты Pipa. Лорд Мрачный на месте заказчика, сколько людей было похоронено в древности?

В последнее время я занимаюсь разработкой системы управления фоном.Я повторяю формы,таблицы,формы и стандартные резюме день за днем.Мне так скучно.Как мне улучшить себя в этом скучном процессе разработки?wave newVueПрактические боевые навыки, эти навыки, если они вам не нужны, потрясающие. Вы также можете нажать на ссылку ниже, чтобы прочитать наши последние статьи.

Практические навыки, Vue тоже умеет так писать1700+ лайков

Абсолютно сухой материал~! Изучите эти советы Vue, вы сможете уйти с работы пораньше и встречаться с богиней970+ лайков

Смотрите заработало! Перечитывая руководство по стилю vue 2.0, я сформулировал эти ключевые правила.Понравилось 120+

Слот, я собираюсь просверлить твои руки

Слоты, доверяйте всемVueВсе они были использованы, но как лучше понять слот и как настроить слот, сегодня Xiaobian предлагает вам более яркое описание.

слот по умолчанию

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

1. Застройщик наконец-то завершил разработку однокомнатной квартиры и сдал дом

<template>
  <!--这是一个一居室-->
  <div class="one-bedroom">
    <!--添加一个默认插槽,用户可以在外部随意定义这个一居室的内容-->
    <slot></slot>
  </div>
</template>

2. Я собираюсь начать украшать

<template>
  <!--这里一居室-->
  <one-bedroom>
    <!--将家具放到房间里面,组件内部就是上面提供的默认插槽的空间-->
    <span>先放一个小床,反正没有女朋友</span>
    <span>再放一个电脑桌,在家还要加班写bug</span>
  </one-bedroom>
</template>
<script>
import OneBedroom from '../components/one-bedroom'
export default {
  components: {
    OneBedroom
  }
}
</script>

именованный слот

Через несколько лет у редактора появилась девушка, и он собирался жениться. Однокомнатная комната точно не подошла бы. Свекровь считала ее слишком маленькой, поэтому мне ничего не оставалось, как наскрести деньги на покупку. большой дом и двухкомнатная (бедная принудительная), поскольку это двухкомнатная, есть разница между главной спальней и второй спальней.Не может ли украшение сделать главную спальню и вторую спальню точно то же самое, поэтому его нужно различать. Думайте о доме как о компоненте, тогда у компонента есть два слота, и его нужно назвать, чтобы его можно было отличить.

1. Застройщик наконец-то завершил разработку и сдал дом

<template>
  <div class="two-bedroom">
    <!--这是主卧-->
    <div class="master-bedroom">
      <!---主卧使用默认插槽-->
      <slot></slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard"></slot>
    </div>
  </div>
</template>

2. Редактор собирается продать кровь, чтобы сэкономить на украшении

<template>
  <two-bedroom>
    <!--主卧使用默认插槽-->
    <div>
      <span>放一个大床,要结婚了,嘿嘿嘿</span>
      <span>放一个衣柜,老婆的衣服太多了</span>
      <span>算了,还是放一个电脑桌吧,还要写bug</span>
    </div>
    <!--次卧,通过v-slot:secondard 可以指定使用哪一个具名插槽, v-slot:secondard 也可以简写为 #secondard-->
    <template v-slot:secondard>
      <div>
        <span>父母要住,放一个硬一点的床,软床对腰不好</span>
        <span>放一个衣柜</span>
      </div>
    </template>
  </two-bedroom>
</template>
<script>
import TwoBedroom from '../components/slot/two-bedroom'
export default {
  components: {
    TwoBedroom
  }
}
</script>

слот с прицелом

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

1. Посмотрите параметры, переданные в слот туалета

<template>
  <div class="two-bedroom">
    <!--其他内容省略-->
    <div class="toilet">
      <!--通过v-bind 可以向外传递参数, 告诉外面卫生间可以放洗衣机-->
      <slot name="toilet" v-bind="{ washer: true }"></slot>
    </div>
  </div>
</template>

2. Поставьте стиральную машину в ванной

<template>
  <two-bedroom>
    <!--其他省略-->
    <!--卫生间插槽,通过v-slot="scope"可以获取组件内部通过v-bind传的值-->
    <template v-slot:toilet="scope">
      <!--判断是否可以放洗衣机-->
      <span v-if="scope.washer">这里放洗衣机</span>
    </template>
  </two-bedroom>
</template>

слот по умолчанию

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

1. Это отремонтированный подержанный дом.

<template>
  <div class="second-hand-house">
    <div class="master-bedroom">
      <!--插槽可以指定默认值,如果外部调用组件时没有修改插槽内容,则使用默认插槽-->
      <slot>
        <span>这里有一张水床,玩的够嗨</span>
        <span>还有一个衣柜,有点旧了</span>
      </slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard">
        <span>这里有一张婴儿床</span>
      </slot>
    </div>
  </div>
</template>

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

<second-hand-house>
    <!--主卧使用默认插槽,只装修主卧-->
    <div>
      <span>放一个大床,要结婚了,嘿嘿嘿</span>
      <span>放一个衣柜,老婆的衣服太多了</span>
      <span>算了,还是放一个电脑桌吧,还要写bug</span>
    </div>
  </second-hand-house>

Понимание стратегии слияния опций, функция крюка пользовательского жизненного цикла

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

1. ПонятьVueСтратегия слияния

существуетVue, разные варианты имеют разные стратегии слияния, напримерdata,props,methodsСвойства с одним и тем же именем переопределяются и объединяются, другие объединяются напрямую, а функция ловушки жизненного цикла состоит в том, чтобы поместить функции с тем же именем в массив и вызывать их по очереди при вызове. к статье перед редактором.Абсолютно сухой материал~! Изучите эти советы Vue, вы сможете уйти с работы пораньше и встречаться с богиней

существуетVue, обеспечиваетapi, Vue.config.optionMergeStrategies, Вы можете использовать этот API для настройки стратегии слияния параметров.

печатать в коде

console.log(Vue.config.optionMergeStrategies)
控制台打印内容
консольная печать

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

2. Настройте функцию жизненного цикла с помощью стратегии слияния.

задний план

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

Позже я обнаружил, что на странице много таймеров,ajaxАнимации есть и в опросе.Открыть вкладку браузера не проблема.Если открыть слишком много, браузер зависнет.На этот раз я подумал,что если можно остановить их,когда пользователь переключает вкладки,то он решиться в ближайшее время. . Искал вдоль и поперёк в Baidu и нашёл событиеvisibilitychange, который можно использовать для определения того, отображается ли вкладка браузера.

Есть способ, напиши

export default {
  created() {
    window.addEventListener('visibilitychange', this.$_hanldeVisiblityChange)
    // 此处用了hookEvent,可以参考小编前一篇文章
    this.$on('hook:beforeDestroy', () => {
      window.removeEventListener(
        'visibilitychange',
        this.$_hanldeVisiblityChange
      )
    })
  },
  methods: {
    $_hanldeVisiblityChange() {
      if (document.visibilityState === 'hidden') {
        // 停掉那一堆东西
      }
      if (document.visibilityState === 'visible') {
        // 开启那一堆东西
      }
    }
  }
}

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

Пользовательская функция хука жизненного цикла

Определение функций жизненного циклаpageHiddenиpageVisible

import Vue from 'vue'

// 通知所有组件页面状态发生了变化
const notifyVisibilityChange = (lifeCycleName, vm) => {
  // 生命周期函数会存在$options中,通过$options[lifeCycleName]获取生命周期
  const lifeCycles = vm.$options[lifeCycleName]
  // 因为使用了created的合并策略,所以是一个数组
  if (lifeCycles && lifeCycles.length) {
    // 遍历 lifeCycleName对应的生命周期函数列表,依次执行
    lifeCycles.forEach(lifecycle => {
      lifecycle.call(vm)
    })
  }
  // 遍历所有的子组件,然后依次递归执行
  if (vm.$children && vm.$children.length) {
    vm.$children.forEach(child => {
      notifyVisibilityChange(lifeCycleName, child)
    })
  }
}

/**
 * 添加生命周期钩子函数
 * @param {*} rootVm vue 根实例,在页面显示隐藏时候,通过root向下通知
 */
export function init() {
  const optionMergeStrategies = Vue.config.optionMergeStrategies
  /*
    定义了两个生命周期函数 pageVisible, pageHidden
    为什么要赋值为 optionMergeStrategies.created呢
    这个相当于指定 pageVisible, pageHidden 的合并策略与 created的相同(其他生命周期函数都一样)
   */
  optionMergeStrategies.pageVisible = optionMergeStrategies.beforeCreate
  optionMergeStrategies.pageHidden = optionMergeStrategies.created
}

/**
 * 将事件变化绑定到根节点上面
 * @param {*} rootVm
 */
export function bind(rootVm) {
  window.addEventListener('visibilitychange', () => {
    // 判断调用哪个生命周期函数
    let lifeCycleName = undefined
    if (document.visibilityState === 'hidden') {
      lifeCycleName = 'pageHidden'
    } else if (document.visibilityState === 'visible') {
      lifeCycleName = 'pageVisible'
    }
    if (lifeCycleName) {
      // 通过所有组件生命周期发生变化了
      notifyVisibilityChange(lifeCycleName, rootVm)
    }
  })
}

применение

  1. существуетmain.jsИмпорт файла основной записи
import { init, bind } from './utils/custom-life-cycle'

// 初始化生命周期函数, 必须在Vue实例化之前确定合并策略
init()

const vm = new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

// 将rootVm 绑定到生命周期函数监听里面
bind(vm)

  1. Прислушивайтесь к функциям жизненного цикла там, где это необходимо
export default {
  pageVisible() {
    console.log('页面显示出来了')
  },
  pageHidden() {
    console.log('页面隐藏了')
  }
}

provideиinject, не только отец и сын передают значение, но и значение предка также может быть передано

VueРелевантные интервью часто задают интервьюеры,VueКаковы пути передачи ценностей между отцом и сыном, обычно мы ответим,propsпроходное значение,$emitзначение прохода события,vuexпередать по значению иeventbusПередача по значению и т. д., добавьте сегодня еще одинprovideиinjectпередать по значениюofferНа шаг ближе. (Да, в следующем разделе есть еще один)

использовалReactстуденты знают, что вReactимеет контекстContext, компонент может пройтиContextпередать значение любому потомку, в то время какVueизprovideиinjectдействующий наContextв основном то же самое

Позвольте мне привести Вам пример

использовалelemment-uiУчащиеся должны быть знакомы со следующим кодом

<template>
  <el-form :model="formData" size="small">
    <el-form-item label="姓名" prop="name">
      <el-input v-model="formData.name" />
    </el-form-item>
    <el-form-item label="年龄" prop="age">
      <el-input-number v-model="formData.age" />
    </el-form-item>
    <el-button>提交</el-button>
  </el-form>
</template>
<script>
export default {
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}
</script>

После прочтения приведенного выше кода кажется, что в этом нет ничего особенного, пишите его каждый день. существуетel-formВыше мы указали свойствоsize="small", а потом нашли все элементы формы и кнопки в формеsizeсталsmall, это как это сделать? Далее смоделируем форму почерком

рукописная форма

теперь мы подражаемelement-uiформу, настройте ее самостоятельно, каталог файлов выглядит следующим образом

пользовательская формаcustom-form.vue

<template>
  <form class="custom-form">
    <slot></slot>
  </form>
</template>
<script>
export default {
  props: {
    // 控制表单元素的大小
    size: {
      type: String,
      default: 'default',
      // size 只能是下面的四个值
      validator(value) {
        return ['default', 'large', 'small', 'mini'].includes(value)
      }
    },
    // 控制表单元素的禁用状态
    disabled: {
      type: Boolean,
      default: false
    }
  },
  // 通过provide将当前表单实例传递到所有后代组件中
  provide() {
    return {
      customForm: this
    }
  }
}
</script>

В приведенном выше коде мы передаемprovideПередать экземпляр текущего компонента компонентам-потомкам,provideэто функция, которая возвращает объект

пользовательский элемент формыcustom-form-item.vue

Ничего особенного, просто добавилlabel,element-uiсложнее

<template>
  <div class="custom-form-item">
    <label class="custom-form-item__label">{{ label }}</label>
    <div class="custom-form-item__content">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    label: {
      type: String,
      default: ''
    }
  }
}
</script>

пользовательское поле вводаcustom-input.vue

<template>
  <div
    class="custom-input"
    :class="[
      `custom-input--${getSize}`,
      getDisabled && `custom-input--disabled`
    ]"
  >
    <input class="custom-input__input" :value="value" @input="$_handleChange" />
  </div>
</template>
<script>
/* eslint-disable vue/require-default-prop */
export default {
  props: {
    // 这里用了自定义v-model
    value: {
      type: String,
      default: ''
    },
    size: {
      type: String
    },
    disabled: {
      type: Boolean
    }
  },
  // 通过inject 将form组件注入的实例添加进来
  inject: ['customForm'],
  computed: {
    // 通过计算组件获取组件的size, 如果当前组件传入,则使用当前组件的,否则是否form组件的
    getSize() {
      return this.size || this.customForm.size
    },
    // 组件是否禁用
    getDisabled() {
      const { disabled } = this
      if (disabled !== undefined) {
        return disabled
      }
      return this.customForm.disabled
    }
  },
  methods: {
    // 自定义v-model
    $_handleChange(e) {
      this.$emit('input', e.target.value)
    }
  }
}
</script>

существуетform, мы проходимprovideвозвращает объект, вinput, мы можем пройтиinjectПолучатьformВозвращает элементы в объекте в приведенном выше кодеinject:['customForm']показано, то вы можете пройтиthis.customFormперечислитьformСвойства и методы экземпляра

**В приведенном выше коде мы использовали пользовательскийv-model, о пользовательскихv-modelВы можете прочитать мою предыдущую статьюАбсолютно сухой материал~! Изучите эти советы Vue, вы сможете уйти с работы пораньше и встречаться с богиней **

использовать в проекте

<template>
  <custom-form size="small">
    <custom-form-item label="姓名">
      <custom-input v-model="formData.name" />
    </custom-form-item>
  </custom-form>
</template>
<script>
import CustomForm from '../components/custom-form'
import CustomFormItem from '../components/custom-form-item'
import CustomInput from '../components/custom-input'
export default {
  components: {
    CustomForm,
    CustomFormItem,
    CustomInput
  },
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}
</script>

Выполните приведенный выше код, и результат:

<form class="custom-form">
  <div class="custom-form-item">
    <label class="custom-form-item__label">姓名</label>
    <div class="custom-form-item__content">
      <!--size=small已经添加到指定的位置了-->
      <div class="custom-input custom-input--small">
        <input class="custom-input__input">
      </div>
    </div>
  </div>
</form>

Как видно из приведенного выше кода,inputКомпонент установил стиль компонента наcustom-input--smallохватывать

injectописание формата

В дополнение к тому, что используется в приведенном выше кодеinject:['customForm']Помимо письма,injectТакже может быть объектом. и может указать значения по умолчанию

Измените приведенный выше пример, еслиcustom-inputнет внешнегоcustom-form, он не будет вводитьcustomForm, в это время дляcustomFormУкажите значение по умолчанию

{
  inject: {
    customForm: {
      // 对于非原始值,和props一样,需要提供一个工厂方法
      default: () => ({
        size: 'default'
      })
    }
  }
}

если мы хотимinjectИмя входящего свойства не называетсяcustomForm, но называетсяparentForm, следующий код

inject: {
    // 注入的属性名称
    parentForm: {
      // 通过 from 指定从哪个属性注入
      from: 'customForm',
      default: () => ({
        size: 'default'
      })
    }
  },
  computed: {
    // 通过计算组件获取组件的size, 如果当前组件传入,则使用当前组件的,否则是否form组件的
    getSize() {
      return this.size || this.parentForm.size
    }
  }

ограничения на использование

  1. provideиinjectПривязки не реактивны. Однако, если вы передаете прослушиваемый объект, как показано вышеcustomForm: this, то свойства его объекта по-прежнему реагируют.

  2. VueПредложение официального сайтаprovideиinjectВ основном используется при разработке высокоуровневых библиотек плагинов/компонентов. Не рекомендуется использовать в обычном коде приложения. так какprovideиinjectВ коде не прослеживается (ctrl+f можно поискать), рекомендуется использоватьVuexзаменять. Однако это не означает, что его нельзя использовать, и иногда он дает относительно большой эффект при использовании в локальных функциях.

диспетчеризация и широковещательная передача, исторический способ передачи компонентов

$dispatchи$broadcastЭто исторический способ связи компонентов, зачем история, потому что ониVue1.0обеспечить способVue2.0Заброшенный. Но устаревшее не означает, что мы не можем реализовать его вручную, как многие библиотеки пользовательского интерфейса имеют внутренние реализации. Эта статья начинается сelement-uiРеализация основана на введении. Одновременно прочитав этот раздел, вы будете иметь хорошее представление о компонентах$parent,$children,$optionsпонимать.

Введение метода

$dispatch: $dispatchСобытие будет инициировано вверх, и в то же время будут переданы имя и параметры запускаемого компонента-предка. распространение прекратится.

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

$dispatchРеализация и применение

1. Реализация кода

/**
 * 向上传播事件
 * @param {*} eventName 事件名称
 * @param {*} componentName 接收事件的组件名称
 * @param {...any} params 传递的参数,可以有多个
 */
function dispatch(eventName, componentName, ...params) {
  // 如果没有$parent, 则取$root
  let parent = this.$parent || this.$root
  while (parent) {
    // 组件的name存储在组件的$options.componentName 上面
    const name = parent.$options.name
    // 如果接收事件的组件是当前组件
    if (name === componentName) {
      // 通过当前组件上面的$emit触发事件,同事传递事件名称与参数
      parent.$emit.apply(parent, [eventName, ...params])
      break
    } else {
      // 否则继续向上判断
      parent = parent.$parent
    }
  }
}

// 导出一个对象,然后在需要用到的地方通过混入添加
export default {
  methods: {
    $dispatch: dispatch
  }
}

2. Применение кода

передать дочерний компонент$dispatchвызвать событие вверх

import emitter from '../mixins/emitter'
export default {
  name: 'Chart',
  // 通过混入将$dispatch加入进来
  mixins: [emitter],
   mounted() {
     // 在组件渲染完之后,将组件通过$dispatch将自己注册到Board组件上
    this.$dispatch('register', 'Board', this)
  }
}

существуетBoardкомпонент через$onПрослушивание событий, которые необходимо зарегистрировать

export default {
  name: 'Board',
  created() {
    this.$on('register',(component) => {
      // 处理注册逻辑
    })
  }
}

$broadcastРеализация и применение

1. Реализация кода


/**
 * 向下传播事件
 * @param {*} eventName 事件名称
 * @param {*} componentName 要触发组件的名称
 * @param  {...any} params 传递的参数
 */
function broadcast(eventName, componentName, ...params) {
  this.$children.forEach(child => {
    const name = child.$options.name
    if (name === componentName) {
      child.$emit.apply(child, [eventName, ...params])
    } else {
      broadcast.apply(child, [eventName, componentName, ...params])
    }
  })
}

// 导出一个对象,然后在需要用到的地方通过混入添加
export default {
  methods: {
    $broadcast: broadcast
  }
}

2. Применение кода

передать родительский компонент$broadcastинициировать событие вниз

import emitter from '../mixins/emitter'
export default {
  name: 'Board',
  // 通过混入将$dispatch加入进来
  mixins: [emitter],
  methods:{
  	//在需要的时候,刷新组件
  	$_refreshChildren(params) {
  		this.$broadcast('refresh', 'Chart', params)
  	}
  }
}

передать компоненты-потомки$onПрослушивание событий обновления

export default {
  name: 'Chart',
  created() {
    this.$on('refresh',(params) => {
      // 刷新事件
    })
  }
}

Суммировать

В приведенном выше примере учащиеся должны уметь$dispatchи$broadcastпонимаю, но почемуVue2.0Отказаться от этих двух методов? Официальное объяснение: «Поскольку метод потока событий, основанный на структуре дерева компонентов, действительно сложен для понимания, и он будет становиться все более и более хрупким в процессе расширения структуры компонентов. Этот метод событий действительно не очень хорош, мы также не хочу делать разработчиков слишком болезненными в будущем.$dispatchи$broadcastЭто также не решает проблему связи между родственными компонентами. "

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

Эпилог

Не истощайте свое вдохновение и воображение, не будьте рабом своих моделей. - Винсент Ван Гог

В этой статье используетсяmdniceнабор текста