Новые функции Vue3.0 и сводка опыта использования

Vue.js
Новые функции Vue3.0 и сводка опыта использования

предисловие

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

Зачем переходить на Vue3

Оба друга, использующие Vue2.x, знакомы, все данные в Vue2.x определеныdata, метод определен вmethodsв и использоватьthisдля вызова соответствующих данных и методов. Во Vue3.x так играть нельзя.О том, как в нее играть, мы поговорим позже.Сначала поговорим о дефектах версии Vue2.x, написанной таким образом, и будут сделаны все апгрейды.

Просмотрите Vue2.x для реализации сложения и вычитания

<template>
  <div class="homePage">
    <p>count: {{ count }}</p>   
    <p>倍数: {{ multiple }}</p>        
    <div>
      <button style="margin-right: 10px" @click="increase">加1</button>
      <button @click="decrease">减一</button>    
    </div>      
  </div>
</template>
<script>
export default {
  data() {
    return { count: 0 };
  },
  computed: {
    multiple() {
      return 2 * this.count;
    },
  },
  methods: {
    increase() {
      this.count++;
    },
    decrease() {
      this.count--;
    },
  },
};
</script>

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

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

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

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

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

Тогда решение, данное версией vue2.x, — это Mixin, но использование Mixin также столкнется с раздражающими проблемами:

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

Я не буду приводить примеры вышеперечисленных часто встречающихся проблем, и знакомые, которые ими пользовались, в той или иной степени столкнутся с ними. В центре внимания статьи не Mixin, если вы действительно хотите знать, просто оставьте сообщение~

Итак, мы запустили Vue3.xComposition APIОсновная цель — решить вышеперечисленные проблемы, объединить разбросанную и распределенную логику вместе для обслуживания, а также может разбить отдельную функциональную логику на отдельные файлы. Далее мы сосредоточимся наComposition API.

Composition API

setup

setup — это новая опция в Vue3.x, которая используется в компонентахComposition APIВход.

Время выполнения установки

Я видел много статей в процессе изучения того, что установка находится вbeforeCreateа такжеcreatedМежду тем этот вывод неверен. Практика — единственный критерий проверки истины, поэтому я проверил это на себе:

export default defineComponent({
  beforeCreate() {
    console.log("----beforeCreate----");
  },
  created() {
    console.log("----created----");
  },
  setup() {
    console.log("----setup----");
  },
});

Время выполнения установки — до beforeCreate. Подробности см. в описании жизненного цикла позже.

параметр настройки

использоватьsetup, он принимает два параметра:

  1. props: свойства, переданные компонентом
  2. context

принято в настройкахpropsОн реактивный и будет обновляться вовремя, когда будут переданы новые реквизиты. Так как он отзывчивый, поэтомуНе могу использовать деструктурирование ES6, деструктуризация лишает его отзывчивости.Пример кода ошибки, этот код заставит props больше не поддерживать реактивность:

// demo.vue
export default defineComponent ({
    setup(props, context) {
        const { name } = props
        console.log(name)
    },
})

что в развитии мыЕсли вы хотите использовать деструктурирование, вы все равно можете оставитьpropsотзывчивый, есть ли способ решить это? Вы можете подумать об этом, в спинуtoRefsМесто, чтобы узнать ответы для всех. Далее поговорим оsetupПринятый второй параметрcontext, мы сказали ранееsetupНаиболее часто используемые в Vue2 недоступны вthisобъект, поэтомуcontextпредоставлено вthisТри наиболее часто используемых свойства:attrs,slotа такжеemit, соответствующий Vue2.x соответственно$attrАтрибуты,slotслот и$emitсобытие запуска. И эти свойства автоматически синхронизируются с последними значениями, поэтому мы получаем самые последние значения каждый раз, когда их используем.

реактивный, ref и toRefs

В vue2.x данные определения находятся вdata, Но его можно использовать vue3.xreactiveа такжеrefдля определения данных. Такrefа такжеreactiveВ чем разница между ними? Когда они используются? Сказав это, я должен упомянуть, что я видел много статей в Интернете, в которых говорилось, что (reactiveДвусторонняя привязка для работы с объектами,refзатем обрабатывает двустороннюю привязку базовых типов js). Я на самом деле не согласен с таким утверждением, новичкам легко подумать, чтоrefможет обрабатывать основные типы js, такие какrefТакже возможно определить двустороннюю привязку объектов, приведенный выше код:

 setup() {
    const obj = ref({count:1, name:"张三"})
    setTimeout(() =>{
        obj.value.count = obj.value.count + 1
        obj.value.name = "李四"
    }, 1000)
    return{
        obj
    }
  }

мы будемobj.countа такжеobj.nameПривязка к странице тоже возможна, однакоreactiveФункции действительно могут проксировать объект, но не примитивные типы, такие как строки, числа, логические значения и т. д. Затем используйте код, чтобы показатьref,reactiveиспользование:текущий результат:В приведенном выше коде мы привязываемся к странице черезuser.name,user.age; Кажется, очень громоздко писать так, можем ли мы напрямуюuserКак насчет деконструкции свойств вuserСтруктурируйте его так, чтобы он был отзывчивым, здесь и выше мы сказалиpropsВы не можете использовать ES6 для прямой деконструкции. Тогда что, если мы хотим использовать деструктурированные данные, решение таково:использоватьtoRefs. toRefs используется для преобразования реактивного объекта в обычный объект, все свойства которого являются объектами ref. Конкретное использование заключается в следующем:

<template>
  <div class="homePage">
    <p>第 {{ year }} 年</p>
    <p>姓名: {{ nickname }}</p>
    <p>年龄: {{ age }}</p>
  </div>
</template>

<script>
import { defineComponent, reactive, ref, toRefs } from "vue";
export default defineComponent({
  setup() {
    const year = ref(0);
    const user = reactive({ nickname: "xiaofan", age: 26, gender: "女" });
    setInterval(() => {
      year.value++;
      user.age++;
    }, 1000);
    return {
      year,
      // 使用reRefs
      ...toRefs(user),
    };
  },
});
</script>

крючки жизненного цикла

Мы можем прямо посмотреть на диаграмму жизненного цикла, чтобы узнать, какие есть крючки жизненного цикла (картинка нарисована согласно переводу официального сайта):Из рисунка видно, что Vue3.0 добавилsetup, мы также подробно описали это ранее, а затем Vue2.xbeforeDestroyимя изменено наbeforeUnmount; destroyedстол большеunmounted, автор говорит, что это изменение чисто для большей семантики, потому что компонент — этоmountа такжеunmountпроцесс. Другие жизненные циклы в Vue2 все еще сохраняются. верх生命周期图Он не содержит всех хуков жизненного цикла, есть несколько других, все хуки жизненного цикла показаны на рисунке:Мы видим, чтоbeforeCreateа такжеcreatedодеялоsetupЗаменено (но вы все еще можете использовать его в Vue3, потому что Vue3 обратно совместим, то есть вы фактически используете vue2). Во-вторых, добавлено имя хука.on; Vue3.x также добавляет хуки для отладкиonRenderTriggeredа такжеonRenderTrickedНиже мы просто используем несколько хуков, чтобы вы могли научиться их использовать.Хук в Vue3.x необходимо импортировать из vue:

import { defineComponent, onBeforeMount, onMounted, onBeforeUpdate,onUpdated,
onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked,
onRenderTriggered } from "vue"; export default defineComponent({ //
beforeCreate和created是vue2的 beforeCreate() {
console.log("------beforeCreate-----"); }, created() {
console.log("------created-----"); }, setup() { console.log("------setup-----");
// vue3.x生命周期写在setup中 onBeforeMount(() => {
console.log("------onBeforeMount-----"); }); onMounted(() => {
console.log("------onMounted-----"); }); // 调试哪些数据发生了变化
onRenderTriggered((event) =>{ console.log("------onRenderTriggered-----",event);
}) }, });

Здесь представлен контент, связанный с жизненным циклом, давайте представим Vue3.x.watchв чем разница.

Использование часов и часового эффекта

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

watch(source, callback, [options])

Описание параметра:

  • источник: может поддерживать строку, объект, функцию, массив; используется для указания адаптивной переменной для прослушивания
  • callback: функция обратного вызова для выполнения
  • варианты: поддерживает глубокие, немедленные и флеш-опции.

Далее я расскажу, как используются эти три параметра.Если вы не понимаете, как использовать часы, прочитайте ниже:

слушать реактивные определенные данные

import { defineComponent, ref, reactive, toRefs, watch } from "vue";
export default defineComponent({
  setup() {
    const state = reactive({ nickname: "xiaofan", age: 20 });

    setTimeout(() => {
      state.age++;
    }, 1000);

    // 修改age值时会触发 watch的回调
    watch(
      () => state.age,
      (curAge, preAge) => {
        console.log("新值:", curAge, "老值:", preAge);
      }
    );

    return {
      ...toRefs(state),
    };
  },
});

слушать данные, определенные ссылкой

const year = ref(0);

setTimeout(() => {
  year.value++;
}, 1000);

watch(year, (newVal, oldVal) => {
  console.log("新值:", newVal, "老值:", oldVal);
});

слушать несколько данных

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

watch([() => state.age, year], ([curAge, newVal], [preAge, oldVal]) => {
console.log("新值:", curAge, "老值:", preAge); console.log("新值:", newVal,
"老值:", oldVal); });

Слушайте сложные вложенные объекты

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

const state = reactive({
  room: {
    id: 100,
    attrs: {
      size: "140平方米",
      type: "三室两厅",
    },
  },
});
watch(
  () => state.room,
  (newType, oldType) => {
    console.log("新值:", newType, "老值:", oldType);
  },
  { deep: true }
);

Если третий параметр не используетсяdeep:true, не может отслеживать изменения данных. Ранее мы упоминали,часы ленивы по умолчанию, тогда при каких обстоятельствах не лениво и callback-функцию можно выполнить сразу? На самом деле использование тоже очень простое, задается в третьем параметреimmediate: trueВот и все. оflushКонфигурация еще учится, будет добавлена ​​позже

перестань слушать

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

const stopWatchRoom = watch(() => state.room, (newType, oldType) => {
    console.log("新值:", newType, "老值:", oldType);
}, {deep:true});

setTimeout(()=>{
    // 停止监听
    stopWatchRoom()
}, 3000)

Также есть функция прослушиванияwatchEffect, я считаюwatchОн уже может удовлетворить потребности мониторинга, зачемwatchEffectШерстяная ткань? Хотя у меня нет необходимости его получать, я все же хочу представить егоwatchEffect, сначала посмотрите на его использование иwatchВ чем разница.

import { defineComponent, ref, reactive, toRefs, watchEffect } from "vue";
export default defineComponent({
  setup() {
    const state = reactive({ nickname: "xiaofan", age: 20 });
    let year = ref(0)

    setInterval(() =>{
        state.age++
        year.value++
    },1000)

    watchEffect(() => {
        console.log(state);
        console.log(year);
      }
    );

    return {
        ...toRefs(state)
    }
  },
});

Результат выполнения сначала печатается один разstateа такжеyearзначение; затем каждую секунду печататьstateа такжеyearстоимость. Как видно из приведенного выше кода, нетwatchТакже необходимо сначала передать зависимости,watchEffectЗависимости собираются автоматически, достаточно указать функцию обратного вызова. Когда компонент будет инициализирован, он будет выполнен один раз для сбора зависимостей, а затем, когда данные в собранных зависимостях изменятся, функция обратного вызова будет выполнена снова. Таким образом, общее сравнение выглядит следующим образом:

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

Vue3 был представлен вышеComposition APIЧасть контента, есть много очень полезных API, рекомендуется напрямую проверить состав API официального сайта. На самом деле, мы также можем сделать индивидуальную упаковку.

Пользовательские крючки

Вначале мы использовали Vue2.x, чтобы написать пример сложения и вычитания, который можно инкапсулировать здесь как хук Мы договорились, что эти «пользовательские хуки» имеют префикс использования, чтобы отличить их от обычных функций.useCount.tsвыполнить:

import { ref, Ref, computed } from "vue";

type CountResultProps = {
  count: Ref<number>;
  multiple: Ref<number>;
  increase: (delta?: number) => void;
  decrease: (delta?: number) => void;
};

export default function useCount(initValue = 1): CountResultProps {
  const count = ref(initValue);

  const increase = (delta?: number): void => {
    if (typeof delta !== "undefined") {
      count.value += delta;
    } else {
      count.value += 1;
    }
  };
  const multiple = computed(() => count.value * 2);

  const decrease = (delta?: number): void => {
    if (typeof delta !== "undefined") {
      count.value -= delta;
    } else {
      count.value -= 1;
    }
  };

  return {
    count,
    multiple,
    increase,
    decrease,
  };
}

Давайте посмотрим на использование компонентовuseCountэтоhook:

<template>
  <p>count: {{ count }}</p>
  <p>倍数: {{ multiple }}</p>
  <div>
    <button @click="increase()">加1</button>
    <button @click="decrease()">减一</button>
  </div>
</template>

<script lang="ts">
import useCount from "../hooks/useCount";
 setup() {
    const { count, multiple, increase, decrease } = useCount(10);
        return {
            count,
            multiple,
            increase,
            decrease,
        };
    },
</script>

Открытая реализация Vue2.x, дисперсияdata,method,computedПодождите, если вы только что взялись за проект, вы действительно не можете быстроdataполя иmethodНа пути Vue3 ясно видно, что гораздо удобнее агрегировать логику, связанную с подсчетом, иuseCountДополнительные функции также могут быть расширены. После того, как проект будет разработан, я напишу статью с кратким изложением «пользовательских хуков», используемых в проекте, чтобы помочь вам в разработке более эффективно.Composition APIЗдесь представлены пользовательские хуки, а затем кратко представлено сравнение отзывчивости между vue2.x и vue3.

Простое сравнение отзывчивости vue2.x и vue3.x

На самом деле, когда тема Vue3.x не выпущена, это огонь.Vue3.x 将使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty. Нет любви без причины, и нет ненависти без причины. Почему долженObject.definePropertyЕсли вы измените его, мы можем кратко рассказать об этом. При первом запуске Vue2.x часто сталкивался с проблемой, обновлялись данные, почему страница не обновляется? когда использовать$setобновить, когда$forceUpdateВынужден обновить, вы когда-нибудь были в беде. Позже в процессе обучения я начал связываться с исходным кодом, и тогда я понял, что корень всегоObject.defineProperty. Для тех, кто хочет узнать больше об этой части, вы можете прочитать эту статью Почему Vue3.0 больше не использует defineProperty для реализации мониторинга данных? Подробно объяснить можно в другой статье, вот простое сравнениеObject.definePropertyс прокси

  1. Object.definePropertyВы можете угнать только свойства объекта, а прокси - прямой прокси-объект

из-заObject.definePropertyТолько свойства объекта могут быть захвачены, и каждое свойство объекта необходимо пройти.Если значение свойства также является объектом, требуется рекурсивный глубокий обход. Но прокси напрямую прокси-объект, нет необходимости проходить операцию

  1. Object.definePropertyДобавление свойств необходимо выполнять вручнуюObserve

потому чтоObject.definePropertyПерехват — это атрибут объекта, поэтому при добавлении нового атрибута вам нужно снова пройтись по объекту и снова использовать новый атрибут.Object.definePropertyугон. То есть при добавлении свойств к массивам и объектам в Vue2.x нужно использовать$setЧтобы новые свойства также реагировали,$setВнутренне также по телефонуObject.definePropertyиметь дело с.

Teleport

Телепорт — это новая функция Vue3.x, и те, кто не слышал этого слова, могут почувствовать себя незнакомыми;传送Я все еще могу чувствовать, что не знаю, что это значит, поэтому я дам вам описание изображения ниже.

Что такое Телепорт?

Телепорт похож на «любую дверь» в Дораэмоне, функция любой двери — мгновенно телепортировать людей в другое место. С этим пониманием давайте посмотрим, почему нам нужно использовать возможности Teleport.Давайте рассмотрим небольшой пример: в подкомпонентеHeaderиспользуется вDialogкомпонент, мы часто используем его в подобных ситуациях в реальной разработкеDialog,В настоящее времяDialogОн визуализируется в виде слоя подкомпонентов для управления позиционированием вложенных компонентов.z-indexи стили стали трудными.DialogС точки зрения восприятия пользователем, это должен быть самостоятельный компонент, а DOM, смонтированный компонентом верхнего уровня Vue, должен быть полностью отделен от структуры dom, при этом также может использоваться состояние в компоненте Vue (dataилиprops) стоимость. Проще говоря,то есть хотите продолжать использовать внутри компонентаDialog, и надеемся, что визуализированная структура DOM не вложена в DOM компонента.. На данный момент нам нужен Телепорт для игры, мы можем использовать<Teleport>пакетDialog, в этот момент устанавливается портал, который можетDialogВизуализированный контент доставляется в любое указанное место. Далее, давайте возьмем небольшой пример, чтобы увидеть, как используется Teleport.

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

Мы надеемся, что Dialog rendering dom и компоненты верхнего уровня являются родственными отношениями, вindex.htmlФайл определяет элемент для монтажа:

<body>
  <div id="app"></div>
  <div id="dialog"></div>
</body>

определитьDialogкомпонентыDialog.vue, обрати внимание наtoсвойства такие же, как и вышеidСелекторы те же:

<template>
  <teleport to="#dialog">
    <div class="dialog">
      <div class="dialog_wrapper">
        <div class="dialog_header" v-if="title">
          <slot name="header">
            <span>{{ title }}</span>
          </slot>
        </div>
      </div>
      <div class="dialog_content">
        <slot></slot>
      </div>
      <div class="dialog_footer">
        <slot name="footer"></slot>
      </div>
    </div>
  </teleport>
</template>

Наконец в дочернем компонентеHeader.vueиспользуется вDialogКомпонент здесь в основном демонстрирует использование Телепорта, а не относящийся к делу код опущен.headerкомпоненты

<div class="header">
    ...
    <navbar />
    <Dialog v-if="dialogVisible"></Dialog>
</div>
...

Эффект рендеринга Dom следующий:изображение.png Как видите, мы используемteleportкомпоненты, черезtoсвойство, указывающее, где компонент визуализируется с помощью<div id="app"></div>На том же уровне, т.bodyвниз, ноDialogположение делdialogVisibleОпять же, он полностью контролируется внутренними компонентами Vue.

Suspense

SuspenseЭто новая функция в Vue3.x, так для чего она нужна? Не волнуйтесь, давайте разберемся с его ролью в некоторых сценариях в Vue2.x. Во Vue2.x часто должен встречаться такой сценарий:

<template>
<div>
    <div v-if="!loading">
        ...
    </div>
    <div v-if="loading">
        加载中...
    </div>
</div>
</template>

Когда интерфейс и сервер получают данные в интерактивном режиме, это асинхронный процесс.Как правило, мы предоставляем анимацию загрузки для совместной работы при возврате данных.v-ifдля управления отображением данных. если вы использовалиvue-async-managerЭтот плагин для выполнения вышеуказанных требований, выSuspenseЭто не может быть незнакомым, Vue3.x выглядит как ссылкаvue-async-manager. Новые встроенные компоненты Vue3.xSuspense, он обеспечивает дваtemplateслот, содержимое в резервном состоянии будет отображаться в начале, а официальное содержимое в состоянии по умолчанию не будет отображаться до тех пор, пока не будет достигнуто определенное условие.SuspenseАсинхронный рендеринг компонентов для презентации намного проще. ::: предупреждение при использованииSuspense, чтобы вернуть обещание :::SuspenseИспользование компонентов:

  <Suspense>
        <template #default>
            <async-component></async-component>
        </template>
        <template #fallback>
            <div>
                Loading...
            </div>
        </template>
  </Suspense>

asyncComponent.vue:

<<template>
<div>
    <h4>这个是一个异步加载数据</h4>
    <p>用户名:{{user.nickname}}</p>
    <p>年龄:{{user.age}}</p>
</div>
</template>

<script>
import { defineComponent } from "vue"
import axios from "axios"
export default defineComponent({
    setup(){
        const rawData = await axios.get("http://xxx.xinp.cn/user")
        return {
            user: rawData.data
        }
    }
})
</script>

Из приведенного выше кодаSuspenseПросто компонент со слотом, указан только его слотdefaultа такжеfallbackдва состояния.

Фрагмент

В Vue2.x,templateДопускается только один корневой узел:

<template>
    <div>
        <span></span>
        <span></span>
    </div>
</template>

Но в Vue3.x вы можете напрямую написать несколько корневых узлов, разве это не круто:

<template>
    <span></span>
    <span></span>
</template>

Лучшее встряхивание деревьев

Vue3.x учитываетtree-shakingГлобальный и внутренний API реконструируются на основе , и в результате текущий глобальный API должен пройтиES Moduleименованная ссылка, например, в Vue2.x нам нужно использоватьnextTick:

// vue2.x
import Vue from "vue"

Vue.nextTick(()=>{
    ...
})

Vue.nextTick()представляет собой глобальный API, доступный непосредственно из объекта Vue, на самом деле$nextTick()ТолькоVue.nextTick()Простая оболочка для функции обратного вызова последней только для удобства.thisпривязан к текущему экземпляру. Хотя мы используемwebpackизtree-shaking, но независимо от того, используем ли мы на самом делеVue.nextTick(), все они попадают в наш производственный код, а поскольку экземпляр Vue экспортируется как единый объект, упаковщик не может настаивать на том, какие свойства объекта всегда используются кодом. Переписано на Vue3.x так:

import { nextTick } from "vue"

nextTick(() =>{
    ...
})

Затронутый API

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

  • Vue.nextTick
  • Vue.observable(использоватьVue.reactiveзаменять)
  • Vue.version
  • Vue.compile(доступно только в полной версии)
  • Vue.set(Доступно только в версиях, совместимых с 2.x)
  • Vue.delete(то же, что и выше)

Встроенные инструменты

В дополнение к вышеперечисленному API существует множество встроенных компонентов. Вышеизложенное относится только кES Modulesсборок, связующие для поддержки древовидной структуры — сборки UMD по-прежнему включают в себя все функции и предоставляют все в глобальных переменных Vue (компилятор будет генерировать соответствующий вывод для использования внешних API вместо импорта). ::: Впереди некоторые новые функции Vue3.0, а затем я сосредоточусь на изменениях по сравнению с Vue2.x?

изменять

синтаксис именованного слота

В Vue2.x способ написания именованного слота:

<!--  子组件中:-->
<slot name="title"></slot>

В родительском компоненте используйте:

<template slot="title">
    <h1>歌曲:成都</h1>
<template>

если мы хотимЧтобы привязать данные к слоту, вы можете использовать слоты с областью видимости., реализуется следующим образом:

// 子组件
<slot name="content" :data="data"></slot>
export default {
    data(){
        return{
            data:["走过来人来人往","不喜欢也得欣赏","陪伴是最长情的告白"]
        }
    }
}
<!-- 父组件中使用 -->
<template slot="content" slot-scope="scoped">
    <div v-for="item in scoped.data">{{item}}</div>
<template>

Именованные слоты и слоты с заданной областью используются отдельно в Vue2.x.slotа такжеslot-scopeДля достижения в Vue3.0 будетslotа такжеslot-scopeСогласие на использование суммируется. В Vue3.0v-slot:

<!-- 父组件中使用 -->
 <template v-slot:content="scoped">
   <div v-for="item in scoped.data">{{item}}</div>
</template>

<!-- 也可以简写成: -->
<template #content="{data}">
    <div v-for="item in data">{{item}}</div>
</template>

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

Давайте сначала рассмотрим реализацию пользовательской директивы в Vue 2:

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

В Vue 2 пользовательские директивы создаются с помощью следующих необязательных хуков:

  • bind: вызывается только один раз, когда директива впервые привязывается к элементу. Здесь можно выполнить одноразовые настройки инициализации.
  • вставленный: вызывается, когда связанный элемент вставляется в родительский узел (гарантируется существование только родительского узла, но не обязательно вставленного в документ).
  • update: вызывается при обновлении VNode компонента, но может произойти до обновления его дочерних VNode. Значение инструкции может измениться, а может и не измениться. Но вы можете игнорировать ненужные обновления шаблона, сравнив значения до и после обновления (подробнее о параметрах функции хука см. ниже).
  • componentUpdated: вызывается после VNode компонента, в котором обновляются инструкция и ее дочерние VNode.
  • Развинтируйте: вызывают только один раз, когда инструкция - это уничтожение из элемента.

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

const { createApp } from "vue"

const app = createApp({})
app.directive('focus', {
    mounted(el) {
        el.focus()
    }
})

Затем новый можно использовать для любого элемента в шаблоне.v-focusинструкции следующим образом:

<input v-focus />

обновление v-модели

Узнал перед использованием Vue 3v-modelПроизошло очень много изменений.После его использования мы действительно можем получить эти изменения.Давайте посмотрим,какие изменения произошли,а потом поговорим о том,как их использовать:

  • Изменено: использование на пользовательских компонентахv-model, имена свойств и событий по умолчанию изменены
  • изменять:v-bindиз.syncМодификаторы снова были удалены в Vue 3, объединены вv-modelвнутри
  • Новое: один и тот же компонент можно установить несколько одновременно.v-model
  • Новое: разработчики могут настраиватьv-modelмодификатор

Смущенный? Не волнуйтесь, см. ниже В Vue2 используйте на компонентахv-modelПо сути, это эквивалентно прохождениюvalueсвойства и триггерыinputмероприятие:

<!-- Vue 2 -->
<search-input v-model="searchValue"><search-input>

<!-- 相当于 -->
<search-input :value="searchValue" @input="searchValue=$event"><search-input>

В настоящее времяv-modelможно связать только для компонентовvalueсвойства, то мы не довольны, мы как бы используем другое свойство для наших собственных компонентов, и мы не хотим запускатьinputчтобы обновить значение, в.syncДо того, как он вышел, он был реализован в Vue 2 следующим образом:

// 子组件:searchInput.vue
export default {
    model:{
        prop: 'search',
        event:'change'
    }
}

После модификации компонент searchInput используетv-modelэквивалентно этому:

<search-input v-model="searchValue"><search-input>
<!-- 相当于 -->
<search-input :search="searchValue" @change="searchValue=$event"><search-input>

Однако в реальной разработке в некоторых сценариях нам может понадобиться "двухсторонняя привязка" реквизита.В качестве примера приведу самый распространенный модал: модальный вполне подходит для двустороннего связывания свойств, а внешний может управлять компонентаvisibleПоказать или скрыть, внутреннее закрытие компонента можно контролироватьvisibleСвойство скрыто, а видимое свойство синхронно переносится наружу. внутри компонента, когда мы закрываемmodal, запустить событие в дочернем компоненте в шаблоне update:PropName:

this.$emit('update:visible', false)

Затем в родительском компоненте вы можете прослушать это событие, чтобы обновить данные:

<modal :visible="isVisible" @update:visible="isVisible = $event"></modal>

На этом этапе мы также можем использоватьv-bind.syncдля упрощения реализации:

<modal :visible.sync="isVisible"></modal>

Приведенный выше обзор Vue2v-modelреализация и двусторонняя привязка свойств компонента, тоКак это должно быть реализовано в Vue 3?В Vue3 используйте пользовательский компонентv-model, что эквивалентно передачеmodelValueсвойство, вызываяupdate:modelValueмероприятие:

<modal v-model="isVisible"></modal>
<!-- 相当于 -->
<modal :modelValue="isVisible" @update:modelValue="isVisible = $event"></modal>

Если вы хотите связать имя свойства, просто дайтеv-modelПросто передайте один параметр, и вы можете привязать несколько одновременноv-model:

<modal v-model:visible="isVisible" v-model:content="content"></modal>

<!-- 相当于 -->
<modal
    :visible="isVisible"
    :content="content"
    @update:visible="isVisible"
    @update:content="content"
/>

Я не знаю, заметили ли вы, это написание полностью отсутствует.syncЧто случилось, так что снова упал в Vue 3.syncорфография, универсальное использованиеv-model

Асинхронные компоненты

Используется в Vue3defineAsyncComponentОпределение асинхронных компонентов, настройка параметровcomponentзаменитьloader, Сама функция загрузчика больше не принимает параметры разрешения и отклонения и должна возвращать обещание, которое используется следующим образом:

<template>
  <!-- 异步组件的使用 -->
  <AsyncPage />
</tempate>

<script>
import { defineAsyncComponent } from "vue";

export default {
  components: {
    // 无配置项异步组件
    AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")),

    // 有配置项异步组件
    AsyncPageWithOptions: defineAsyncComponent({
   loader: () => import(".NextPage.vue"),
   delay: 200,
   timeout: 3000,
   errorComponent: () => import("./ErrorComponent.vue"),
   loadingComponent: () => import("./LoadingComponent.vue"),
 })
  },
}
</script>

Справочная статья:

  • Руководство по началу работы с Vue3 Family Bucket
  • Изучите волну новых функций Vue3
  • Новые функции Vue3.0 и сводка изменений в использовании (используется в реальной работе)
  • Потрясающий Vue3

Идея ума


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

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

Если в тексте есть какие-либо ошибки, вы можете исправить их в области комментариев, если они вам полезны, ставьте лайк и подписывайтесь~~~