Зачем использовать состав API
Многие могут спросить, почему обязательноvue2использовать наcomposition-apiШерстяная ткань? Обновите проект прямо доvue3Разве это не будет хорошо?
- Экологические проблемы, многие библиотеки с открытым исходным кодом в настоящее время постепенно обновляются до vue3.
- Если проект очень большой, начните
vue2->vue3Миграция по-прежнему очень проблематична. - существует
vue2использоватьcomposition-apiЭто не повлияет на существующие функции, и в будущем, если вы захотите перейти наvue3Затем просто измените импортированный пакет с@vue/composition-apiизменить наvueВ теме
Установите @vue/composition-api
npm install @vue/composition-api
# or
yarn add @vue/composition-api
Просто скачать его недостаточно, нужно еще зарегистрировать его как плагинVue.use()
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
затем в.vueВведенный в компонент, вы можете использовать частьvue3функция
// use the APIs
import { ref, reactive } from '@vue/composition-api'
// 💡 When you migrate to Vue 3, just replacing `@vue/composition-api` to `vue` and your code should just work.
import { ref, reactive } from 'vue'
Поддержка TypeScript
Некоторые студенты могут спросить, я используюVue2проект представленvue-property-decoratorа такжеvue-class-componentподдерживатьTypescript, если я перейду наcomposition-apiспособ написания, то я могу только написатьJavascriptуже? усердно учился раньшеTypeScriptРазве это не белый.
Не волнуйтесь, друзья, хотяVue 2.6Предыдущая версияVueиспользуетсяflowсделать проверку типов, но вVue3так же какVue confУпомянутое выше было выпущено в Q3Vue2.7используютсяTypeScriptсделать проверку типов, всеcomposition-apiтакже поддерживатьTypeScriptиз
но нужноTypeScriptверсия>3.5.1
import { defineComponent } from '@vue/composition-api'
// 只需要把代码写在defineComponent里面,ts的静态检查就会工作
export default defineComponent({
// type inference enabled
props:{}
setup(props,ctx){}
data(){}
created(){}
mounted(){}
})
Поддержка браузера
а такжеVue3Такой же,composition-apiПоддерживает все современные браузеры и IE11+, если вам нужна поддержка более ранних версий IE, вам следует установитьWeakMapполифилл напримерcore-js
composition-api VS options api
Как следующий кодVue2options api, когда наш код достигнет определенного объема, эту структуру будет трудно поддерживать.В это время, некоторые люди скажут, что мы можем использоватьmixinИзвлеките общую логику.
<scirpt>
export default {
components:{}
mixins:[xxxMixin]
props:{}
data(){
return{
// some reactive data
}
}
created(){
this.getList()
}
methods:{
getList(){}
}
}
</scirpt>
Но я думаю многие сталкивались с такой проблемой: в<template>илиmethodsПри поиске метода или переменной в параметрах выполняйте поиск по всему.vueфайлы не найдены, пока не увидитеscriptсмотрите на этикеткеmixinsВарианты приходили в себя, ох, как оказалось, вперемешку, а то еслиmixinsесть несколькоmixinПерейдите к каждому файлу, чтобы найти соответствующую переменную
В дополнение к вышеуказанному случаю, если нам нужно перейти к этому.vueфайл для добавления новых функций, то нам, скорее всего, потребуется выполнить следующие шаги
1⃣️ВdataОпределите соответствующую переменную в опциях, чтобы эта переменная могла стать отзывчивой
2⃣️ВmethodsДобавьте соответствующий метод функции в параметры
Или мы можем извлечь новые функции вmixinНо таким образом мы можем столкнуться с проблемами, упомянутыми ранее.Конечно, мы также можем избежать этих проблем некоторыми методами, такими как определение префикса переменной с помощьюMixin_НапримерMixin_xxxИтак, когда мы используем эту переменную, мы знаем, что этоmixin, вместо того, чтобы искать во всех файлах, чтобы узнать, что онmixin
Ниже я буду использовать классическую старую картинку, чтобы показатьcomposition-apiего преимущество
Некоторые люди могут быть очень смущены, увидев эту картинку, и они скажут: «Эй, мальчик, я вижу, что объем кода не сильно изменился после сравнения двух. Он все еще такой длинный. Посмотри на него».
Но на самом деле мы можем поставить код цвета справа как таковой
setup(props,ctx){
// 相对于mixin是不是更加的清晰
const { username,login } = useLogin()
const { pageNum, total, pageSize, getList } = usePagination()
const { xxx, XXX } = useXxx()
}
Почему вы видите это случиться?
В этом случае необходимо ввестиrefтак же какreactiveЭти два понятия
исх, реактивный
В параметрах API, если мы хотим, чтобы переменная была реактивной, нам нужно определить переменную вdata()в, но вsetup()в мы можем использоватьrefилиreactiveсуществуетsetupВ любом месте тела этой функции переменная преобразуется в реактивную переменную.
setup(){
// 我们可以先在这里定义一个变量
const dataList = ref([])
dataList.value = getList()
// 假设我们的代码很长,然后如果有某些条件,我们可以紧接着再定义一个变量,而不需要再回到data()里面重新定义一个新变量使得这个变量reactive
const message = ref('')
message.value = getMessage()
// 当然,如果你习惯了options api或者说,你们公司自己的规范就是希望变量都定义在同一个区域内。那么你也可以这么写
const data = reactive({
dataList:[],
message:''
})
data.dataList = getList()
data.message = getMessage()
}
Внимательные друзья, возможно, обнаружили, что,refа такжеreactiveКогда мы выполняем манипуляции с данными на двух из них, они ведут себя немного по-разному, почему?refнеобходимо определить.valueпосетить? В это время вы должны увидетьофициальная документациясреда дляrefтак же какreactiveвведение
существуетVue3в вы можете пройтиrefфункция, чтобы сделать любую переменную реактивной, как вVue2изdata()так же, как определено в
import { ref } from 'vue'
const counter = ref(0)
refПринимает один параметр и возвращает объект, обертывающийvalueсвойства, поэтому мы можем передать этоvalueчтобы получить доступ к этому свойству или изменить его
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value++
console.log(counter.value) // 1
так почему этоrefЧто делать так сложно, 1 пакет будешь ставить? Классическая динамическая карта официального сайта, яркое пояснение - делать это ради бога.
Это дляJavaScriptподдерживать согласованное поведение различных типов данных. Потому чтоJavaScript, базовые типы, такие какNumber,Stringпередается по значению, а не по ссылке.
После того, как мы обернем эту переменную и превратим ее в объект, мы можем безопасно передавать ее по приложению, не беспокоясь о потере ее отзывчивости в некоторых местах в процессе передачи.
другими словами,refВсе, что мы делаем для нашей переменной, — это создаем реактивныйcomposition-apiпроцесс, это引用Понятие будет появляться часто.
Теперь вернемся к нашему коду выше,
// index.js
export default defineComponent({
setup(props,ctx){
// 相对于mixin是不是更加的清晰
const { username,login } = useLogin()
const { pageNum, total, pageSize, getList } = usePagination()
const { xxx, XXX } = useXxx()
}
})
Когда мы вынимаем общий код и используем эти'mixin'по сравнению сmixinЭто более ясно
// usePagination.js
export default function usePagination(){
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
const getList = () => {
// some logic...
}
return {
pageNum,
pageSize,
total,
getList
}
}
Мы здесьrefсозданный引用для запуска через наш составной API.
Следует отметить, что если вы хотитеtemplateЧтобы использовать переменные, вам нужно поместить ихreturnвне, и мимоrefСозданные переменные также не нужно использовать.valueпосетить, он автоматически развернется
Setup()
существуетsetupУ нас будет два параметра для использования, один из нихprops, другойcontext, давайте посмотрим, что это за два параметра
Props
propsНа самом деле, это значение prop нашего родительского компонента при передаче значения нашему дочернему компоненту.setupНам нужно вызывать их с этим параметром, потому что вsetupсередина,thisЭто невозможно,setupсерединаthisне указывая прямо наVueпример
export default defineComponent({
props: {
searchTemplate: {
type: Array,
required: true
}
},
setup(props){
// 你可以直接这么访问
console.log(props.searchTemplate)
}
})
когда вы используете напрямуюprops.xxxПри обращении это отзывчиво.При изменении данных родительского компонента, здесь тоже будут меняться, но когда вы захотите использоватьES6Когда деконструкция этот атрибут потеряет отзывчиво. Если вы хотите разложить, вы должны использовать значение, передаваемое реквизитом, то вам следует использовать его.toRefsСледует отметить, что доступ осуществляется через ==.value==
export default defineComponent({
props: {
searchTemplate: {
type: Array,
required: true
}
},
setup(props){
// 你可以直接这么访问
console.log(props.searchTemplate)
// ❌
const { searchTemplate } = props
// ✅
const { searchTemplate } = toRefs(props)
console.log(searchTemplate.value)
}
})
когда твоя опора неrequiredкогда это неопределенно, вы используетеtoRefsможет быть недоступен, то он не создаст егоref, на этот раз вы хотите использоватьtoRefохватывать
export default defineComponent({
props: {
searchTemplate: {
type: Array,
required: true
},
total: {
type:Number,
default:0
}
},
setup(props){
const { total } = toRef(props,'total')
console.log(total.value)
}
})
Context
setupВторой параметр вcontext,существуетVue3Введение в официальную документацию является обычнымJavaScriptобъект, который предоставляет три свойства компонента, которыеattrs,slots,emit, но по фактуVue2используется вsetupЕсли это, этоcontextОбъект находится внутри, не только эти три свойства.
Мы видим, что в дополнение к трем атрибутам, введенным выше, есть несколько атрибутов зачеркивания,parent,root,listeners,refsКогда мы наведем указатель мыши, мы увидим подсказку о том, что это заброшенный атрибут, этот атрибут находится вVue3Его нельзя использовать, конечно, если вы хотите его использовать, это не невозможно, если только вы не хотите перейти на этот проект в будущем.Vue3, в противном случае мой совет — следовать официальной практике и не использовать эти устаревшие свойства.
Вы также можете использовать деструктурирование, чтобы напрямую получить три вышеупомянутых свойства, в конце концовcontextпросто обычный объект
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
существуетsetupПри выполнении экземпляр компонента еще не создан,setupмеждуbeforeCreateа такжеcreatedмежду ними, другими словами, вы можете толькоsetupполучить доступ к следующим свойствам в
-
props -
attrs -
slots -
emit
Другими словами, вы не можете получить доступdata,computed,methods,а такжеsetupнет внутриthis, ты не сможешь, даже если захочешь посетить~~
this
Тогда кто-то может спросить, а, так как естьsetupне могу понятьthisтогда я обязанprototypeКак вызвать вышеуказанный метод, не паникуйте, давайте прочитаемофициальная документацияНашел этот материал
существуетVue3Уже не рекомендуется связывать метод напрямую вprototypeЭто выше, но изменено на другой API. Немного холодно смотреть на это ❤️. Не пропустил ли я этот объединенный API? Не паникуйте, у нас есть еще одинgetCurrentInstance, этот API позволяет нам получить доступ к экземпляру внутреннего компонента, давайтеconsole.log👀 Что внутри
Хе, чувак, там много всего, давай нажмем на этоproxyпосмотри
ДоcontextВсе свойства в нем появляются в этомproxyВнутри, заброшенный или годный к употреблению, некоторые студенты могут спросить, но я таких не видел.elementСвязанные методы, что?$message,$confirm, как мы все знаем, цепочка прототипов ищется по уровням вверх, а здесь не можем найти, смотрим на родителя
не только видетьelementметод, тоже виделVueНекоторые из наших собственных методов API, как мы можем использовать это конкретноproxyШерстяная ткань
import {
ComponentInternalInstance,
defineComponent,
getCurrentInstance,
} from '@vue/composition-api';
export default defineComponent({
setup(){
const { proxy } = getCurrentInstance()
}
})
Мы можем деконструировать его напрямую, но в этом случае вTypeScriptБудет ошибка в
Мой способ - использовать утверждение типаconst { proxy } = getCurrentInstance() as ComponentInternalInstance, некоторые люди могут сказать, что яproxy.$message,proxy.$router.pushТак некрасиво писать, я до сих пор к этому привыкthis.Тогда я рекомендую вам использовать ваши параметры API напрямую, ты сможешьproxyпереименовать, напримерconst { proxy:_this } = getCurrentInstance() as ComponentInternalInstanceТаким образом, он не сильно отличается от оригинала, не так ли?
LifeCycle
существуетsetupжизненный цикл и традиционныеoptions apiЭто немного другое,setupв нетcreatedа такжеbeforeCreateДа, вsetupЕсли вы непосредственно напечатаете абзац в консоли, вы обнаружите, что между ними выполняется настройка.
И для других функций ловушки жизненного цикла,vueОни также были переименованы, чтобы быть более семантическими.
| Options API | Hook inside setup
|
|---|---|
beforeCreate |
Not needed* |
created |
Not needed* |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
activated |
onActivated |
deactivated |
onDeactivated |
какие-то ступенчатые ямы
1. В начале используйте погоню за удобствомcontext.rootпередача$emitПри использовании метода, хотя у vetur есть подсказка для его использования, он вообще не сработает.$emit
2,getCurrentInstanceДеконструированное значение не должно находиться вreturnВернитесь внутрь, иначе произойдет ошибка, подробности можно посмотреть здесьissue
3. Потому чтоVue2а такжеVue3Реактив реализован немного по-другому, поэтомуreactiveОпределенная переменная будет немного отличаться. Если ее изменить напрямую, то переменная, скорее всего, не будет реагировать. Лучше всего использоватьrefДавай, см. это для деталейissue
reactive([1,2,3]) VS ref([])
этоissueЭто довольно ясно
наконец
Можно только сказать, что я с нетерпением жду версии 2.7, которая, по словам Vue conf, будет выпущена в третьем квартале.mixinПользоваться им веселее.