Подробное объяснение синтаксического сахара настройки скрипта Vue3

внешний интерфейс JavaScript Vue.js

В настоящее времяsetup sugarбыл завершен,vue3 + setup sugar + TSСпособ написания выглядит восхитительно, версия Vue на момент написания этой статьи"^3.2.6"

настройка скрипта синтаксический сахар

новый setupопция создается в компонентеДоpropsПосле анализа и выполнения это точка входа составного API.

WARNING
существует setupвам следует избегать использованияthis, потому что он не найдет экземпляр компонента.setupВызов происходит вdataимущество,computedсобственность илиmethodsперед анализом, поэтому они не могут быть > вsetupполучено в .

setupвариант полученияprops а также contextфункция , мы будемПозжепровести обсуждение. Кроме того, мы будемsetupВсе возвращаемое отображается для остальной части компонента (вычисляемые свойства, методы, обработчики жизненного цикла и т. д.) и для шаблона компонента.

Это новый синтаксический сахар для Vue3, вsetupв функции. Все экспорты модуля ES считаются значениями, доступными для контекста и включенными в возвращаемый объект setup(). По сравнению с предыдущим методом записи синтаксис становится проще после использования.

В тег script с добавленной настройкойНам не нужно объявлять и использовать метод, этот способ написания автоматически выставит все переменные и функции верхнего уровня в шаблон (шаблон) для использования.
Здесь подчеркивается, что «Разоблачение шаблона — это не то же самое, что раскрытие снаружи"

Он очень прост в использовании, нужно толькоscriptтег плюсsetupключевые слова подойдут. Пример:

<script setup></script>

Функция настройки — это новая опция компонента. Это унифицированный API, который предоставляет все свойства и методы внутри компонента.

После использования это означает, что содержимое тега script эквивалентно телу функции setup() в исходном объявлении компонента, но есть определенные отличия.

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

время вызова

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

используется в шаблоне

Если установка возвращает объект, свойства объекта будут объединены с контекстом рендеринга шаблона компонента.

<template>
    <div>
    {{ count }} {{ object.foo }}
    </div>
</template>

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

  1. "реквизит"Первый параметр принимает реактивную опору, которая указывает на внешние опоры. Если вы не определите параметр props, первый параметр в настройке будет неопределенным. props ничем не отличается от vue2.x и по-прежнему следует предыдущим принципам;
  • Не изменяйте реквизиты в подкомпонентах, если вы попытаетесь, вас предупредят или даже выдадут ошибку.
  • Не структурируйте реквизит. Структурные реквизиты перестают отвечать на запросы.

2."контекст"Второй параметр предоставляет объект контекста, который выборочно предоставляет некоторые свойства исходного 2.x this .

<script setup="props, context" lang="ts">
 context.attrs
 context.slots
 context.emit 
<script>

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

<script setup="props, { emit }" lang="ts">
 
<script>

Компонент Авторегистрация

Импорт компонента или директивы непосредственно импортируют, без дополнительной декларации

import { MyButton } from "@/components"
import { directive as clickOutside } from 'v-click-outside'

Как и прежде, шаблон также поддерживает использование kabab-case для создания компонентов, таких как

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

<template>
    <HelloWorld />
</template>

<script setup>
import HelloWorld from "./components/HelloWorld.vue"; //此处使用 Vetur 插件会报红
</script>

Если вам нужно определить атрибуты, похожие на имя, вы можете добавить тег сценария уровня и реализовать его внутри.

Использование компонентов основного API

Определить свойства компонента

пройти черезdefinePropsУкажите текущий тип реквизита, чтобы получить объект реквизита контекста. Пример:

<script setup>
  import { defineProps } from 'vue'

  const props = defineProps({
    title: String,
  })
</script>
<!-- 或者 -->
<script setup lang="ts"> 
    import { ref,defineProps } from 'vue';
    
    type Props={ 
        msg:string 
    }
    defineProps<Props>(); 
</script>

определить излучение

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

<script setup>
  import { defineEmits } from 'vue'

  const emit = defineEmits(['change', 'delete'])
</script>

Взаимодействие компонентов родитель-потомок

definePropsИспользуется для получения реквизита от родительского компонента;defineEmitsИспользуется для объявления инициированного события.

//父组件
<template>
  <my-son foo="🚀🚀🚀🚀🚀🚀" @childClick="childClick" />
</template>

<script lang="ts" setup>
import MySon from "./MySon.vue";

let childClick = (e: any):void => {
  console.log('from son:',e);  //🚀🚀🚀🚀🚀🚀
};
</script>


//子组件
<template>
  <span @click="sonToFather">信息:{{ props.foo }}</span>
</template>

<script lang="ts" setup>
import { defineEmits, defineProps} from "vue";

const emit = defineEmits(["childClick"]);     // 声明触发事件 childClick
const props = defineProps({ foo: String });   // 获取props

const sonToFather = () =>{
    emit('childClick' , props.foo)
}
</script>

Дочерний компонент получает данные от родительского компонента через defineProps, а дочерний компонент отправляет информацию родительскому компоненту через defineEmits для определения событий.

Расширенные определения типов реквизита:

const props = defineProps<{
  foo: string
  bar?: number
}>()

const emit = defineEmit<(e: 'update' | 'delete', id: number) => void>()

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

Определить переменные ответа, функции, прослушиватели, вычисляемые свойства

<script setup lang="ts"> 
import { ref,computed,watchEffect } from 'vue';

const count = ref(0); //不用 return ,直接在 templete 中使用

const addCount=()=>{ //定义函数,使用同上 
    count.value++; 
} 

//定义计算属性,使用同上
const howCount=computed(()=>"现在count值为:"+count.value);

//定义监听,使用同上 //...some code else 
watchEffect(()=>console.log(count.value)); 
</script>

watchEffect

Для операций с побочными эффектами автоматически собираются зависимости.

Отличие от часов

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

reactive

В настоящее время имя будет назначено только при первом создании.Если вы хотите изменить значение имени в середине, вам нужно использовать реактивный API в составе.

<script setup lang="ts">
import { reactive, onUnmounted } from 'vue'

const state = reactive({
    counter: 0
})
// 定时器 每秒都会更新数据
const timer = setInterval(() => {
    state.counter++
}, 1000);

onUnmounted(() => {
    clearInterval(timer);
})
</script>
<template>
    <div>{{state.counter}}</div>
</template>

Использование ref также может привести к ожидаемому «счетчику», и в шаблоне, который vue обработал, мы можем использовать счетчик напрямую, не записывая counter.value.

Отношения между ref и реактивным:

ref представляет собой структуру {value:'xxxx'}, значение представляет собой реактивный объект

ref предоставляет переменные шаблонам

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

export const count = ref(0)

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

<script setup lang="ts">
import { ref } from 'vue'

const counter = ref(0);//不用 return ,直接在 templete 中使用

const timer = setInterval(() => {
    counter.value++
}, 1000)

onUnmounted(() => {
    clearInterval(timer);
})
</script>
<template>
    <div>{{counter}}</div>
</template>

методы жизненного цикла

потому что setupвокругbeforeCreate а также createdКрючки жизненного цикла выполняются, поэтому нет необходимости определять их явно. Другими словами, любой код, написанный в этих хуках, должен быть написан непосредственно вsetupнаписано в функции.

Доступ к хукам жизненного цикла компонента можно получить, поставив перед хуком жизненного цикла префикс «on».Официальный сайт: крючки жизненного цикла

В таблице ниже указано, какsetup ()Внутренний вызов хуков жизненного цикла:

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
<script setup lang="ts"> 
import { onMounted } from 'vue';

onMounted(() => { console.log('mounted!'); });

</script>

Получить слоты и атрибуты

Примечание. API useContext устарел в пользу более детализированного API.

в состоянии пройтиuseContextПолучить слоты и атрибуты из контекста. Однако после того, как предложение было официально принято, эта грамматика была упразднена и разделена наuseAttrsа такжеuseSlots.

  1. useAttrs: Зная название, это используется для получения данных attrs, но это отличается от vue2, который содержитclass,属性,方法.
<template>
    <component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>
   const attrs = useAttrs();
<script>
  1. useSlots: Как следует из названия, получить данные слота.

Пример использования:

// 旧
<script setup>
  import { useContext } from 'vue'

  const { slots, attrs } = useContext()
</script>

// 新
<script setup>
  import { useAttrs, useSlots } from 'vue'

  const attrs = useAttrs()
  const slots = useSlots()
</script>

Другие API-интерфейсы хуков

  1. useCSSModule: CSS Modules — это система модульности и композиции CSS. vue-loader интегрирует модули CSS, которые можно использовать для имитации CSS с ограниченной областью действия. Позволяет в одном файле компонентsetupДоступ к модулям CSS в формате . Я меньше использую этот API, но я буду вводить его больше.
  2. useCssVars: Этот API временно имеет меньше данных. представлятьv-bind in stylesупомянул.
  3. useTransitionState: Этот API временно имеет меньше данных.
  4. useSSRContext: Этот API временно имеет меньше данных.

defineExpose API

При традиционном способе написания мы можем получить доступ к содержимому дочернего компонента через экземпляр ref в родительском компоненте, но в настройке скрипта этот метод использовать нельзя.Настройка эквивалентна замыканию, за исключением внутреннегоtemplateШаблон, никто не может получить доступ к внутренним данным и методам.

Если вам нужно предоставить доступ к данным и методам установки извне, вам нужно использовать API defineExpose. Пример:

const a = 1
const b = ref(2)
defineExpose({ a, b, })

Примечание: в настоящее время найденоdefineExposeВыставленные свойства и методыunknownВведите, если есть способ исправить тип, добро пожаловать, чтобы добавить его в область комментариев.

//父组件

<template>
  <Daughter ref="daughter" />
</template>

<script lang="ts" setup>
import { ref } from "vue";
import Daughter from "./Daughter.vue";

const daughter = ref(null)
console.log('🚀🚀🚀🚀~daughter',daughter)
</script>


//子组件

<template>
  <div>妾身{{ msg }}</div>
</template>

<script lang="ts" setup>
import { ref ,defineExpose} from "vue";
const msg = ref('貂蝉')
defineExpose({
    msg
})
</script>

Свойства и методы не нужно возвращать, используйте их напрямую!

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

<template>
  <div>
   	<p>My name is {{name}}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const name = ref('Sam')
</script>

Поддержка асинхронного ожидания асинхронного

Обратите внимание, что в исходном коде vue3 после выполнения установки значение внутри функции getCurrentInstance освободит ссылку на currentInstance, а оператор await вызовет асинхронное выполнение последующего кода. Так что последний getCurrentInstance() в приведенном выше примере вернет null, рекомендуется использовать переменную для сохранения ссылки, возвращаемой первым getCurrentInstance().

<script setup>
  const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>

<script setup>верхний уровень может использоваться вawait. Полученный код будет скомпилирован вasync setup():

<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>

Кроме того, выражения await автоматически компилируются вawaitПри этом сохраняется формат текущего контекста экземпляра компонента.

Уведомление
async setup()должно быть сSuspenseиспользуется в сочетании,SuspenseЭта функция все еще находится на экспериментальной стадии. Мы планируем разработать и предоставить документацию в будущем выпуске - если вы заинтересованы сейчас, вы можете обратиться кtestsПосмотри, как это работает.

Определить другую конфигурацию компонента

Отсутствие элементов конфигурации, иногда нам нужно изменить параметры компонента, вsetupВ настоящее время мы не можем этого сделать. мы должны上方представить еще одинscript, напишите соответствующее вышеexportВот и все, вам нужно открыть один скрипт.

<script setup>может и обычный<script>использовать вместе. обычный <script>Его можно использовать в таких ситуациях:

  • невозможно<script setup>Заявленные параметры, например.inheritAttrsИли настраиваемые параметры, включенные плагинами.
  • Объявите именованный экспорт.
  • Запускайте побочные эффекты или создавайте объекты, которые нужно выполнить только один раз.

Используйте экспорт по умолчанию вне настройки скрипта, его содержимое будет обработано и помещено в исходное поле объявления компонента.

<script>
// 普通 `<script>`, 在模块范围下执行(只执行一次)
runSideEffectOnce()

// 声明额外的选项
  export default {
    name: "MyComponent",
    inheritAttrs: false,
    customOptions: {}
  }
</script>
<script setup>
    import HelloWorld from '../components/HelloWorld.vue'
    // 在 setup() 作用域中执行 (对每个实例皆如此)
    // your code
</script>
<template>
  <div>
    <HelloWorld msg="Vue3 + TypeScript + Vite"/>
  </div>
</template>

Примечание. Vue 3 SFC обычно автоматически определяет имя компонента из имени файла компонента. В большинстве случаев явное объявление имени не требуется. Единственный случай, когда вам нужно<keep-alive>Это имя необходимо вам при включении, исключении или прямой проверке параметров компонентов.

Недостатки TS и ESLint

  1. а также@typescript-eslint/no-unused-varsПравило несовместимо, значение этого правила определено и не используется. На самом деле это правило малоэффективно, и его можно отключить.

  2. Несовместимо с объявлениями импортированных типов, когда вы импортируете типы путем деструктурирования,setup sugarПроизойдет автоматический экспорт. В это время вы получите сообщение об ошибке от TS: Это тип, но он используется как значение. Обходной путь: введите экспорт, используяexport defaultИспользуется при экспорте или импортеimport * as xxдля импорта вы также можете использоватьimport type { test } from "./test";решить.

Реализация синтаксического сахара

код вью-файла

<template>
  <div>{{ msg }}</div>
</template>
<script setup>
  const msg = 'Hello!'
</script>

Скомпилированный js-код:

export default {
  setup() {
    const msg = 'Hello!'

    return function render() {
      // has access to everything inside setup() scope
      // 在函数 setup 作用域,函数 render 能访问 setup 的一切,
      return h('div', msg)
    }
  }
}

Обратите внимание, что даже обычные переменные могут быть скомпилированы в шаблон как шаблон, что некоторые люди считают неуместным и недостаточным разделением.

Плагин поддержки vscode

volarЭто плагин vscode для улучшения написания vue.Используйте плагин volar, чтобы получить наилучшую поддержку синтаксиса настройки скрипта.

а такжеveturтакой же,volarявляется цельюvueизvscodeплагин, но сveturразница в том,volarОбеспечивает более мощный, люди обращаются к нему卧槽.

Способ установки очень прост, прямо вvscodeПоиск на торговой площадке плагиновvolar, а затем нажмите «Установить».

vscodeПри использовании сначала отключите егоVetur, затем скачайте и используйтеVolar

привычка использования

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

  • Самостоятельно закодируйте раздел и попробуйте разделить метод (написать комментарий), раздел выглядит следующим образом:

    1. родственное введение
    2. Реактивные данные, свойства, определения эмиссии
    3. Жизненный цикл и запись часов
    4. определение метода
    5. Метод и свойства воздействия
  • Извлечение компонента: разделите страницу на две папки, одну дляviews, один дляcomponents. Папки представлений и компонентов имеют свои собственные файлы. Папка представлений — это запись страницы, которая отвечает за данные, а компоненты — это извлечение некоторых компонентов на странице. Если это общедоступный компонент, извлеките его в другое место в папке компонентов.

  • Извлечение хука: логика извлекается настолько, насколько это возможно, и повторно использовать ее не нужно.

напиши в конце

Писать не легко, надеюсь получить от вас "лайк". Если статья вам полезна, вы можете выбрать «Подписаться + Избранное». Если в статье есть ошибки или предложения, прошу прокомментировать и исправить, спасибо. ❤️