предисловие
Vue3Появление идеального решенияVue2Дефекты в некоторых аспектах, давайте пройдемся вместеVue3, посмотрите, какие изменения он нам приносит~
Vue3
Vue3СравниватьVue2Быстрее, меньше и меньше41%, улучшена скорость рендеринга33%, использование памяти падает54%. более гибкийComposition APIи идеальная поддержкаTypeScript. Благодаря этим цифрам и преимуществам нам очень важно поставитьVue3Удачной учебы! Ниже у нас естьVue3общий вCompsition APIОбъясните подробно.
Документация Vue3 на китайском языке
Composition API
Документация по составу API на китайском языке
- setup
setupфункцияфункция входа, В этой функции мы можем определить переменные, функции, жизненные циклы и т. д., а затем экспортировать их, к которым можно получить доступ на странице. Конкретные этапы использования следующие:
<template>
<p>数字为:{{num}}</p>
<p>两倍为:{{double}}</p>
<button @click="sum">累加</button>
</template>
<script>
import { ref, onMounted, computed } from "vue"; // 导入Vue3中的核心方法
export default {
..., // 可以定义一些Vue2时的options
setup() {
const num = ref(666); // 定义一个响应式的常量
const sum = (a, b) => a + b; // 定义一个方法
const double = computed(() => num.value+1) // 定义一个计算属性
onMounted(() => {
console.log('页面加载完执行的生命周期钩子函数')
})
// ...等等都可以定义在setup函数中
return { // 导出定义的变量和方法,在模板中使用
num,
sum,
double
}
}
}
</script>
Уведомление:setupФункция принимает два аргумента:props,context;
-
propsПредставляет свойство, переданное из родительского компонента, и значение является адаптивным. Если значение изменить, страница будет обновлена. Следовательно,propsДеструктуризация невозможна, но вы можете использоватьtoRefsПроведите деструктуризацию, иначе он потеряет отзывчивость. -
contextконтекст, содержащийattrs,slots,emitЖдать. Он не реактивный, поэтому его можно разобрать
когдаsetupПри выполнении экземпляр компонента не создается и может получить доступ только к следующим свойствам:props,attrs,slots,emit. Нет доступа к другим параметрам:computed,methodsЖдать.
Далее мы подробно объясним
Vue3Общие основные методы в !
- ref
ref: обычно задайте значение базового типа данных для адаптивного значения.
<template>
<p v-show="flag">是否显示</p>
<p>我的名字:{{name}}</p>
<p>我的年龄:{{age}}</p>
<p ref="refDom">你好啊</p>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const flag = ref(false); // 定义 Boolean 类型的变量
const age = ref(25); // 定义 Number 类型的变量
const name = ref('tmc'); // 定义 String 类型的变量
const refDom = ref(null); // 可以访问到 Dom 元素
return {
flag,
age,
name,
refDom
}
}
}
</script>
Уведомление:refОпределенные переменные будут автоматически расширены в шаблоне, поэтому нет необходимости использовать.value;существуетsetupИспользование этих переменных в функции не требует добавления.value
- reactive
Реактивное: обычно устанавливает значение типа ссылочного типа на адаптивное значение
<template>
<p>我的名字:{{state.name}}</p>
<p>我的年龄:{{state.age}}</p>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
const state = reactive({
name: 'tmc',
age: 25
})
return {
state
}
}
}
</script>
Уведомление:
-
reactiveпохожий наVue2серединаVue.observable() - Если вы хотите легко использовать его в модуле, вы можете использовать
toRefsэкспорт -
ref(variable)Эквивалентноreactive({value: variable})
- toRefs
toRefs: преобразует реактивные объекты в обычные объекты.
<template>
<p>我的名字:{{name}}</p>
<p>我的年龄:{{age}}</p>
</template>
<script>
import { toRefs, reactive } from "vue";
export default {
setup() {
const data = reactive({
name: 'tmc',
age: 25
})
return {
...toRefs(data)
}
}
}
</script>
Уведомление:toRefsПреобразуйте оба свойства вref; поэтому он не теряет своей отзывчивости при деструктурировании
- toRaw
toRaw: возвращеноreactiveилиreadonlyметоды конвертируются в простые объекты для реактивных прокси
<template>
<!-- ... -->
</template>
<script>
import { toRaw, reactive, ref } from "vue";
export default {
setup() {
const data1 = reactive({
name: 'tmc',
age: 25
})
const data2 = ref(666)
const changeData1 = toRaw(data1)
const changeData2 = toRaw(data2.value)
return {
...toRefs(data)
}
}
}
</script>
Уведомление: при конвертацииrefобъект, вам нужно пройти.value
- provide & inject
обеспечить и ввести: родительский компонент предоставляет данные с помощью параметра предоставления, а дочерний компонент принимает и использует предоставленные данные с помощью параметра ввода
<!-- 父组件 -->
<template>
<my-test></my-test>
</template>
<script>
import { provide } from "vue";
import MyTest from './MyTest';
export default {
components: {
MyTest
},
setup() {
provide('name', 'tmc')
// 可提供多个 provide
return {
// ...
}
}
}
</script>
Уведомление:provideПринимает два параметра, первыйkey, другойvalue
<!-- 子组件 -->
<template>
<p> {{name}} </p>
</template>
<script>
import { inject } from "vue";
export default {
components: {
MyTest
},
setup() {
const name = inject('name');
// inject('name', 'xxx'); // 可指定默认值
return {
name
}
}
}
</script>
Уведомление:injectПервый параметрkey, второй параметр может указывать значение по умолчанию (необязательно)
Чтобы предоставить и ввести реактивные значения, вы можете предоставитьprovideиспользовать, когдаrefа такжеreactive
- computed
вычислено: для вычисления свойств, пожалуйста, обратитесь к приведенному выше примеру.
- watch & watchEffect
Использование: смотреть( источник, cb, [опции] )
-
watchмониторrefСозданы адаптивные данные<template> <!-- ... --> </template> <script> import { watch, ref } from "vue"; export default { setup() { const name = ref('tmc'); watch(name, (newVal, oldVal) => { console.log('新值:' + newVal) console.log('旧值:' + oldVal) }) } } </script> -
watchмониторreactiveСозданы адаптивные данные<template> <!-- ... --> </template> <script> import { watch, reactive } from "vue"; export default { setup() { const data = reactive({ name: 'tmc', age: 25 }); // 监听单个属性 watch(() => data.name, (newVal, oldVal) => { console.log('新值:' + newVal) console.log('旧值:' + oldVal) }) // 监听多个属性 watch(() => [data.name, data.age], ([newName, oldName], [newAge, oldAge]) => { console.log('新值:' + newName) console.log('旧值:' + oldName) console.log('新值:' + newAge) console.log('旧值:' + oldAge) }) } } </script>
watch,watchEffectвернет функцию, чтобы остановить слушателяstop, пользователь может остановить мониторинг.
Уведомление:watchа такжеwatchEffectразница?
-
watchэто свойство, которое необходимо передать для мониторинга, иwatchEffectзаключается в автоматическом сборе зависимостей -
watchВы можете увидеть изменение значения свойства до и после, а такжеwatchEffectнет -
watchвыполняется при изменении свойства, иwatchEffectПо умолчанию он будет выполнен один раз, и изменения свойств также будут выполнены.
- ...
БолееComposition APIИнформацию об использовании и мерах предосторожности см.API композиции Vue
Жизненный цикл
Основное использование каждого жизненного цикла:
<template>
<!-- ... -->
</template>
<script>
import { onMounted, onUpdated, onUnmounted } from "vue";
export default {
setup() {
onMounted(() => {
console.log('mounted!') // 挂载
})
onUpdated(() => {
console.log('updated!') // 更新
})
onUnmounted(() => {
console.log('unmounted!') // 销毁
})
}
}
</script>
с версией 2.хразница
-
beforeCreate-> использоватьsetup -
created-> использоватьsetup -
beforeMount->onBeforeMount -
mounted->onMounted -
beforeUpdate->onBeforeUpdate -
updated->onUpdated -
beforeDestroy->onBeforeUnmount -
destroyed->onUnmounted -
errorCaptured->onErrorCaptured
Добавлена функция хука:
- onRenderTracked
- onRenderTriggered
Пользовательские функциональные хуки
Опустите, чтобы загрузить больше
// hooks/useLoadMore.ts
import { computed, onMounted, Ref } from 'vue';
import { IGlobalState } from '@/store';
import { Vuex } from 'vuex';
import _ from 'lodash';
export function useLoadMore(refreshEle: Ref<null | HTMLElement>, store: Store<IGlobalState>, type: string) {
let element: HTMLElement; // 需要滚动的元素
function _loadMore() {
let containerHeight = element.clientHeight; // 获取可视区域的高度
let scrollTop = element.scrollTop; // 获取滚动的高度
let scrollHeight = element.scrollHeight; // 获取这个列表的高度
if(containerHeight + scrollTop + 25 >= scrollHeight) {
store.dispatch(type); // 派发action
}
}
onMounted(() => {
element = refreshEle.value as HTMLElement;
element.addEventListener('scroll', _.debounce(_loadMore, 200)); // 防抖
})
// 可更改loading、hasMore等状态
const isLoading = computed(() => {
return store.state.home.homeList.loading
})
const hasMore = computed(() => {
return store.state.home.homeList.hasMore
})
}
использовать на странице
// index.vue
<template>
...
<div ref="refreshEle">
...
<HomeList :xxx="xxx"></HomeList>
...
</div>
...
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { Store, useStore } from 'vuex';
import { IGlobalState } from '@/store';
import { useLoadMore } from '@/hooks/useLoadMore';
export default defineComponent({
...
setup() {
let store = useStore<IGlobalState>();
let refreshEle = ref<null | HTMLElement>(null);
const { isLoading, hasMore } = useLoadMore(refreshEle, store, `home/${types.SET_HOME_LIST}`);
return {
refreshEle,
isLoading,
hasMore
}
}
...
})
</script>
Встроенные компоненты
Набор для телепортации
-
TeleportМодули можно перемещать в текущийDOMТехники в других местах вне Элементов
// index.html
<html>
...
<div id="app"></div>
<div id="teleport-toast"></div>
</html>
// components/index.vue
<button @click="showToast">显示toast</button>
<teleport to="#teleport-toast">
<div v-show="showFlag">
<div>
显示 Toast 内容
</div>
</div>
</teleport>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const showFlag = ref(false);
const showToast = (() => {
showFlag.value = true;
});
return {
showFlag,
showToast
}
}
})
Суммировать:использоватьteleportкомпоненты, черезtoсвойств, вручную укажите место, где компонент отображается и<div id="app"></div>тот же уровень, ноteleportположение делshowFlagопять же полностью изнутриVueУправление компонентами, это очень приятно~!
Suspense загружает компоненты асинхронно
<Suspense>
<!-- #default可不写 -->
<template #default>
<xxxx>某某组件</xxxx>
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
Уведомление:#default,#fallbackявляется сокращением для использования именованных слотов, например:v-slot:tmc === #tmc
расширять:Reactтакже содержит<Suspense>компоненты, часто сReact.lazy()Используется в сочетании
// 基本用法
import React, { Suspense } from 'react';
const Page = React.lazy(() => import('./Page'));
<Suspense fallback={<div> Loading... </div>}>
<Page />
</Suspense>
Vue3серединаdefineAsyncComponentа такжеReact.lazy()аналогичный
Fragement
существуетVue2.x, компонент может иметь только один кореньDOM,существуетVue3, компонент может иметь несколько корнейDOM
Глобальный API
- getCurrentInstance
- Изменения в способе регистрации компонентов
// Vue2 使用 Vue.component 方法
import Vue from 'vue';
import Test from './Test.vue';
Vue.component('Test', Test);
// Vue3 使用 createApp().component 方式
import { createApp, h } from 'vue';
import Test from './Test.vue';
createApp(Test).component('Comp', { render: () => h('div', '自定义组件') })
- часть
APIизменение способа его использования (дляtree-shaking)
// Vue2
import Vue from 'vue';
Vue.nextTick(() => {})
// Vue3
import { nextTick } from 'vue';
nextTick(() => {})
- Приложения
import { createApp } from 'vue';
const app = createApp(); // app 为应用实例
| Глобальный API Vue2.x | API экземпляра приложения Vue3 |
|---|---|
| Vue.config | app.config |
| Vue.config.productionTip | Удалить |
| Vue.use | app.config.isCustomElement |
| Vue.component | app.use |
| ... | ... |
Уведомление:
-
Vue3удаленный$on/$once/$offа такжеVue.filter
Vue-Router
Основное использование
import { createRouter, createWebHashHistory } from 'vue-router';
import Home from '@/views/home.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue');
}
]
const router = createRouter({
histroy: createWebHashHistory(),
routes
})
export default router;
Vuex
Основное использование
// store
import { createStore } from 'vuex';
export default createStore({
state: {}, // 状态
getters: {}, // 获取状态
mutations: {}, // 同步修改状态
actions: {}, // 异步修改状态
modules: {} // 模块
})
// template
<template>
...
</template>
<script>
import { useStore } from 'vuex';
export default defineComponent({
setup() {
const store = useStore(); // 创建store实例
...
}
})
</script>
Дизайн структуры полного магазина
Если проект относительно небольшой, вы можете обратиться к этой структуре каталогов
существуетstoreСоздайте четыре подкаталога и один файл в каталоге, а именно:
-
state: содержит состояние, используемое в проекте -
getters: Выполните некоторую обработку некоторых состояний перед использованием. -
mutations: Статус синхронизированной модификации -
actions: Состояние асинхронной модификации -
index.jsфайл: для интеграцииstate,getters,mutations,actions
Если проект относительно большой, вы можете обратиться к этой структуре каталогов
существуетstoreСоздайте каталог и файл в каталоге, а именно:
-
modules: хранить относительно большой модуль проекта, такой как: домашняя страница, мой... -
index.jsфайл: для интеграцииmodulesмодуль
НеквалифицированныйVuexДрузья, вы можете прочитать эту статью:Освойте использование и основные принципы Vuex core API на работе.
Vue2.x & Vue3
-
Vue2.0использоватьflowписать, покаVue3.0Весь исходный кодTypeScriptдля разработки, дружественная к поддержке TS (все свойства размещены вthisОбъект, трудно подтолкнуть к типу данных компонента) - Оптимизация размера исходного кода: удалить часть
api(filter),использоватьtree-shaking(МногоAPIПрикреплено кVueНа прототипе объекта сложно добитьсяTreeShaking) - Оптимизация захвата данных:
Vue3использоватьProxy, производительность значительно улучшилась - Скомпилируйте и оптимизируйте:
Vue3Реализован статический анализ шаблонов и алгоритм перезаписи различий -
Composition API: интегрируйте логику бизнес-кода, извлеките общую логику (с учетомReact HooksВдохновленный.Vue2использоватьmixin- конфликт имен и неясный источник данных) - Пользовательский рендерер: можно использовать для создания собственного рендерера и перезаписи базовой логики рендеринга Vue.
- новый
Fragment,Teleport,Suspenseи другие встроенные компоненты
Суммировать
Лучший способ изучить новую технологию — это использовать технологию для самостоятельного написания проекта, медленно исследовать и продолжать карабкаться по ямам, и тогда вы постепенно освоитесь ~