Подробный обзор новых функций Vue3.0

Vue.js
Подробный обзор новых функций Vue3.0

Vue3.0 был обновлен и оптимизирован с момента выпуска первой версии One Piece в сентябре 2020 года; также была выпущена официальная документация китайской версии; тогда, как конечные пользователи, давайте посмотрим, какие функции и возможности были добавлены к Vue3.

Эта статья была впервые опубликована в публичном аккаунте【前端壹读】, для более интересного контента, пожалуйста, обратите внимание на последние новости официального аккаунта.

Ю Да поделился несколькими яркими моментами Vue3.0 во время прямой трансляции на станции B:

  • Производительность: оптимизация производительности
  • Поддержка встряхивания дерева: поддержка оптимизации встряхивания дерева
  • API композиции: API композиции
  • Фрагмент, телепорт, саспенс: добавлены компоненты
  • Улучшенная поддержка TypeScript: Улучшенная поддержка TypeScript
  • API пользовательского рендерера: Пользовательский рендерер

С точки зрения производительности, по сравнению с Vue2.x, производительность улучшена примерно в 1,3~2 раза, упакованный объем также меньше, если вы пишете HelloWorld для упаковки, это всего 13,5 КБ, плюс все функции времени выполнения, это всего 22,5кб.

Итак, как конечные пользователи, в чем разница между нами и Vue2.x при разработке?Talk is cheap, давайте снова посмотрим на код.

Tree-shaking

Одним из наиболее важных изменений в Vue3 является введение Tree-Shaking, Меньший размер пакета, обеспечиваемый Tree-Shaking, очевиден. В версии 2.x многие функции монтируются в глобальный объект Vue, напримерnextTick,следующийTick,Set и другие функции, поэтому, хотя мы можем их не использовать, пока vue вводится во время упаковки, эти глобальные функции все равно будут упакованы в бандл.

В Vue3 все API вводятся через модульность ES6, так что инструменты упаковки, такие как webpack или rollup, могут исключить неиспользуемые API при упаковке и минимизировать размер пакета; мы используем его только в main.js. Такие изменения можно найти:

//src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

const app = createApp(App);
app.use(router).mount("#app");

Создайте экземпляр приложения из оригиналаnew Vue()Он создается с помощью функции createApp, однако некоторые основные функции, такие как алгоритм обновления virtualDOM и отзывчивая система, будут упакованы в любом случае; изменения, вызванные этим, — это компоненты (Vue. Vue.directive), миксин (Vue.mixin ), а плагины (Vue.use) стали методами, которые напрямую монтируются на инстансе, мы вызываем его через созданный инстанс, и преимущество в том, что приложение может иметь несколько инстансов Vue, конфигурация между разными инстансами не повлияет на каждый разное:

const app = createApp(App)
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

Таким образом, Vue2.x также необходимо изменить следующий глобальный API. Введен модуль ES6:

  • Vue.nextTick
  • Вместо этого Vue.observable больше не поддерживаетreactive
  • Vue.version
  • Vue.compile (только полная сборка)
  • Vue.set (только совместимые сборки)
  • Vue.delete (только совместимые сборки)

Кроме того, vuex и vue-router также использовали Tree-Shaking для улучшения, но синтаксис API не сильно изменился:

//src/store/index.js
import { createStore } from "vuex";

export default createStore({
  state: {},
  mutations: {},
  actions: {},
  modules: {},
});
//src/router/index.js
import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

Подробнее об использовании Tree-Shaking можно узнать вПолный анализ конфигурации WebpackПосмотреть в.

функция жизненного цикла

Мы все знаем, что в Vue2.x есть 8 функций жизненного цикла:

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroyed

В vue3 появился новыйsetupФункция жизненного цикла, время выполнения настройки находится вbeforeCreateВыполняется перед функцией жизни, поэтому его нельзя передать в эту функциюthisдля получения экземпляра, в то же время для унификации именованияbeforeDestroyпереименовать вbeforeUnmount,destroyedпереименовать вunmounted, поэтому vue3 имеет следующие функции жизненного цикла:

  • beforeCreate (вместо этого рекомендуется использовать настройку)
  • создано (вместо этого рекомендуется использовать настройку)
  • setup
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeUnmount
  • unmounted

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

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted
  • onErrorCaptured
  • onRenderTracked
  • onRenderTriggered

Так как же вызывать эти функции ловушек? Мы монтируем хук жизненного цикла в настройке, и когда соответствующий жизненный цикл выполняется, вызывается соответствующая функция хука:

import { onBeforeMount, onMounted } from "vue";
export default {
  setup() {
    console.log("----setup----");
    onBeforeMount(() => {
      // beforeMount代码执行
    });
    onMounted(() => {
      // mounted代码执行
    });
  },
}

Добавлен функционал

После разговора о жизненном цикле, вот новые функции, которые мы с нетерпением ждем в Vue3.

Реактивный API

мы вУглубленное изучение Object.defineProperty и ProxyЯ объяснил преимущества прокси и почему Vue3 использует прокси для реализации отзывчивости. В то же время Vue3 также тезисывает некоторые адаптивные API для лучшего повторного использования кода.

мы можем использоватьreactiveЧтобы создать реактивное состояние для объектов JS:

import { reactive, toRefs } from "vue";
const user = reactive({
  name: 'Vue2',
  age: 18,
});
user.name = 'Vue3'

Реактивный эквивалентен Vue2.xVue.observable.

Реактивная функция принимает только сложные типы данных, такие как объект и массив.

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


import { ref } from "vue";
const num = ref(0);
const str = ref("");
const male = ref(true);

num.value++;
console.log(num.value);

str.value = "new val";
console.log(str.value);

male.value = false;
console.log(male.value);

Отзывчивый объект, возвращаемый ref, представляет собой объект RefImpl, который содержит только параметр с именем value.Он получен и изменен в js через его атрибут value.Однако при отображении в шаблоне внутреннее значение автоматически расширяется, поэтому оно не нужно добавлять в шаблон.value.

<template>
  <div>
    <span>{{ count }}</span>
    <button @click="count ++">Increment count</button>
  </div>
</template>

<script>
  import { ref } from 'vue'
  export default {
    setup() {
      const count = ref(0)
      return {
        count
      }
    }
  }
</script>

Reactive в основном отвечает за сложные структуры данных, тогда как ref в основном имеет дело с базовыми структурами данных; но многие детские ботиночки неправильно поймут, что ref может обрабатывать только базовые данные, а сам ref также может обрабатывать объекты и массивы:

import { ref } from "vue";

const obj = ref({
  name: "qwe",
  age: 1,
});
setTimeout(() => {
  obj.value.name = "asd";
}, 1000);

const list = ref([1, 2, 3, 4, 6]);
setTimeout(() => {
  list.value.push(7);
}, 2000);

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

let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})
let {
  name,
} = book

name = 'new Learn'
// Learn Vue
console.log(book.name);

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

let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})
let {
  name,
} = toRefs(book)

// 注意这里解构出来的name是ref对象
// 需要通过value来取值赋值
name.value = 'new Learn'
// new Learn
console.log(book.name);

Для некоторых данных только для чтения мы хотим предотвратить любые изменения в них, что можно сделать с помощьюreadonlyПриходите создать объект только для чтения:

import { reactive, readonly } from "vue";
let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})

const copy = readonly(book);
//Set operation on key "name" failed: target is readonly.
copy.name = "new copy";

Иногда нужное нам значение зависит от состояния других значений, в vue2.x мы используемcomputed函数Для вычисления свойств вычисляемая функция извлекается в vue 3. Она принимает функцию-получатель и создает получатель для значения, возвращаемого получателем.неизменныйОтзывчивый объект ref:

const num = ref(0);
const double = computed(() => num.value * 2);
num.value++;
// 2
console.log(double.value);
// Warning: computed value is readonly
double.value = 4

Или мы можем использовать функции get и set для создания объекта ref для чтения и записи:

const num = ref(0);
const double = computed({
  get: () => num.value * 2,
  set: (val) => (num.value = val / 2),
});

num.value++;
// 2
console.log(double.value);

double.value = 8
// 4
console.log(num.value);

реактивное слушание

Вычисляемому соответствует наблюдение, вычисленное — отношение «многие к одному», а наблюдение — отношение «один ко многим»; vue3 также предоставляет две функции для прослушивания изменений в источниках данных: наблюдение и наблюдение за эффектом.

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

import { reactive, ref, watch } from "vue";

const state = reactive({
  count: 0,
});

//侦听时返回值得getter函数
watch(
  () => state.count,
  (count, prevCount) => {
    // 1 0
    console.log(count, prevCount);
  }
);
state.count++;

const count = ref(0);
//直接侦听ref
watch(count, (count, prevCount) => {
  // 2 0
  console.log(count, prevCount, "watch");
});
count.value = 2;

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

const state = reactive({
  count: 1,
});
const count = ref(2);
watch([() => state.count, count], (newVal, oldVal) => {
  //[3, 2]  [1, 2]
  //[3, 4]  [3, 2]
  console.log(newVal, oldVal);
});
state.count = 3;

count.value = 4;

Если мы хотим прослушивать изменения свойств глубоко вложенного объекта, нам нужно установитьdeep:true:

const deepObj = reactive({
  a: {
    b: {
      c: "hello",
    },
  },
});

watch(
  () => deepObj,
  (val, old) => {
    // new hello new hello
    console.log(val.a.b.c, old.a.b.c);
  },
  { deep: true }
);

deepObj.a.b.c = "new hello";

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

import _ from "lodash";
const deepObj = reactive({
  a: {
    b: {
      c: "hello",
    },
  },
});

watch(
  () => _.cloneDeep(deepObj),
  (val, old) => {
    // new hello hello
    console.log(val.a.b.c, old.a.b.c);
  },
  { deep: true }
);

deepObj.a.b.c = "new hello";

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

const count = ref(0);

const stop = watch(count, (count, prevCount) => {
  // 不执行
  console.log(count, prevCount);
});

setTimeout(()=>{
  count.value = 2;
}, 1000);
// 停止watch
stop();

Так же есть функция watchEffect которую тоже можно использовать для прослушивания, но там уже часы Чем отличается этот watchEffect от часов? Основные отличия в их использовании заключаются в следующем:

  1. watchEffect не нужно полагаться на ручной ввод
  2. Watcheffect будет выполнять функцию обратного вызова при инициализации каждой инициализации.
  3. watchEffect не может получить исходное значение, только измененное значение
import { reactive, ref, watch, watchEffect } from "vue";

const count = ref(0);
const state = reactive({
  year: 2021,
});

watchEffect(() => {
  console.log(count.value);
  console.log(state.year);
});
setInterval(() => {
  count.value++;
  state.year++;
}, 1000);

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

Объединение API

API композиции (composition API) также является самой важной функцией в Vue 3. Предыдущая версия 2.x использовалаOptions API(вариант API), то есть официальное определение метода написания: данные, вычисляемые, методы, где нужно писать, где нужно писать, проблема, которую это приносит, заключается в том, что с увеличением функций код становится более и более сложные, мы видим, что код нужно повторять вверх и вниз. Горизонтальный прыжок:

Composition API对比

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

Давайте сначала посмотрим на предыдущую запись API опций:

export default {
  components: {},
  data() {},
  computed: {},
  watch: {},
  mounted() {},
}

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

а такжеComposition APIЧто нужно сделать, так это собрать код одной и той же функции вместе, чтобы нам нужно было поддерживать функциональную точку, не заботясь о другой логике, просто обращая внимание на текущую функцию;Composition APIпройти черезsetupВарианты организации кода:

export default {
  setup(props, context) {}
};

Здесь мы видим, что он получает два параметра: props и context, props — это некоторые данные, передаваемые родительским компонентом, а context — это объект контекста, который представляет собой некоторые свойства, представленные в версии 2.x:

  • attrs
  • slots
  • emit

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

Давайте посмотрим на конкретное использование настройки с помощью кнопки Button:

举个栗子

<template>
  <div>{{ state.count }} * 2 = {{ double }}</div>
  <div>{{ num }}</div>
  <div @click="add">Add</div>
</template>
<script>
import { reactive, computed, ref } from "vue";
export default {
  name: "Button",
  setup() {
    const state = reactive({
      count: 1,
    });
    const num = ref(2);
    function add() {
      state.count++;
      num.value += 10;
    }
    const double = computed(() => state.count * 2);
    return {
      state,
      double,
      num,
      add,
    };
  },
};
</script>

У многих детской обуви могут возникнуть сомнения.Разве это ничем не отличается от того, что я написал в данных и методах?Разве это не просто сведение их воедино? мы можем поставитьsetupФункции извлекаются и делятся на независимые функции, и каждая функция также может быть логически повторно использована в разных компонентах:

export default {
  setup() {
    const { networkState } = useNetworkState();
    const { user } = userDeatil();
    const { list } = tableData();
    return {
      networkState,
      user,
      list,
    };
  },
};
function useNetworkState() {}
function userDeatil() {}
function tableData() {}

Fragment

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

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

Или также может быть представлен в Vue2.xvue-fragmentsбиблиотека, которая заменяет div фиктивным фрагментом; в React обходным путем является передачаReact.FragmentТег создает фиктивный элемент, в Vue3 нам может просто не понадобиться корневой узел:

<template>
    <span>hello</span>
    <span>world</span>
</template>

Это устраняет множество бессмысленных элементов div.

Teleport

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

传送门游戏

В React вы можете сделать это черезcreatePortalфункция для создания узла, который должен быть отправлен;Portal, но H5 роднойPortal标签Он тоже есть в планах.Хотя есть некоторые проблемы с безопасностью, во избежание дублирования имен он изменен наTeleport.

Обычный сценарий использования Teleport — передача положения модального окна в некоторые глубоко вложенные компоненты. Хотя модальное окно логически относится к этому компоненту, с точки зрения стиля и структуры DOM, оно не способствует обслуживанию (z-индекс и другие вопросы) после того, как уровень вложенности станет глубже, поэтому нам нужно его вырезать:

<template>
  <button @click="showDialog = true">打开模态框</button>

  <teleport to="body">
    <div class="modal" v-if="showDialog" style="position: fixed">
      我是一个模态框
      <button @click="showDialog = false">关闭</button>
      <child-component :msg="msg"></child-component>
    </div>
  </teleport>
</template>
<script>
export default {
  data() {
    return {
      showDialog: false,
      msg: "hello"
    };
  },
};
</script>

Здесь модальный div в Телепорте перенесен в нижнюю часть тела; хотя они и рендерятся в разных местах, элементы и компоненты в Телепорте по-прежнему являются логическими подкомпонентами родительского компонента, и все еще могут взаимодействовать с родителем компонент. Телепорт получает два параметраtoа такжеdisabled:

  • to - строка: Должен быть допустимым селектором запроса или HTMLElement, может быть селектором идентификатора или класса и т. д.
  • disabled - boolean: Если это правда, это означает, что функция телепорта отключена, и содержимое его слота не будет перемещено ни в какую позицию.По умолчанию false не отключено.

Suspense

Suspense — это встроенный компонент, запущенный Vue3, который позволяет нашей программе отображать некоторый резервный контент в ожидании асинхронных компонентов, что позволяет нам создать плавный пользовательский интерфейс; загрузка асинхронных компонентов в Vue на самом деле уже существует в Vue2.x, маршрутизация компонент, загруженный в используемый нами vue-router, на самом деле является асинхронным компонентом:

export default {
  name: "Home",
  components: {
    AsyncButton: () => import("../components/AsyncButton"),
  },
}

Переопределены в Vue3, асинхронные компоненты должны проходитьdefineAsyncComponentчтобы определить отображение:

// 全局定义异步组件
//src/main.js
import { defineAsyncComponent } from "vue";
const AsyncButton = defineAsyncComponent(() =>
  import("./components/AsyncButton.vue")
);
app.component("AsyncButton", AsyncButton);


// 组件内定义异步组件
// src/views/Home.vue
import { defineAsyncComponent } from "vue";
export default {
  components: {
    AsyncButton: defineAsyncComponent(() =>
      import("../components/AsyncButton")
    ),
  },
};

В то время как асинхронный компонент может иметь более сложное управление:

export default {
  components: {
    AsyncButton: defineAsyncComponent({
      delay: 100,
      timeout: 3000,
      loader: () => import("../components/AsyncButton"),
      errorComponent: ErrorComponent,
      onError(error, retry, fail, attempts) {
        if (attempts <= 3) {
          retry();
        } else {
          fail();
        }
      },
    }),
  },
};

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

异步组件加载失败

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

<template>
  <div>
    <button @click="showButton">展示异步组件</button>
    <template v-if="isShowButton">
      <Suspense>
        <template #default>
          <AsyncButton></AsyncButton>
        </template>
        <template #fallback>
          <div>组件加载中...</div>
        </template>
      </Suspense>
    </template>
  </div>
</template>
<script>
export default {
  setup() {
    const isShowButton = ref(false);
    function showButton() {
      isShowButton.value = true;
    }
    return {
      isShowButton,
      showButton,
    };
  },
}
</script>

异步组件加载显示占位

Несовместимые функции

Несовместимые функции — это в основном некоторый синтаксис, который сильно изменился в версии Vue2.x, и могут быть проблемы совместимости с Vue3.

данные, примеси и фильтры

В Vue2.x мы можем определить данные какobjectилиfunction, но мы знаем, что если данные являются объектом в компоненте, данные будут взаимодействовать друг с другом, потому что объект является ссылочным типом данных;

В Vue3 данные принимаются толькоfunctionтип, черезfunctionвозвращаемый объект; тем временемMixinОбъединенное поведение изменилось, и когда выполняется база данных класса Mixin Class Most Copy:

const Mixin = {
  data() {
    return {
      user: {
        name: 'Jack',
        id: 1,
        address: {
          prov: 2,
          city: 3,
        },
      }
    }
  }
}
const Component = {
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2,
        address: {
          prov: 4,
        },
      }
    }
  }
}

// vue2结果:
{
  id: 2,
  name: 'Jack',
  address: {
    prov: 4,
    city: 3
  }
}

// vue3结果:
user: {
  id: 2,
  address: {
    prov: 4,
  },
}

Мы видим результат окончательного слияния, vue2.x выполнит глубокую копию, а также объединит и скопирует данные в данные вниз и вглубь; в то время как vue3 выполняет только неглубокую копию, и данные в данных обнаруживаются существующими и не будут объединены и скопированы.

В vue2.x мы также можем передать过滤器filterЧтобы обработать отображение некоторого текстового содержимого:

<template>
  <div>{{ status | statusText }}</div>
</template>
<script>
  export default {
    props: {
      status: {
        type: Number,
        default: 1
      }
    },
    filters: {
      statusText(value){
        if(value === 1){
          return '订单未下单'
        } else if(value === 2){
          return '订单待支付'
        } else if(value === 3){
          return '订单已完成'
        }
      }
    }
  }
</script>

Чаще всего приходится бороться с отображением некоторых ордеров копирайтингом, однако в vue3 фильтр filter удален и больше не поддерживается, официальная рекомендация использовать вызовы методов или计算属性computedзаменить.

v-model

В Vue2.x,v-modelэквивалентно связываниюvalueсвойства иinputСобытия, которые по сути являются синтаксическим сахаром:

<child-component v-model="msg"></child-component>
<!-- 相当于 -->
<child-component :value="msg" @input="msg=$event"></child-component>

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

<child-component 
    v-model="msg" 
    :msg1="msg1" 
    @change1="msg1=$event"
    :msg2="msg2" 
    @change2="msg2=$event">
</child-component>

Представлено в версии vue2.3.0+.syncМодификаторы, которые по сути являются синтаксическим сахаром, связаны с компонентами.@update:propNameОбратный вызов, более краткий синтаксис:

<child-component 
    :msg1.sync="msg1" 
    :msg2.sync="msg2">
</child-component>

<!-- 相当于 -->

<child-component 
    :msg1="msg1" 
    @update:msg1="msg1=$event"
    :msg2="msg2"
    @update:msg2="msg2=$event">
</child-component>

Генерал-лейтенант Вью3v-modelа также.syncФункция интегрирована, а .sync заброшен, что означает, что несколько значений значений двусторонней привязки могут быть напрямую переданы через несколько v-моделей; в то же время имя свойства по умолчанию, переданное v-моделью, изменено с значение в modelValue:

<child-component 
    v-model="msg">
</child-component>

<!-- 相当于 -->
<child-component 
  :modelValue="msg"
  @update:modelValue="msg = $event">
</child-component>

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

<child-component 
    v-model.msg1="msg1"
    v-model.msg2="msg2">
</child-component>

<!-- 相当于 -->
<child-component 
    :msg1="msg1" 
    @update:msg1="msg1=$event"
    :msg2="msg2"
    @update:msg2="msg2=$event">
</child-component>

v-для и ключ

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

<template v-for="item in list">
  <div :key="item.id">...</div>
  <span :key="item.id">...</span>
</template>

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

<template v-for="item in list" :key="item.id">
  <div>...</div>
  <span>...</span>
</template>

v-связать слияние

В vue2.x, если элемент определен одновременноv-bind="object"и идентичное отдельное свойство, то это отдельное свойство переопределяетobjectПривязки в:

<div id="red" v-bind="{ id: 'blue' }"></div>
<div v-bind="{ id: 'blue' }" id="red"></div>

<!-- 最后结果都相同 -->
<div id="red"></div>

Однако в vue3, если элемент определен одновременноv-bind="object"И идентичный индивидуальный атрибут, порядок привязки объявления определяет последний результат (последний покрывает первый):

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>

исх в v-для

В vue2.x используется на v-forrefсвойства, черезthis.$refsполучит массив:

<template
  <div v-for="item in list" :ref="setItemRef"></div>
</template>
<script>
export default {
  data(){
    list: [1, 2]
  },
  mounted () {
    // [div, div]
    console.log(this.$refs.setItemRef) 
  }
}
</script>

Но это может быть не тот результат, который нам нужен, поэтому vue3 больше не создает массив автоматически, а превращает обработку ref в функцию, которая по умолчанию передается в ноду:

<template
  <div v-for="item in 3" :ref="setItemRef"></div>
</template>
<script>
import { reactive, onUpdated } from 'vue'
export default {
  setup() {
    let itemRefs = reactive([])

    const setItemRef = el => {
      itemRefs.push(el)
    }

    onUpdated(() => {
      console.log(itemRefs)
    })

    return {
      itemRefs,
      setItemRef
    }
  }
}
</script>

v-для и v-если приоритет

В vue2.x используйте как v-for, так и v-if для элемента,v-forОн имеет более высокий приоритет, поэтому для оптимизации производительности в Vue2.x важный момент заключается в том, что V-для и V-IF нельзя размещать на одном элементе.

И в vue3,v-ifСравниватьv-forимеют более высокий приоритет. Поэтому следующий код может нормально работать в vue2.x, но не тогда, когда v-if вступает в силу в vue3.itemпеременная, поэтому будет сообщено об ошибке:

<template>
  <div v-for="item in list" v-if="item % 2 === 0" :key="item">{{ item }}</div>
</template>

<script>
export default {
  data() {
    return {
      list: [1, 2, 3, 4, 5],
    };
  },
};
</script>

Суммировать

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

Для получения дополнительной информации о внешнем интерфейсе, пожалуйста, обратите внимание на общедоступный номер【前端壹读】.

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