Позвольте вам быстро освоить vue 3 за 30 минут

Vue.js
Позвольте вам быстро освоить vue 3 за 30 минут

После долгой итерации,VueНаконец, 18 сентября 2020 г. была выпущена версия 3.0 с потрясающими изменениями с использованиемTypescriptподвергся масштабному рефакторингу, в результате чегоComposition API RFCверсия вродеReact Hookнаписать то же самоеVue, вы можете настроить свой собственныйhooks, сделать пользователей более гибкими, а затем обобщитьvue 3.0некоторые новые функции.

  1. setup()
  2. ref()
  3. reactive(),shallowReactive()
  4. isRef()
  5. toRefs()
  6. readonly(),isReadonly(),shallowReadonly()
  7. computed()
  8. watch()
  9. LifeCycle Hooks(новый жизненный цикл)
  10. Template refs
  11. globalProperties
  12. Suspense
  13. Provide/Inject

Сравнение Vue2 и Vue3

  • правильноTypeScriptПоддержка недружественная (все свойства размещены вthisНа объект сложно пропихнуть тип данных компонента)
  • МногоAPIПрикреплено кVueНа прототипе объекта сложно добитьсяTreeShaking.
  • Уровень архитектуры против кроссплатформенностиdomОказание поддержки разработки не является дружественным
  • CompositionAPI. отReactHookвдохновленный
  • более удобная поддержкаjsx
  • Вью 3TemplateПоддержка нескольких корневых тегов, не поддерживается в 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и вернуть его

  1. Как всегда, вhtmlнаписать вrefНазвание
  2. существуетsteupопределитьref
  3. steupвернуться вrefэкземпляр
  4. 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) => {}

Глобальные свойства, к которым можно получить доступ в любом экземпляре компонента в приложении, свойства компонента будут иметь приоритет. это можно заменитьVue2.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

библиотека компонентов пользовательского интерфейса