Предложения по обучению Vue3.0
Для студентов, изучающих vue2.0
Новые функции Vue3.0
- Состав Api (самое ядро)
- изменение v-модели
- Изменения в использовании ключевых узлов v-for
- v-if и v-for имеют более высокий приоритет для одного и того же элемента
- ref внутри v-for больше не регистрирует ссылочные массивы
- Функциональные компоненты могут быть созданы только с помощью обычных функций.
- Асинхронные компоненты должны использовать
defineAsyncComponent
Создать метод - Все слоты проходят
$slots
- существует
destroyed
Параметры жизненного цикла были переименованыunmounted
- существует
beforeDestroy
Параметры жизненного цикла были переименованыbeforeUnmount
- ...
Преимущества и недостатки Vue3.0
преимущество:
- Предоставьте доступ к большинству внутренних API-интерфейсов Vue, чтобы у Vue была возможность разрабатывать крупномасштабные проекты, такие как компиляция и компиляция API-интерфейсов и т. д.
- встряхивание дерева веб-пакета (встряхивание дерева - это способ DCE, который может игнорировать неиспользуемый код при сборке.) Дружественная поддержка
- Использование Proxy для адаптивного определения переменных повышает производительность в 1,2–2 раза.
- ssr в 2-3 раза быстрее
- Плагин композиции-api можно использовать отдельно в Vue2.0 или для непосредственной разработки плагинов.
- Более дружественная поддержка машинописного текста
- Глядя в будущее: недавно инновационный сервер разработки vite от Yuxi для вас (высокопроизводительный сервер разработки, который отказывается от веб-пакета и использует платформу Koa в нижней части), синтаксис Vue3.0 используется напрямую
недостаток:
- Vue3 больше не будет поддерживать IE11, Vue по-прежнему поддерживает IE11 в версии 2.X, если вы хотите использовать новые функции, такие как Vue 3, вы можете дождаться версии Vue 2.7. В этом RFC объявлено, что он будет обратно совместим с версией 2.7 и перенесет некоторые новые функции 3.x, чтобы обеспечить одинаковый опыт разработки между двумя версиями.
- Для разработчиков, привыкших к режиму разработки Vue2.0, это увеличивает умственную нагрузку и имеет опыт в организации кода разработчика.
В то же время это также возможность улучшить возможности.Мне особенно нравится первоначальный дизайнерский замысел автора Vue: позволить разработчикам расти вместе с фреймворком.
Испытайте четыре позы Vue3.0
Теперь есть четыре позы, чтобы испытать Vue3.0портал
-
Через CDN:
<script src="https://unpkg.com/vue@next"></script>
-
пройти черезCodepenбраузерная площадка
-
строительные лесаVite:
npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3
Новый инструмент, разработанный Youda, призван в будущем заменить веб-пакет.Первоначальный вариант заключается в использовании импорта, который браузеры уже поддерживают ES6; при обнаружении импорта будет отправлен http-запрос для загрузки соответствующего файла, а vite перехватит эти запросы. и выполните предварительную компиляцию. Посетите длительные мероприятия по пакетированию веб-пакетов, чтобы улучшить процесс разработки.
-
строительные лесаvue-cli
npm install -g @vue/cli # OR yarn global add @vue/cli vue create hello-vue3 # select vue 3 preset
Глобальный API
Новый глобальный API:createApp
передачаcreateApp
Возвращает экземпляр приложения, что является новой концепцией Vue3.0:
Открытьsrc/main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
Экземпляр приложения предоставляет подмножество текущего глобального API. Практическое правило заключается в том, что любой API, который глобально меняет поведение Vue, теперь будет перемещен в приложение в экземпляре приложения. Вот таблица текущих глобальных API и их соответствующие API экземпляра:
2.x Глобальный API | API экземпляра 3.x (app ) |
---|---|
Vue.config | app.config |
Vue.config.productionTip | removedудаленный |
Vue.config.ignoredElements | app.config.isCustomElement |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
изучение API композиции
setup
Функция настройки — это новая опция компонента. В качестве точки входа для использования Composition API внутри компонента.
Создайте экземпляр компонента, затем инициализируйте свойства, затем вызовитеsetup
функция. это будет вbeforeCreate
Вызывается до хука.
setup возвращает объект. то все свойства объекта (это ответные данные) можно использовать непосредственно в шаблоне. Эквивалентно объекту, возвращаемому функцией данных в vue2.0.
App.vue
<script>
export default {
setup () {
return {}
}
}
</script>
отзывчивые данные
- ref: вы можете передать любой тип значения и вернуть реактивный и изменяемый объект ref. Объекты ref имеют одно свойство, указывающее на внутреннее значение.
.value
, вы должны использовать его атрибут value при изменении значения - реактивный: принимает простой объект и возвращает реактивный прокси для этого простого объекта. Эквивалент 2.x
Vue.obserable()
Вкратце: реактивный отвечает за сложные структуры данных, а ref может оборачивать базовые структуры данных в реактивный.
reactive
<template>
<div>
<h2>{{state.count}}</h2>
<button @click="add">计算</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup(){
// 响应式变量声明 reactive负责复杂数据结构,
const state = reactive({
count: 1
});
function add() {
state.count++;
}
return { state, add};
}
};
</script>
ref
<template>
<div>
<h2>{{state.count}}</h2>
<h3>{{num}}</h3>
<button @click="add">计算</button>
</div>
</template>
<script>
import { reactive, ref } from "vue";
export default {
setup(){
const state = reactive({
count: 1
});
const num = ref(0);
function add() {
state.count++;
num.value+=2
}
return { state, add, num };
}
};
</script>
Число, упакованное по ссылке, можно использовать непосредственно в шаблоне, но оно работает при изменении в js..value
Атрибуты.
toRefs
Преобразование реактивного объекта в обычный объект, где каждое свойство результирующего объекта указывает на соответствующее свойство исходного объекта.
toRefs полезен при возврате реактивных объектов из составных функций, так что потребляющие компоненты могут разлагать/рассеивать возвращаемый объект без потери реактивности:
useFeatureX.js
import {reactive} from 'vue';
export function userFeatureX(){
const state = reactive({
foo: 1,
bar: 2
})
// 逻辑运行状态
// 返回时转换为ref
return state;
}
App.vue
import {toRefs} from 'vue'
export default {
setup(){
const state = useFeatureX();
return {
...toRefs(state)
}
}
}
computed
Передайте функцию получения, которая возвращает объект ref, который по умолчанию нельзя изменить вручную.
import { reactive, ref, computed } from "vue";
export default {
setup() {
// 1.响应式变量声明 reactive负责复杂数据结构,
const state = reactive({
count: 1
});
// 2.ref可以把基本的数据结构包装成响应式
const num = ref(0);
// 3.创建只读的计算属性
const computedEven1 = computed(() => state.count % 2);
// 4.创建可读可写的计算属性
const computedEven2 = computed({
get:()=>{
return state.count % 2;
},
set: newVal=>{
state.count = newVal;
}
})
// 事件的声明
function add() {
state.count++;
num.value += 2;
}
function handleClick() {
computedEven2.value = 10;
}
return { state, add, num, computedEven1,computedEven2,handleClick };
}
};
watchEffect
Немедленно выполняет переданную функцию, реактивно отслеживает ее зависимости и повторно запускает функцию при изменении ее зависимостей.
const num = ref(0)
watchEffect(() => console.log(count.value))
// -> 打印出 0
setTimeout(() => {
count.value++
// -> 打印出 1
}, 100)
-
Хватит слушать
Неявная остановка
когда
watchEffect
в компонентеsetup()
Когда вызывается функция или хук жизненного цикла, слушатель связывается с жизненным циклом компонента и автоматически останавливается, когда компонент размонтирован.показать остановку
В некоторых случаях значение возврата вызова также может отображаться, чтобы прекратить прослушивание.
const stop = watchEffect(()=>{ /*...*/ }) //停止侦听 stop()
-
явные побочные эффекты
Иногда функция побочного эффекта выполняет некоторые асинхронные побочные эффекты, и эти ответы необходимо очищать, когда они становятся недействительными (т. е. состояние изменилось до завершения). Вы можете принять функцию в функции, которая прослушивает побочные эффекты
onInvalidate
Функция в качестве параметра используется для регистрации обратного вызова в случае сбоя очистки. Когда происходит следующее, этоОбратный вызов недействительностибудет запущено:- Когда побочный эффект вот-вот повторится
- слушатель останавливается (если
setup()
или используется в функции хука жизненного циклаwatchEffect
, то при удалении компонента)
Пример официального сайта:
watchEffect((onInvalidate) => { const token = performAsyncOperation(id.value) onInvalidate(() => { // id 改变时 或 停止侦听时 // 取消之前的异步操作 token.cancel() }) })
Кейс: Реализуйте эффект «анти-тряски» при вводе данных пользователем.
<template>
<div>
<input type="text"
v-model="keyword">
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const keyword = ref('')
const asyncPrint = val => {
return setTimeout(() => {
console.log('user input: ', val)
}, 1000)
}
watchEffect(
onInvalidate => {
//用户输入的时间间隔小于1秒,都会立刻清除掉定时,不输入结果。正因为这个,实现了用户防抖的功能,只在用户输入时间间隔大于1秒,才做打印
const timer = asyncPrint(keyword.value)
onInvalidate(() => clearTimeout(timer))
console.log('keyword change: ', keyword.value)
},
// flush: 'pre' watch() 和 watchEffect() 在 DOM 挂载或更新之前运行副作用,所以当侦听器运行时,模板引用还未被更新。
//flush: 'post' 选项来定义,这将在 DOM 更新后运行副作用,确保模板引用与 DOM 保持同步,并引用正确的元素。
{
flush: 'post' // 默认'pre',同步'sync','pre'组件更新之前
}
)
return {
keyword
}
}
}
// 实现对用户输入“防抖”效果
</script>
watch
watch
API полностью эквивалентен 2.xthis.$watch
(так же какwatch
соответствующие варианты).watch
Необходимо прослушивать определенный источник данных и выполнять побочные эффекты в функции обратного вызова. По умолчанию используется ленивый, что означает, что обратный вызов выполняется только при изменении прослушиваемого источника.
Первый параметр, полученный функцией watch(), называется «источник данных», который может быть:
- Функция получения, которая возвращает произвольное значение
- Объект-оболочка (может быть ссылкой или реактивным обернутым объектом)
- Массив, содержащий два вышеуказанных источника данных
Второй параметр — это функция обратного вызова. Функция обратного вызова будет запущена только при изменении источника данных:
-
Слушайте один источник данных
const state = reactive({count: 1}); //侦听一个reactive定义的数据,修改count值时会触发 watch的回调 watch(()=>state.count,(newCount,oldCount)=>{ console.log('newCount:',newCount); console.log('oldCount:',oldCount); }) //侦听一个ref const num = ref(0); watch(num,(newNum,oldNum)=>{ console.log('newNum:',newNum); console.log('oldNum:',oldNum); })
-
Прослушивание нескольких источников данных (массивов)
const state = reactive({count: 1}); const num = ref(0); // 监听一个数组 watch([()=>state.count,num],([newCount,newNum],[oldCount,oldNum])=>{ console.log('new:',newCount,newNum); console.log('old:',oldCount,oldNum); })
-
Слушайте сложные вложенные объекты
В нашей реальной разработке сложные данные можно увидеть повсюду, например:
const state = reactive({ person: { name: '张三', fav: ['帅哥','美女','音乐'] }, }); watch( () => state.person, (newType, oldType) => { console.log("新值:", newType, "老值:", oldType); }, { deep: true }, // 立即监听 );
Если третий параметр не используется
deep:true
, не может отслеживать изменения данных. Ранее мы упоминали,часы ленивы по умолчанию, тогда при каких обстоятельствах не лениво и callback-функцию можно выполнить сразу? На самом деле использование тоже очень простое, задается в третьем параметреimmediate: true
Только чтоПри этом watch и watchEffect ведут себя одинаково в плане прекращения прослушивания, сброса побочных эффектов (и соответственно onInvalidate передается третьим параметром callback'а) и т.д.
<template>
<div>
<input type="text"
v-model="keyword">
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const keyword = ref('')
const asyncPrint = val => {
return setTimeout(() => {
console.log('user input: ', val)
})
}
watch(
keyword,
(newVal, oldVal, onCleanUp) => {
const timer = asyncPrint(keyword)
onCleanUp(() => clearTimeout(timer))
},
{
lazy: true // 默认false,即初始监听回调函数执行了
}
)
return {
keyword
}
}
}
</script>
крючки жизненного цикла
Компонуемый API, соответствующий жизненному циклу версии 2.x
Новый тестовый компонент/components/Test.vue
<template>
<div id="test">
<h3>{{a}}</h3>
<button @click="handleClick">更改</button>
</div>
</template>
<script>
import {
ref,
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
export default {
// 初始化数据阶段的生命周期,介于beforeCreate和created之间
setup() {
const a = ref(0);
console.log("👌");
function handleClick() {
a.value += 1;
}
onBeforeMount(() => {
console.log("组件挂载之前");
});
onMounted(() => {
console.log("DOM挂载完成");
});
onBeforeUpdate(() => {
console.log("DOM更新之前", document.getElementById("test").innerHTML);
});
onUpdated(() => {
console.log("DOM更新完成", document.getElementById("test").innerHTML);
});
onBeforeUnmount(() => {
console.log("实例卸载之前");
});
onUnmounted(() => {
console.log("实例卸载之后");
});
return { a, handleClick };
}
};
</script>
Согласно официальной поговорке, вам не нужно сразу во всем разбираться, но по мере того, как вы продолжаете изучать и использовать его, его эталонное значение будет становиться все выше и выше.
внедрение зависимости
provide
а такжеinject
Обеспечивает внедрение зависимостей, аналогично 2.x.provide/inject
. Оба могут использоваться только в текущем компоненте.setup()
вызывать
App.vue
предоставить источник данных
<template>
<div>
<Article></Article>
</div>
</template>
<script>
import {
ref,
provide
} from "vue";
import Article from "./components/Article";
export default {
setup() {
const articleList = ref([
{ id: 1, title: "Vue3.0学习", author: "小马哥" },
{ id: 2, title: "componsition api", author: "尤大大" },
{ id: 3, title: "Vue-router最新", author: "vue官方" }
]);
/*
provide 函数允许你通过两个参数定义 property:
property 的 name (<String> 类型)
property 的 value
*/
provide("list",articleList);
return {
articleList
};
},
components: {
Article
}
};
</script>
Article.vue
вводить данные
<template>
<div>
{{articleList[0].title}}
</div>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
const articleList = inject('list',[]);
return {articleList};
},
};
</script>
ссылки на шаблоны
При использовании API композицииreactive refs
а такжеtemplate refs
Концепция была унифицирована. Чтобы получить ссылку на экземпляр элемента или компонента в шаблоне, вы можете напрямуюsetup()
объявить ссылку и вернуть ее
<template>
<div>
<div ref='wrap'>hello vue3.0</div>
<Article ref='articleComp'></Article>
</div>
</template>
<script>
import {
ref,
onMounted,
provide
} from "vue";
import Article from "./components/Article";
export default {
setup() {
const isShow = ref(true);
const wrap = ref(null);
const articleComp = ref(null);
const articleList = ref([
{ id: 1, title: "Vue3.0学习", author: "小马哥" },
{ id: 2, title: "componsition api", author: "尤大大" },
{ id: 3, title: "Vue-router最新", author: "vue官方" }
]);
/*
provide 函数允许你通过两个参数定义 property:
property 的 name (<String> 类型)
property 的 value
*/
provide("list", articleList);
onMounted(() => {
console.log(wrap.value); //获取div元素
console.log(articleComp.value); //获取的article组件实例对象
});
return {
articleList,
wrap,
articleComp
};
},
components: {
Article
}
};
</script>
<style scoped>
</style>
Изображение эффекта:
компонент связи
- props
- $emit
- expose /ref
- attrs
- v-model
- provide/inject
- vuex
- mitt
props
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
setup(){
// 创建一个响应式数据
const msg1 = ref("这是传级子组件的信息1")
const msg2 = reactive(["这是传级子组件的信息2"])
return {
msg1
msg2
}
}
}
</script>
// Child.vue 接收
<script>
export default {
props: ["msg1", "msg2"],// 如果这行不写,下面就接收不到
setup(props) {
console.log(props) // { msg1:"这是传给子组件的信息1", msg2:"这是传给子组件的信息2" }
},
}
</script>
$emit
// Child.vue 派发
<template>
// 写法一
<button @click="$emit('myClick',123)">按钮</buttom>
</template>
<script>
export default {
emits:['myClick']
//emits:{
//myClick:null
//}
}
</script>
// Parent.vue 响应
<template>
<child @myClick="onMyClick"></child>
</template>
<script setup>
import child from "./child.vue"
const onMyClick = (msg) => {
console.log(msg) // 这是父组件收到的信息 123
}
</script>
Большие перемены
Teleport
Телепорт похож на «любую дверь» в Дораэмоне, функция любой двери — мгновенно телепортировать людей в другое место. С этим пониманием давайте посмотрим, почему нам нужно использовать функции Teleport.Давайте рассмотрим небольшой пример: В подкомпонентахHeader
используется вDialog
Компоненты, мы часто используем фактическое развитие в аналогичных обстоятельствахDialog
,В настоящее времяDialog
Он визуализируется в виде слоя подкомпонентов для управления позиционированием вложенных компонентов.z-index
и стили стали трудными.Dialog
С точки зрения восприятия пользователем, это должен быть самостоятельный компонент, а DOM, смонтированный компонентом верхнего уровня Vue, должен быть полностью отделен от структуры dom, при этом также может использоваться состояние в компоненте Vue (data
илиprops
) стоимость. Проще говоря,то есть хотите продолжать использовать внутри компонентаDialog
, и надеемся, что визуализированная структура DOM не вложена в DOM компонента.. На данный момент нам нужен Телепорт для игры, мы можем использовать<Teleport>
пакетDialog
, в этот момент устанавливается портал, который можетDialog
Визуализированный контент доставляется в любое указанное место. Далее, давайте возьмем небольшой пример, чтобы увидеть, как используется Телепорт.
Мы надеемся, что компоненты dom и верхнего уровня, визуализируемые Dialog, являются братьями и сестрами, т.е.index.html
Файл определяет элемент для монтажа:
<body>
<div id="app"></div>
<div id="dialog"></div>
</body>
определитьDialog
компонентыDialog.vue
, обрати внимание наto
свойства такие же, как и вышеid
Селекторы те же:
<template>
<teleport to="#dialog">
<!-- 即希望继续在组件内部使用Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中。 此时就需要 Teleport 上场,
我们可以用<Teleport>包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方 -->
<div class="dialog">
<div class="dialog_wrapper">
<div class="dialog_header">
<h3>我是弹框 {{ count }}</h3>
</div>
</div>
</div>
</teleport>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,
})
return {
...toRefs(state),
}
},
}
</script>
<style lang="less" scoped></style>
Suspense
экспериментальный
Приостановка — это экспериментальная новая функция, и ее API может быть изменен в любое время. Настоящим объявляется, чтобы сообщество могло оставить отзыв о текущей реализации.
Не используйте в производственной среде
Должен<suspense>
Компоненты предоставляют еще одно решение, которое позволяет поднимать ожидающие процессы для обработки в дереве компонентов, а не в одном компоненте.
Принесите дваslot
соответственноdefault、fallback
. Как следует из названия, когда загружаемый компонент не соответствует состоянию,Suspense
вернется кfallback
Состояние не отображается, пока загруженный компонент не удовлетворяет условию.
Suspense.vue
<template>
<button @click="loadAsyncComponent">点击加载异步组件</button>
<Suspense v-if="loadAsync">
<template #default>
<!-- 加载对应的组件 -->
<MAsynComp></MAsynComp>
</template>
<template #fallback>
<div class="loading"></div>
</template>
</Suspense>
</template>
<script>
import { ref, defineAsyncComponent } from 'vue'
export default {
components: {
MAsynComp: defineAsyncComponent(() => import('./AsynComp.vue')),
},
setup() {
const loadAsync = ref(false)
const loadAsyncComponent = () => {
loadAsync.value = true
}
return {
loadAsync,
loadAsyncComponent,
}
},
}
</script>
<style lang="less" scoped>
button {
padding: 12px 12px;
background-color: #1890ff;
outline: none;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
.loading {
position: absolute;
width: 36px;
height: 36px;
top: 50%;
left: 50%;
margin: -18px 0 0 -18px;
background-image: url('../assets/loading.png');
background-size: 100%;
animation: rotate 1.4s linear infinite;
}
@keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
</style>
AsynComp.vue
<template>
<h1>this is async component</h1>
</template>
<script>
import { setup } from 'vue'
export default {
name: 'AsyncComponent',
async setup() {
const sleep = (time) => {
return new Promise((reslove, reject) => {
setTimeout(() => {
reslove()
}, time)
})
}
await sleep(3000) //模拟数据请求
},
}
</script>
Fragments
В компонентах Vue3.0 может быть разрешено несколько корневых компонентов, что позволяет избежать многократного ненужного рендеринга div.
<template>
<div>头部</div>
<div>内容</div>
</template>
Преимущества этого:
- гораздо меньше бессмысленных div
- Он может обеспечить горизонтальную рекурсию, что очень полезно для реализации древовидных компонентов.
emits
- излучает может быть массивом или объектом
- Инициировать пользовательские события
- Позволяет нам настраивать и проверять события, если emits является объектом. Функция проверки должна возвращать логическое значение, чтобы указать, является ли параметр события допустимым.
Emits.vue
<template>
<div>
<button @click="$emit('submit',{username:'xiaomage',password:'123'})">自定义事件</button>
</div>
</template>
<script>
export default {
// emits:['submit'],//可以是数组
emits: {
submit: payload => {
if(payload.username && payload.password){
return true;
}else{
console.warn('无效的payload,请检查submit事件');
return false
}
}
},
setup() {
return {};
}
};
</script>
<style scoped>
</style>
App.vue
<Emits @submit="submitHandle"></Emits>
<script>
import Emits from "./components/Emits";
export default{
components:{
Emits
},
setup(){
function submitHandle(payload) {
console.warn("自定义事件触发",payload);
}
return {
}
}
}
</script>
Показать результаты:
Global Vue API изменен на экземпляр приложения
Об этом было сказано выше, поэтому я не буду вдаваться в подробности.
API может выполнять оптимизацию Tree Shakeable
В vue2.0 есть много глобальных API, которые напрямую навешиваются на конструктор Vue как статические функции.Вы должны вручную манипулировать DOM, и вы столкнетесь со следующими паттернами. Если мы не использовали их в коде, мы сформируем то, что мы называем «мертвым кодом», а «мертвый код», вызванный таким глобальным API, не может использовать вебапки.tree-shaking
Сделайте «устранение мертвого кода».
import Vue from 'vue'
Vue.nextTick(()=>{
//一些和DOM相关的东西
})
Поэтому в vue3.0 были внесены соответствующие изменения, чтобы выделить их в независимые функции, чтобы древовидная оптимизация инструмента упаковки могла исключить эти «мертвые коды». Глобальные API теперь доступны только как именованные экспорты сборок модуля ES. Например, наш предыдущий фрагмент теперь должен выглядеть так
import {nextTick} from 'vue'
nextTick(()=>{
//一些和DOM相关的东西
})
Затронутый API
Эти глобальные API в Vue2.x затронуты этим изменением:
- Vue.nextTick
- Vue.observable (заменен на Vue.reactive)
- Vue.version
- Vue.compile (только при полной сборке)
- Vue.set (только совместимая версия)
- Vue.delete (только совместимая версия)
TreeShaking.vue
<template>
<div >
<hr />摇树优化,把没引入的不必要的代码进行优化
<div id='name'>小马哥</div>
<h3 ref='myMsg'>{{msg}}</h3>
<button @click="changeMsg('hai!')">改变</button>
</div>
</template>
<script>
import { ref, nextTick } from "vue";
export default {
setup() {
const msg = ref("hello!");
const myMsg = ref(null);
async function changeMsg(newV) {
msg.value = newV;
// console.log(myMsg.value.innerText); //直接获取DOM还是以前的
// nextTick返回了promise对象
await nextTick();
console.log(myMsg.value.innerText);
}
return {
msg,
myMsg,
changeMsg
};
}
};
</script>
Синтаксис именованного слота
В Vue2.x способ написания именованного слота:
<!-- 子组件中:-->
<slot name="title"></slot>
В родительском компоненте используйте:
<template slot="title">
<h1>歌曲:《孤勇者》</h1>
<template>
если мы хотимЧтобы привязать данные к слоту, вы можете использовать слоты с областью видимости., реализуется следующим образом:
// 子组件
<slot name="content" :data="data"></slot>
export default {
data(){
return{
data:["走过来人来人往","不喜欢也得欣赏","陪伴是最长情的告白"]
}
}
}
<!-- 父组件中使用 -->
<template slot="content" slot-scope="scoped">
<div v-for="item in scoped.data">{{item}}</div>
<template>
Именованные слоты и слоты с заданной областью используются отдельно в Vue2.x.slot
а такжеslot-scope
Для достижения в Vue3.0 будетslot
а такжеslot-scope
Согласие на использование суммируется. В Vue3.0v-slot
:
<!-- 父组件中使用 -->
<template v-slot:content="scoped">
<div v-for="item in scoped.data">{{item}}</div>
</template>
<!-- 也可以简写成: -->
<template #content="{data}">
<div v-for="item in data">{{item}}</div>
</template>
использование v-модели на компонентах
После выпуска Vue 2.0 разработчики используютv-model
Директива должна использоваться какvalue
опора Если разработчикам нужно использовать другие реквизиты для других целей, они должны использоватьv-bind.sync
. Кроме того, посколькуv-model
а такжеvalue
Причина этих жестко запрограммированных отношений между ними поднимает вопрос о том, как обрабатывать нативные и пользовательские элементы.
В Vue 2.2 мы представилиmodel
Параметры компонента, позволяющие использовать настройку компонента дляv-model
реквизит и мероприятия. Тем не менее, это по-прежнему позволяет использовать только один компонентmodel
.
В Vue 3 API двусторонней привязки данных был стандартизирован, что снижает потребность разработчиков в использованииv-model
Обфускация при директиве и использованииv-model
может быть более гибким при заказе.
2.x синтаксис
В 2.x использовать на компонентахv-model
эквивалентно связываниюvalue
опора иinput
мероприятие:
<ChildComponent v-model="pageTitle" />
<!-- 简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
Если вы хотите изменить имя свойства или события на другое, вам нужноChildComponent
компонент добавленmodel
Опции:
<!-- ParentComponent.vue -->
<ChildComponent v-model="pageTitle" />
// ChildComponent.vue
export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// 这将允许 `value` 属性用于其他用途
value: String,
// 使用 `title` 代替 `value` 作为 model 的 prop
title: {
type: String,
default: 'Default title'
}
}
}
Итак, в этом примереv-model
Аббревиатура выглядит следующим образом:
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
использоватьv-bind.sync
В некоторых случаях нам может потребоваться «двухсторонний привязку» (кроме предыдущегоv-model
связанная опора). Для этого мы рекомендуем использоватьupdate:myPropName
Выбросить событие. Например, для предыдущего примера сtitle
реквизитChildComponent
, мы можем сообщить о намерении присвоить новое значение родителю следующим образом:
this.$emit('update:title', newValue)
Родитель может прослушивать это событие и при необходимости обновлять свойство локальных данных. Например:
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Для удобства мы можем использовать.sync
модификатор для сокращения следующим образом:
<ChildComponent :title.sync="pageTitle" />
3.x синтаксис
В 3.x на пользовательских компонентахv-model
эквивалентно прохождениюmodelValue
опора и получение брошенногоupdate:modelValue
мероприятие:
<ChildComponent v-model="pageTitle" />
<!-- 简写: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
Изменения API функции рендеринга
-
h
Теперь импортируется глобально, а не передается в качестве параметра функции рендеринга. - Параметры функции рендеринга более согласованы между компонентами с отслеживанием состояния и функциональными компонентами.
- vnode теперь является плоской опорной структурой
render
Функция автоматически получитh
функция (которая является псевдонимом для createElement) в качестве параметра
//vue2.x
export default{
render(h){
return h('div')
}
}
//vue3 渲染
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
Например:
<template>
<div>
<RenderComp v-model='title'>
<template v-slot:default>
<!-- 默认插槽 -->
头部
</template>
<template v-slot:content>
<!-- 具名插槽 -->
内容
</template>
</RenderComp>
</div>
</template>
<script>
import {
ref,
h
} from "vue";
export default {
components: {
RenderComp: {
props: {
modelValue: {
type: String,
default: ''
},
},
setup(props,{attrs,slots,emit}) {
// 以前得通过$scopedSlots获取对应的插槽
console.log(slots.default()); //获取默认插槽
console.log(slots.content()); //获取名字为content的插槽
function changeTitle(newV) {
emit('update:modelValue','哈哈哈');
}
return () => h("div", {}, [h("div", {
onClick:changeTitle,
},[
`渲染函数api:${props.modelValue}`,
slots.default(),
slots.content()
])]);
}
}
},
setup(props) {
const title = ref("双向数据绑定");
return {
title
};
}
};
</script>
В то же время продемонстрировал$scopedSlots
свойство удалено, все слоты пройдены$slots
выставлен как функция
Создавайте функциональные компоненты, используя обычные функции
- В 3.x прирост производительности функциональных компонентов 2.x незначителен, поэтому мы рекомендуем использовать только stateful-компоненты.
- Функциональные компоненты могут использовать только прием
props
а такжеcontext
нормальное создание функции (т.е.:slots
,attrs
,emit
). -
Критические изменения:
functional
атрибут в компоненте одного файла (SFC)<template>
удаленный -
Критические изменения:
{ functional: true }
Добавлена возможность создавать компонент через функцию.удаленный
В vue2.0 функциональные компоненты имеют две основные цели:
- Улучшена оптимизация производительности, поскольку они инициализируются быстрее, чем компоненты с отслеживанием состояния.
- Можно вернуть несколько корневых узлов
Однако в Vue 3 производительность компонентов с отслеживанием состояния улучшилась до незначительного уровня. Кроме того, компоненты с отслеживанием состояния теперь включают возможность возвращать несколько корневых узлов.
Таким образом, единственные оставшиеся варианты использования функциональных компонентов — это простые компоненты, такие как те, которые создают динамические заголовки. В противном случае рекомендуется использовать компоненты с отслеживанием состояния как обычно.
Резюме: в не особых случаях официальный сайт по-прежнему рекомендует использовать компоненты с отслеживанием состояния.
Functional.vue
import { h } from 'vue'
const DynamicHeading = (props, context) => {
return h(`h${props.level}`, context.attrs, context.slots)
}
DynamicHeading.props = ['level']
export default DynamicHeading
<Functional level='3'>动态标题</Functional>
Вы можете пройти разные уровни, чтобы настроить разные названия серии h.
Асинхронные изменения компонентов
- новый
defineAsyncComponent
Вспомогательный метод, явно определяющий асинхронный компонент -
componnet
опция с именемloader
- Функция загрузчика не принимается сама по себе
resolve
а такжеreject
параметр, должен возвращать обещание
2.x
Раньше асинхронные компоненты создавались путем определения компонента как функции, возвращающей обещание, например:
const asyncPage = () => import('./NextPage.vue')
Для синтаксиса компонента более высокого порядка с параметрами:
const asyncPage = {
component: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
}
3.x
В vue3, поскольку функциональные компоненты определяются как чистые функции, необходимо обернуть определение асинхронного компонента в новыйdefineAsyncComponent
Помощники для явного определения компонентов
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// 不带选项的异步组件
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
// 带选项的异步组件
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
пользовательская директива
API переименован для лучшего согласования с жизненным циклом компонента.
- связать →beforeMount
- вставил →mounted
- beforeUpdate:новый! Это вызывается перед обновлением самого элемента, очень похоже на хуки жизненного цикла компонента.
- Обновление → удаление! Слишком много общего для обновления, так что это лишнее, пожалуйста, используйте
updated
- компонентОбновлено →updated
- **beforeUnmount **
新的
Подобно хукам жизненного цикла компонента, он будет вызываться перед выгрузкой элемента. - unbind -> unmounted
Например:
main.js
const app = createApp(App);
// 创建自定义指令
app.directive('highlight',{
// 指令 也拥有一组生命周期钩子
// 1.在绑定元素的父组件挂载之前调用
beforeMount(el,binding,vnode){
el.style.background = binding.value;
},
})
App.vue
<p v-highlight="'red'">自定义指令</p>
Изменения анимированных переходов
- v-enter->v-enter-from
- v-leave->v-leave-from
В версии vue2.x
Удалить API
2.x, поддержкаkeyCodes
как модификацияv-on
метод метода
<!-- 键码版本 -->
<input v-on:keyup.13="submit" />
<!-- 别名版本 -->
<input v-on:keyup.enter="submit" />
vue3.x
Для любых ключей, которые будут использоваться в качестве модификаторов, рекомендуется использовать имена с регистром кебаб (тире).
<!-- Vue 3 在 v-on 上使用 按键修饰符 -->
<input v-on:keyup.delete="confirmDelete" />
Так это значитconfig.keyCodes
Также теперь устарело и больше не поддерживается.
$on
,$off
а также$once
Методы экземпляра были удалены, а экземпляры приложений больше не реализуют интерфейс запуска событий.
Фильтры были удалены из Vue 3.0 и больше не поддерживаются. Вместо этого мы рекомендуем заменить их вызовами методов или вычисляемыми свойствами.