После долгой итерации,Vue
Наконец, 18 сентября 2020 г. была выпущена версия 3.0 с потрясающими изменениями с использованиемTypescript
подвергся масштабному рефакторингу, в результате чегоComposition API RFC
версия вродеReact Hook
написать то же самоеVue
, вы можете настроить свой собственныйhooks
, сделать пользователей более гибкими, а затем обобщитьvue 3.0
некоторые новые функции.
setup()
ref()
-
reactive()
,shallowReactive()
isRef()
toRefs()
-
readonly()
,isReadonly()
,shallowReadonly()
computed()
watch()
-
LifeCycle
Hooks
(новый жизненный цикл) Template refs
globalProperties
Suspense
Provide/Inject
Сравнение Vue2 и Vue3
- правильно
TypeScript
Поддержка недружественная (все свойства размещены вthis
На объект сложно пропихнуть тип данных компонента) - Много
API
Прикреплено кVue
На прототипе объекта сложно добитьсяTreeShaking
. - Уровень архитектуры против кроссплатформенности
dom
Оказание поддержки разработки не является дружественным -
CompositionAPI
. отReactHook
вдохновленный - более удобная поддержка
jsx
- Вью 3
Template
Поддержка нескольких корневых тегов, не поддерживается в Vue 2. - Переписан виртуальный DOM, оптимизирована компиляция шаблона...
1. функция настройки
setup()
функцияvue3
, новые свойства, предоставленные специально для компонентов. это работает для насvue3
изComposition API
Новая функция обеспечивает единую запись,setup
функция будет вbeforeCreate
,created
выполненный ранее,vue3
Также отмените эти два хука, унифицированное использованиеsetup
Вместо этого функция эквивалентна функции жизненного цикла,vue
в прошломdata
,methods
,watch
Подождите, пока все используют соответствующие новыеapi
писать наsetup()
в функции
setup(props, context) {
// Attribute (非响应式对象,等同于 $attrs)
context.attrs
// 插槽 (非响应式对象,等同于 $slots)
context.slots
// 触发事件 (方法,等同于 $emit)
context.emit
// 暴露公共 property (函数)
context.expose
return {}
}
-
props
: получитьprops
данные,props
является реактивным, когда передается в новыйprops
, он будет обновлен. -
context
Объект контекста, используемый для определения контекста, содержит некоторые полезные свойства, которые необходимо передать в vue 2.x.this
получить доступ, вsetup()
невозможно получить доступ в функцииthis
,Являетсяundefined
-
context
обычныйJavaScript
объект, то есть он не реактивный, а значит можно смелоcontext
использоватьES6
деконструировать. - возвращаемое значение:
return {}
, возвращает отзывчивые данные, функция, которую необходимо использовать в шаблоне
Примечание: потому что
props
отзывчивый, тыНевозможно использовать деструктурирование ES6, что убирает отзывчивость опоры. Но вы можете использовать следующий способ борьбы с
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
export default defineComponent({
setup(props, context) {
const { title } = toRefs(props)
console.log(title.value)
return {}
}
});
</script>
если title
является необязательным реквизитом, переданным вprops
может не иметь вtitle
. при этих обстоятельствах,toRefs
не будетtitle
Создайте реф. вам нужно использоватьtoRef
заменить его:
<script lang="ts">
import { defineComponent, reactive, toRef, toRefs } from 'vue';
export default defineComponent({
setup(props, context) {
const { title } = toRef(props, 'title')
console.log(title.value)
return {}
}
});
</script>
Во-вторых, реактивные, поверхностные Реактивные функции
2.1 reactive()
reactive()
Функция принимает обычный объект и возвращает реактивный объект данных, что эквивалентноVue 2.x
середина Vue.observable()
API, реактивное преобразование является «глубоким» — оно затрагивает все вложенные свойства. Он реализован на основе прокси, а использовать созданные адаптивные данные очень просто.После его создания вsetup
серединаreturn
снаружи, прямо наtemplate
можно позвонить в
<template>
{{name}} // test
<template>
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
export default defineComponent({
setup(props, context) {
let state = reactive({
name: 'test'
});
return state
}
});
</script>
Примечание. API возвращает реактивное состояние объекта. Это реактивное преобразование является «глубоким преобразованием» — оно затрагивает все вложенные свойства переданного объекта.
2.1 shallowReactive()
Создайте реактивный прокси, который отслеживает реакцию своих собственных свойств.shallowReactive
Создавайте нерекурсивные данные ответа, прослушивайте только изменения в первом слое данных, но не выполняйте глубокие реактивные преобразования вложенных объектов (открывая исходное значение).
<script lang="ts">
import { shallowReactive } from "vue";
export default defineComponent({
setup() {
const test = shallowReactive({ num: 1, creator: { name: "撒点了儿" } });
console.log(test);
test.creator.name = "掘金";
return {
test
};
},
});
</script>
3. функция ref()
ref()
Функция используется для создания реактивного объекта данных на основе заданного значения,ref()
Возвращаемое значение вызова функции — это объект, содержащий только одинvalue
свойство, доступное только внутри функции настройкиref
нужно добавить функцию.value
, цель которого создает независимые примитивные значения
<template>
<div class="mine">
{{count}} // 10
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const count = ref<number>(10)
// 在js 中获取ref 中定义的值, 需要通过value属性
console.log(count.value);
return {
count
}
}
});
</script>
существуетreactive
доступ к объектамref
Созданы адаптивные данные
<template>
<div class="mine">
{{count}} -{{t}} // 10 -100
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
export default defineComponent({
setup() {
const count = ref<number>(10)
const obj = reactive({
t: 100,
count
})
// 通过reactive 来获取ref 的值时,不需要使用.value属性, ref 将被自动解包
console.log(obj.count);
return {
...toRefs(obj)
}
}
});
</script>
4. Функция isRef()
isRef()
используется для определения того, является ли значениеref()
созданный объект
<script lang="ts">
import { defineComponent, isRef, ref } from 'vue';
export default defineComponent({
setup(props, context) {
const name: string = 'vue'
const age = ref<number>(18)
console.log(isRef(age)); // true
console.log(isRef(name)); // false
return {
age,
name
}
}
});
</script>
Пять, функция toRefs()
toRefs()
функция может бытьreactive()
Созданный отзывчивый объект преобразуется в обычный объект, за исключением того, что каждый узел атрибута этого объектаref()
тип реактивных данных
<template>
<div class="mine">
{{name}} // test
{{age}} // 18
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
export default defineComponent({
setup(props, context) {
let state = reactive({
name: 'test'
});
const age = ref(18)
return {
...toRefs(state),
age
}
}
});
</script>
Шесть, readonly(), isReadonly(), smallReadonly()
6.1 только для чтения() и isReadonly()
-
readonly
: входящийref
илиreactive
объект и возвращает доступный только для чтения прокси исходного объекта, а любые вложенные свойства внутри объекта также доступны только для чтения и рекурсивно только для чтения. -
isReadonly
: проверьте, создан ли объектreadonly
Создан объект только для чтения
<script lang="ts">
import { readonly, reactive } from "vue";
export default defineComponent({
setup() {
const test = reactive({ num: 1 });
const testOnly = readonly(test);
console.log(test);
console.log(testOnly);
test.num = 110;
// 此时运行会提示 Set operation on key "num" failed: target is readonly.
// 而num 依然是原来的值,将无法修改成功
testOnly.num = 120;
// 使用isReadonly() 检查对象是否是只读对象
console.log(isReadonly(testOnly)); // true
console.log(isReadonly(test)); // false
// 需要注意的是: testOnly 值会随着 test 值变化
return {
test,
testOnly,
};
},
});
</script>
мы знаемconst
Определенные переменные также не могут быть изменены.readonly
иconst
Какая разница?
-
const
защита присвоения, использованиеconst
Определенная переменная, которую нельзя переназначить. но еслиconst
Присвоение относится к объекту, поэтому вещи в объекте могут быть изменены. Причина в том, чтоconst
То, что определенная переменная не может быть изменена, так это то, что адрес, соответствующий объекту, не может быть изменен. - и
readonly
Это защита собственности и не может быть переназначена собственности
6.2 shallowReadonly()
shallowReadonly
Роль обрабатывает только реактивные (поверхностные реактивные) только для чтения самые внешние свойства объекта, но не выполняет глубокие преобразования вложенных объектов только для чтения (открывая исходное значение).
<script lang="ts">
import { readonly, reactive } from "vue";
export default defineComponent({
setup() {
const test = shallowReadonly({ num: 1, creator: { name: "撒点了儿" } });
console.log(test);
// 依然会提示: Set operation on key "num" failed: target is readonly.
// 而num 依然是原来的值,将无法修改成功
test.num = 3;
// 但是对于深层次的属性,依然可以修改
test.creator.name = "掘金";
return {
test
};
},
});
</script>
Семь, вычислено()
Эта функция используется для создания вычисляемых свойств, и, как и в прошлом, возвращаемое ею значение является объектом ссылки.
Он может передать метод или объект, объект содержитset()
,get()
метод
7.1 Создание вычисляемых свойств, доступных только для чтения
import { computed, defineComponent, ref } from 'vue';
export default defineComponent({
setup(props, context) {
const age = ref(18)
// 根据 age 的值,创建一个响应式的计算属性 readOnlyAge,它会根据依赖的 ref 自动计算并返回一个新的 ref
const readOnlyAge = computed(() => age.value++) // 19
return {
age,
readOnlyAge
}
}
});
</script>
7.2 Прохождениеset()
,get()
метод для создания вычисляемого свойства для чтения и записи
<script lang="ts">
import { computed, defineComponent, ref } from 'vue';
export default defineComponent({
setup(props, context) {
const age = ref<number>(18)
const computedAge = computed({
get: () => age.value + 1,
set: value => age.value + value
})
// 为计算属性赋值的操作,会触发 set 函数, 触发 set 函数后,age 的值会被更新
age.value = 100
return {
age,
computedAge
}
}
});
</script>
Восемь, смотреть () функция
watch
Функция используется для прослушивания определенного источника данных и выполнения побочных эффектов в функции обратного вызова. По умолчанию используется отложенное выполнение, то есть обратный вызов выполняется только при изменении исходных данных прослушивания.
8.1 Прослушивание источников данных, объявленных с помощью реактивного
<script lang="ts">
import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
interface Person {
name: string,
age: number
}
export default defineComponent({
setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 })
watch(
() => state.age,
(age, preAge) => {
console.log(age); // 100
console.log(preAge); // 10
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值
state.age = 100
return {
...toRefs(state)
}
}
});
</script>
8.2 Прослушивание источников данных, объявленных с помощью ref
<script lang="ts">
import { defineComponent, ref, watch } from 'vue';
interface Person {
name: string,
age: number
}
export default defineComponent({
setup(props, context) {
const age = ref<number>(10);
watch(age, () => console.log(age.value)); // 100
// 修改age 时会触发watch 的回调, 打印变更后的值
age.value = 100
return {
age
}
}
});
</script>
8.3 Одновременное прослушивание нескольких значений
<script lang="ts">
import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
interface Person {
name: string,
age: number
}
export default defineComponent({
setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 })
watch(
[() => state.age, () => state.name],
([newName, newAge], [oldName, oldAge]) => {
console.log(newName);
console.log(newAge);
console.log(oldName);
console.log(oldAge);
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
state.age = 100
state.name = 'vue3'
return {
...toRefs(state)
}
}
});
</script>
8.4 перестань слушать
существуетsetup()
создается внутри функцииwatch
Часы автоматически остановятся, когда текущий компонент будет уничтожен. Если вы хотите явно остановить часы, вы можете вызватьwatch()
Возвращаемого значения функции достаточно, синтаксис следующий:
<script lang="ts">
import { set } from 'lodash';
import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
interface Person {
name: string,
age: number
}
export default defineComponent({
setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 })
const stop = watch(
[() => state.age, () => state.name],
([newName, newAge], [oldName, oldAge]) => {
console.log(newName);
console.log(newAge);
console.log(oldName);
console.log(oldAge);
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
state.age = 100
state.name = 'vue3'
setTimeout(()=> {
stop()
// 此时修改时, 不会触发watch 回调
state.age = 1000
state.name = 'vue3-'
}, 1000) // 1秒之后讲取消watch的监听
return {
...toRefs(state)
}
}
});
</script>
Девять, LifeCycle Hooks (новая жизнь в более позднем периоде)
Новую версию функции жизненного цикла можно импортировать в компонент по мере необходимости и использовать только вsetup()
функции, но также может использоваться вsetup
вне определения, вsetup
используется в
<script lang="ts">
import { set } from 'lodash';
import { defineComponent, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onErrorCaptured, onMounted, onUnmounted, onUpdated } from 'vue';
export default defineComponent({
setup(props, context) {
onBeforeMount(()=> {
console.log('beformounted!')
})
onMounted(() => {
console.log('mounted!')
})
onBeforeUpdate(()=> {
console.log('beforupdated!')
})
onUpdated(() => {
console.log('updated!')
})
onBeforeUnmount(()=> {
console.log('beforunmounted!')
})
onUnmounted(() => {
console.log('unmounted!')
})
onErrorCaptured(()=> {
console.log('errorCaptured!')
})
return {}
}
});
</script>
10. Ссылки на шаблоны
пройти черезrefs
туда и обратно правдаdom
элемент, это иreact
Как обычно, чтобы получить ссылку на экземпляр элемента или компонента в шаблоне, мы можемsetup()
объявитьref
и вернуть его
- Как всегда, в
html
написать вref
Название - существует
steup
определитьref
-
steup
вернуться вref
экземпляр -
onMounted
доступно вref
изRefImpl
объект, по.value
получить реальныйdom
<template>
<!--第一步:还是跟往常一样,在 html 中写入 ref 的名称-->
<div class="mine" ref="elmRefs">
<span>1111</span>
</div>
</template>
<script lang="ts">
import { set } from 'lodash';
import { defineComponent, onMounted, ref } from 'vue';
export default defineComponent({
setup(props, context) {
// 获取真实dom
const elmRefs = ref<null | HTMLElement>(null);
onMounted (() => {
console.log(elmRefs.value); // 得到一个 RefImpl 的对象, 通过 .value 访问到数据
})
return {
elmRefs
}
}
});
</script>
Одиннадцать, глобальная конфигурация vue
пройти черезvue
примерconfig
настроить, в том числеVue
Объект глобальной конфигурации приложения. Вы можете изменить перечисленные ниже свойства перед монтированием приложения:
const app = Vue.createApp({})
app.config = {...}
Назначьте обработчики необработанных ошибок во время рендеринга компонентов и наблюдателей. Ошибка и экземпляр приложения вызовут обработчик
app.config.errorHandler = (err, vm, info) => {}
Глобальные свойства, к которым можно получить доступ в любом экземпляре компонента в приложении, свойства компонента будут иметь приоритет. это можно заменитьVue
2.xVue.прототип расширения:
const app = Vue.createApp({})
app.config.globalProperties.$http = 'xxxxxxxxs'
можно использовать в компонентах черезgetCurrentInstance()
чтобы получить глобальныйglobalProperties
информация настроена в,getCurrentInstance
метод для получения экземпляра текущего компонента, а затем передатьctx
свойство для получения текущего контекста, поэтому мы можемsetup
используется вrouter
иvuex
, через это свойство мы можем манипулировать переменными, глобальными свойствами, свойствами компонентов и т. д.
setup( ) {
const { ctx } = getCurrentInstance();
ctx.$http
}
12. Компоненты подвески
Представить в началеVue
изSuspense
Перед компонентами нам нужно сначала понятьReact
изSuspense
компоненты, потому что их функции схожи.
React.lazy
Принимает функцию, которую необходимо вызвать динамическиimport()
. он должен вернутьPromise
,ДолженPromise
необходимостьresolve
Одинdefault export
изReact
компоненты.
import React, { Suspense } from 'react';
const myComponent = React.lazy(() => import('./Component'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<myComponent />
</Suspense>
</div>
);
}
Vue3
также добавленоReact.lazy
аналогичная функцияdefineAsyncComponent
Функция, которая обрабатывает динамический импорт (компонентов).defineAsyncComponent
Фабричная функция, которая возвращает обещание, может быть принята. Когда вы получаете определение компонента с сервера, вы должны вызватьPromise
разобрать обратный вызов. Вы также можете позвонитьreject(reason)
чтобы указать, что загрузка не удалась
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
Vue3 также добавил компонент Suspense:
<template>
<Suspense>
<template #default>
<my-component />
</template>
<template #fallback>
Loading ...
</template>
</Suspense>
</template>
<script lang='ts'>
import { defineComponent, defineAsyncComponent } from "vue";
const MyComponent = defineAsyncComponent(() => import('./Component'));
export default defineComponent({
components: {
MyComponent
},
setup() {
return {}
}
})
</script>
Тринадцать, Обеспечить / Ввести
Обычно, когда нам нужно передать данные от родительского компонента к дочернему, мы используемprops
. Представьте себе структуру, в которой есть несколько глубоко вложенных компонентов, а глубоким дочерним компонентам нужна только часть родительского содержимого. В этом случае, еслиprop
Передача компонентов по цепочке может быть обременительной.
В этом случае мы можем использовать пару provide
иinject
. Независимо от того, насколько глубока иерархия компонентов, родительский компонент может действовать как поставщик зависимостей для всех своих дочерних компонентов. Эта функция состоит из двух частей: родительский компонент имеетprovide
возможность предоставления данных, дочерний компонент имеетinject
возможность начать использовать данные.
Конкретное использование заключается в следующем:
13.1 Основное использование
// 父组件
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
provide: {
provideData: { name: "撒点了儿" },
}
});
</script>
// 子组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
{{ provideData }}
</div>
</template>
<script lang="ts">
export default defineComponent({
name: "HelloWorld",
props: {
msg: String,
},
inject: ["provideData"],
});
</script>
13.2 Использование в setup()
существуетsetup()
используется, вам нужно явно импортировать из vueprovide
,inject
метод. После импорта мы можем вызвать его, чтобы определить, как компонент отображается для нас.
provide
Функции позволяют вам определять свойства с двумя параметрами:
-
name
:имя параметра -
value
: стоимость имущества
<script lang="ts">
import { provide } from "vue";
import HelloWorldVue from "./components/HelloWorld.vue";
export default defineComponent({
name: "App",
components: {
HelloWorld: HelloWorldVue,
},
setup() {
provide("provideData", {
name: "撒点了儿",
});
},
});
</script>
<script lang="ts">
import { provide, inject } from "vue";
export default defineComponent({
name: "HelloWorld",
props: {
msg: String,
},
setup() {
const provideData = inject("provideData");
console.log(provideData); // { name: "撒点了儿" }
return {
provideData,
};
},
});
</script>
13.3 Передача данных ответа
чтобы увеличитьprovide
ценность иinject
отзывчивость между значениями, мы можемprovide
значение для использованияref
илиreactive
.
<script lang="ts">
import { provide, reactive, ref } from "vue";
import HelloWorldVue from "./components/HelloWorld.vue";
export default defineComponent({
name: "App",
components: {
HelloWorld: HelloWorldVue,
},
setup() {
const age = ref(18);
provide("provideData", {
age,
data: reactive({ name: "撒点了儿" }),
});
},
});
</script>
<script lang="ts">
import { inject } from "vue";
export default defineComponent({
name: "HelloWorld",
props: {
msg: String,
},
setup() {
const provideData = inject("provideData");
console.log(provideData);
return {
provideData,
};
},
});
</script>
Если вы хотите, чтобы данные, передаваемые через provider, не изменялись внедренным компонентом, мы рекомендуем использовать readonly для свойства провайдера.
Четырнадцать, vue 3.x полная структура шаблона компонента
завершенныйvue 3.x
Полная структура шаблона компонента включает: имя компонента,props
,components
,setup(hooks、computed、watch、methods 等)
<template>
<div class="mine" ref="elmRefs">
<span>{{name}}</span>
<br>
<span>{{count}}</span>
<div>
<button @click="handleClick">测试按钮</button>
</div>
<ul>
<li v-for="item in list" :key="item.id">{{item.name}}</li>
</ul>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, getCurrentInstance, onMounted, PropType, reactive, ref, toRefs } from 'vue';
interface IState {
count: 0,
name: string,
list: Array<object>
}
export default defineComponent({
name: 'demo',
// 父组件传子组件参数
props: {
name: {
type: String as PropType<null | ''>,
default: 'vue3.x'
},
list: {
type: Array as PropType<object[]>,
default: () => []
}
},
components: {
/// TODO 组件注册
},
emits: ["emits-name"], // 为了提示作用
setup (props, context) {
console.log(props.name)
console.log(props.list)
const state = reactive<IState>({
name: 'vue 3.0 组件',
count: 0,
list: [
{
name: 'vue',
id: 1
},
{
name: 'vuex',
id: 2
}
]
})
const a = computed(() => state.name)
onMounted(() => {
})
function handleClick () {
state.count ++
// 调用父组件的方法
context.emit('emits-name', state.count)
}
return {
...toRefs(state),
handleClick
}
}
});
</script>
Экология vue 3
библиотека компонентов пользовательского интерфейса