多个根节点编辑器不会报错

Vue3是容许咱们有多个根节点的,然而咱们前端培训如果应用Vetur就会报错,不会影响运行,然而看起来就很烦。所以当咱们转向Volar那么就不会呈现这个问题了。

编辑器分隔

即使Vue的组件化开发,能够将单文件的代码长度大幅缩短,但还是动辄几百行甚是上千行。那么咱们切换template,script和style的时候就要频繁高低翻,尽管有的插件能够间接定位到css,然而你回不去啊!所以这个性能几乎是太人性化了。

装置完Volar当前,关上一个.vue文件,看vscode的右上角,有这么一个图标,点一下。

它就会主动给你分隔成三个页面,别离对应template,script和style,这样就太难受了有没有。

Vue 3 Snippets

举荐的第二个插件叫做Vue 3 Snippets,同样的,他也有本人的Vue2版本。它是干什么的呢,能够看一下上面这张图,我只输出了“v3”,它有很多提醒,咱们就先抉择v3computed,选中回车即可。

而后它就给主动给咱们写了如下代码

是不是超级省事,摸鱼的工夫又减少了!还有更多乏味的应用形式,小伙伴们自行摸索吧。

创立Vue3我的项目

那么正式开始学习咱们的Vue3,先从创立我的项目开始。

应用 vue-cli 创立

输出上面的命令而后抉择配置项进行装置即可,这里留神vue-cli的版本肯定要在4.5.0以上

// 装置或者降级
npm install -g @vue/cli
//查看版本 保障 vue cli 版本在 4.5.0 以上
vue --version
// 创立我的项目
vue create my-project
//而后依据提醒一步一步傻瓜式操作就行了
...
复制代码

应用 Vite 创立

都说Vue3.0和Vite2更配,各种优化,各种快,但都不属于本文的内容,本文的目标咱们只须要晓得它特地好用,怎么用就行了。我这里是多抉择了TS,每行都有正文,高深莫测。

// 初始化viete我的项目
npm init vite-app <project-name>
// 进入我的项目文件夹
cd <project-name>
// 装置依赖
npm install
//启动我的项目
npm run dev
复制代码

创立完当前咱们先来看看入口文件main.ts

// 引入createApp函数,创立对应的利用,产生利用的实例对象
import { createApp } from 'vue';
// 引入app组件(所有组件的父级组件)
import App from './App.vue';
// 创立app利用返回对应的实例对象,调用mount办法进行挂载 挂载到#app节点下来
createApp(App).mount('#app');
复制代码

而后看看根组件app.vue

//Vue2组件中的html模板中必须要有一对根标签,Vue3组件的html模板中能够没有根标签
<template>
<img alt="Vue logo" src="./assets/logo.png">
<!-- 应用子级组件 -->
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</template>

<script lang="ts">
// 这里能够书写TS代码

// defineComponent函数,目标是定义一个组件 外部能够传入一个配置对象
import { defineComponent } from 'vue';
//引入子级组件
import HelloWorld from './components/HelloWorld.vue';

// 裸露进来一个定义好的组件
export default defineComponent({
// 以后组件的名字
name: 'App',
// 注册组件
components: {

// 注册一个子级组件HelloWorld,

},
});
</script>
复制代码

Composition API

接下来到了重头戏,Vue3的招牌个性,Composition API

对于Composition API这里有大佬做的动画演示,极力推荐。

那个忙了一夜的Vue3动画很好,就是太短了

Composition API能够更不便的抽取共通逻辑,然而不要过于在意逻辑代码复用,以性能提取代码也是一种思路。

顺便提一句,Vue3兼容大部分Vue2语法,所以在Vue3中书写Vue2语法是没有问题的(破除的除外),然而既然咱们曾经降级Vue3了,不倡议混合应用,除非一些大型非凡我的项目须要兼容两个版本。

setup

setup是组合Composition API中的入口函数,也是第一个要应用的函数。

setup只在初始化时执行一次,所有的Composition API函数都在此应用。

setup() {
console.log('我执行了') //我执行了
},
复制代码

能够通过console.log看到setup是在beforeCreate生命周期之前执行的(只执行一次)

beforeCreate() {

console.log('beforeCreate执行了');

},
setup() {

console.log('setup执行了');return {};

},
//setup执行了
//beforeCreate执行了
复制代码

由此能够推断出setup执行的时候,组件对象还没有创立,组件实例对象this还不可用,此时this是undefined, 不能通过this来拜访data/computed/methods/props。

返回对象中的属性会与data函数返回对象的属性合并成为组件对象的属性,返回对象中的办法会与methods中的办法合并胜利组件对象的办法,如果有重名, setup优先。因为在setup中this不可用,methods中能够拜访setup提供的属性和办法, 但在setup办法中不能拜访data和methods里的内容,所以还是不倡议混合应用。

setup函数如果返回对象, 对象中的 属性 或 办法 , 模板 中能够间接应用

//templete
<div>{{number}}</div>

//JS
setup() {
const number = 18;
return {

number,

};
},
复制代码

留神:setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板中就不能够应用return中返回对象的数据了。

setup的参数(props,context)`

props: 是一个对象,外面有父级组件向子级组件传递的数据,并且是在子级组件中应用props接管到的所有的属性

context:上下文对象,能够通过es6语法解构 setup(props, {attrs, slots, emit})

attrs: 获取以后组件标签上所有没有通过props接管的属性的对象, 相当于 this.$attrs
slots: 蕴含所有传入的插槽内容的对象, 相当于 this.$slots
emit: 用来散发自定义事件的函数, 相当于 this.$emit

演示attrs和props

//父组件
<template>
<child :msg="msg" msg2='哈哈哈' />
</template>
<script lang='ts'>
import { defineComponent, ref } from 'vue';
// 引入子组件
import Child from './components/Child.vue';
export default defineComponent({
name: 'App',
components: {

Child,

},
setup() {

const msg = ref('hello,vue3');return {  msg,};

},
});
</script>

//子组件
<template>
<h2>子组件</h2>
<h3>msg:{{ msg }}</h3>
</template>

<script lang='ts'>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Child',
props: ['msg'],
setup(props, {attrs, slots, emit}) {

console.log('props:', props);//msg: "hello,vue3"console.log('attrs:', attrs);//msg2: "哈哈哈"return {};

},
});
</script>
复制代码

演示emit

//父组件
<template>
<child @show="show" />
</template>

<script lang='ts'>
setup() {

const show = () => {  console.log('name:', 'hzw');};return {  show,};

},
</script>

//子组件
<template>
<button @click='emitFn'>事件散发</button>
</template>
<script lang='ts'>
import { defineComponent } from 'vue';

export default defineComponent({
name: 'Child',
setup(props, { emit }) {

const emitFn = () => {  emit('show');};return {  emitFn,};

},
});
</script>
复制代码

ref
作用

定义一个响应式的数据(个别用来定义一个根本类型的响应式数据Undefined、Null、Boolean、Number和String)

语法
const xxx = ref(initValue):
复制代码

留神:script中操作数据须要应用xxx.value的模式,而模板中不须要增加.value

用一个例子来演示:实现一个按钮,点击能够减少数字

<template>
<div>{{count}}</div>
<button @click='updateCount'>减少</button>
</template>
复制代码

在Vue2中

data() {
return {

conunt: 0,

};
},
methods: {
updateCount() {

this.conunt++;

},
},
复制代码

在Vue3中

setup() {

// ref用于定义一个响应式的数据,返回的是一个Ref对象,对象中有一个value属性//如果须要对数据进行操作,须要应用该Ref对象的value属性const count = ref(0);function updateCount() {  count.value++;}return {  count,  updateCount,};

},
复制代码

在Vue2中咱们通过this.$refs来获取dom节点,Vue3中咱们通过ref来获取节点

首先须要在标签上增加ref='xxx',而后再setup中定义一个初始值为null的ref类型,名字要和标签的ref属性统一

const xxx = ref(null)
复制代码

留神:肯定要在setup的return中返回,不然会报错。

还是用一个例子来演示:让输入框主动获取焦点

<template>
<h2>App</h2>
<input type="text">---
<input type="text" ref="inputRef">
</template>

<script lang="ts">
import { onMounted, ref } from 'vue'
/*
ref获取元素: 利用ref函数获取组件中的标签元素
性能需要: 让输入框主动获取焦点
*/
export default {
setup() {

const inputRef = ref<HTMLElement|null>(null)onMounted(() => {  inputRef.value && inputRef.value.focus()})return {  inputRef}

},
}
</script>
复制代码

reactive
语法
const proxy = reactive(obj)
复制代码

作用

定义多个数据的响应式,接管一个一般对象而后返回该一般对象的响应式代理器对象(Proxy),响应式转换是“深层的”:会影响对象外部所有嵌套的属性,所有的数据都是响应式的。

代码演示
<template>
<h3>姓名:{{user.name}}</h3>
<h3>年龄:{{user.age}}</h3>
<h3>wife:{{user.wife}}</h3>
<button @click="updateUser">更新</button>
</template>

setup() {

const user = reactive({  name: 'hzw',  age: 18,  wife: {    name: 'xioaohong',    age: 18,    books: ['红宝书', '设计模式', '算法与数据结构'],  },});const updateUser = () => {  user.name = '小红';  user.age += 2;  user.wife.books[0] = '金瓶梅';};return {  user,  updateUser,};

},
复制代码

computed函数:

与Vue2中的computed配置性能统一,返回的是一个ref类型的对象

计算属性的函数中如果只传入一个回调函数 示意的是get操作

import { computed } from 'vue';
const user = reactive({
firstName: '韩',
lastName: '志伟',
});
const fullName1 = computed(() => {
return user.firstName + user.lastName;
});
return {
user,
fullName1,
};
复制代码

计算属性的函数中能够传入一个对象,能够蕴含set和get函数,进行读取和批改的操作

const fullName2 = computed({
get() {

return user.firstName + '_' + user.lastName;

},
set(val: string) {

const names = val.split('_');user.firstName = names[0];user.lastName = names[1];

},
});
return {
user,
fullName2,
};
复制代码

watch函数:

与Vue2中的watch配置性能统一,

参数1:要监听的数据
参数2:回调函数
参数3:配置
作用

监督指定的一个或多个响应式数据, 一旦数据变动, 就主动执行监督回调

默认初始时不执行回调, 但能够通过配置immediate为true, 来指定初始时立刻执行第一次

通过配置deep为true, 来指定深度监督

import { watch, ref } from 'vue';
const user = reactive({
firstName: '韩',
lastName: '志伟',
});
const fullName3 = ref('');
watch(
user,
({ firstName, lastName }) => {

fullName3.value = firstName + '_' + lastName;

},
{ immediate: true, deep: true }
);
return {
user,
fullName3,
};
复制代码

watch监听多个数据,应用数组

watch监听非响应式数据的时候须要应用回调函数的模式

watch([()=>user.firstName,()=>user.lastName,fullName3],()=>{console.log('我执行了')})
复制代码

watchEffect函数:
作用

监督数据发生变化时执行回调,不必间接指定要监督的数据, 回调函数中应用的哪些响应式数据就监督哪些响应式数据,默认初始时就会执行第一次, 从而能够收集须要监督的数据。

import { watchEffect, ref } from 'vue';
const user = reactive({
firstName: '韩',
lastName: '志伟',
});
const fullName4 = ref('');
watchEffect(() => {
fullName4.value = user.firstName + '_' + user.lastName;
});
return {
user,
fullName4,
};
watchEffect能够实现计算属性set办法
watchEffect(() => {

const names = fullName3.value.split('_');user.firstName = names[0];user.lastName = names[1];

});
复制代码

生命周期比照:

留神:3.0中的生命周期钩子要比2.X中雷同生命周期的钩子要快

Composition API还新增了以下调试钩子函数:然而不怎么罕用

onRenderTracked
onRenderTriggered
代码演示
setup() {

onBeforeMount(() => {

console.log('--onBeforeMount')

})

onMounted(() => {

console.log('--onMounted')

})

onBeforeUpdate(() => {

console.log('--onBeforeUpdate')

})

onUpdated(() => {

console.log('--onUpdated')

})

onBeforeUnmount(() => {

console.log('--onBeforeUnmount')

})

onUnmounted(() => {

console.log('--onUnmounted')

})
}
复制代码

toRefs
作用

把一个响应式对象转换成一般对象,该一般对象的每个属性都是一个 ref

利用

咱们应用reactive创立的对象,如果想在模板中应用,就必须得应用xxx.xxx的模式,如果大量用到的话还是很麻烦的,然而应用es6解构当前,会失去响应式,那么toRefs的作用就体现在这,,利用toRefs能够将一个响应式 reactive 对象的所有原始属性转换为响应式的ref属性。当然小伙伴们能够自行开发更多利用场景。

代码演示
<template>
<div>

name:{{name}}

</div>
</template>

<script lang='ts'>
import { defineComponent, reactive, toRefs } from 'vue';

export default defineComponent({
name: '',
setup() {

const state = reactive({  name: 'hzw',});const state2 = toRefs(state);setInterval(() => {  state.name += '===';}, 1000);return {  //通过toRefs返回的对象,解构进去的属性也是响应式的  ...state2,};

},
});
</script>
复制代码

provide 与 inject
作用

实现跨层级组件(祖孙)间通信

代码演示

父组件

<template>
<h1>父组件</h1>
<p>以后色彩: {{color}}</p>
<button @click="color='red'">红</button>
<button @click="color='yellow'">黄</button>
<button @click="color='blue'">蓝</button>



<Son />
</template>
<script lang="ts">
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'ProvideInject',
components: {
Son

},
setup() {

const color = ref('red')provide('color', color)return {  color}

}
}
</script>
复制代码

子组件

<template>
<div>

<h2>子组件</h2><hr><GrandSon />

</div>
</template>

<script lang="ts">
import GrandSon from './GrandSon.vue'
export default {
components: {

GrandSon

},
}
</script>
复制代码

孙子组件

<template>
<h3 :style="{color}">孙子组件: {{color}}</h3>
</template>

<script lang="ts">
import { inject } from 'vue'
export default {
setup() {

const color = inject('color')return {  color}

}
}
</script>
复制代码

其余个性
**Teleport(瞬移)
作用**

Teleport 提供了一种洁净的办法, 让组件的html在父组件界面外的特定标签(很可能是body)下插入显示 换句话说就是能够把 子组件 或者 dom节点 插入到任何你想插入到的中央去。

语法

应用to属性 引号内应用选择器

<teleport to="body">
</teleport>
复制代码

代码演示
//父组件

<template>
<div >

<h2>App</h2><modal-button></modal-button>

</div>
</template>

<script lang="ts">
import ModalButton from './components/ModalButton.vue'
export default {
setup() {

return {}

},
components: {

ModalButton,

},
}
</script>

//子组件
<template>
<div >

<button @click="modalOpen = true">  点我关上对话框</button><teleport to="body">  <div v-if="modalOpen"       >    看看我呈现在了哪里    <button @click="modalOpen = false">      Close    </button>  </div></teleport>

</div>
</template>

<script>
import { ref } from 'vue'
export default {
name: 'modal-button',
setup() {

const modalOpen = ref(false)return {  modalOpen,}

},
}
</script>
复制代码

能够看到在子组件中的looklook元素跑到了body上面,而之前的地位默认呈现了两行正文

微信截图_20210623170701.png

Suspense(不确定的)
作用

它们容许咱们的应用程序在期待异步组件时渲染一些后备内容,能够让咱们创立一个平滑的用户体验

语法
<Suspense>

<template v-slot:default>  <!-- 异步组件 -->  <AsyncComp /></template><template v-slot:fallback>  <!-- 后备内容 -->  <h1>LOADING...</h1></template>

</Suspense>
复制代码

vue3中引入异步组件的形式

const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
复制代码

代码演示

父组件

<template>
<Suspense>

 <!-- v-slot:defaul能够简写成#defaul --><template v-slot:default>  <AsyncComp/></template><template v-slot:fallback>  <h1>LOADING...</h1></template>

</Suspense>
</template>

<script lang="ts">
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
export default {
setup() {

return {}

},

components: {

AsyncComp,

}
}
</script>
复制代码

子组件

<template>
<h2>AsyncComp22</h2>
<p>{{msg}}</p>
</template>

<script lang="ts">
export default {
name: 'AsyncComp',
setup () {

 return new Promise((resolve, reject) => {   setTimeout(() => {     resolve({       msg: 'abc'     })   }, 2000) })

}
}
</script>

复制代码

通过下图能够看到在异步组件加载进去之前,显示的是fallback中的内容

响应式数据的判断
作用
isRef: 查看一个值是否为一个 ref 对象
isReactive: 查看一个对象是否是由 reactive 创立的响应式代理
isReadonly: 查看一个对象是否是由 readonly 创立的只读代理
isProxy: 查看一个对象是否是由 reactive 或者 readonly 办法创立的代理
代码演示
setup() {

const state1 = ref(1);console.log('isref:', isRef(state1));//isref: trueconst state2 = reactive({});console.log('isReactive:', isReactive(state2));//isReactive: trueconst state3 = readonly({});console.log('isReadonly:', isReadonly(state3));//isReadonly: trueconst state4 = reactive({});console.log('isProxy:', isProxy(state2));//isProxy: trueconsole.log('isProxy:', isProxy(state4));//isProxy: truereturn {};

},
复制代码

其余不罕用个性

还有很多很多不罕用的新个性,我在日常开发中是没有用到的,很多都是用来做优化的,感兴趣的小伙伴们自行去官网查看,或者大佬们能够介绍一下利用场景。

shallowReactive
shallowRef
readonly
shallowReadonly
markRaw
customRef
...
语法糖

尽管Composition API用起来曾经十分不便了,然而咱们还是有很烦的中央,比方

组件引入了还要注册
属性和办法都要在setup函数中返回,有的时候仅一个return就十几行甚至几十行
...
不想写啊怎么办

好办,Vue3官网提供了script setup语法糖

只须要在script标签中增加setup,组件只需引入不必注册,属性和办法也不必返回,setup函数也不须要,甚至export default都不必写了,不仅是数据,计算属性和办法,甚至是自定义指令也能够在咱们的template中主动取得。

然而这么过瘾的语法糖,还是略微增加了一点点心智累赘,因为没有了setup函数,那么props,emit,attrs怎么获取呢,就要介绍一下新的语法了。

setup script语法糖提供了三个新的API来供咱们应用:defineProps、defineEmit和useContext

defineProps 用来接管父组件传来的值props。
defineEmit 用来申明触发的事件表。
useContext 用来获取组件上下文context。
代码演示

父组件

<template>
<div>

<h2>我是父组件!</h2><Child msg="hello"       @child-click="handleClick" />

</div>
</template>

<script setup>
import Child from './components/Child.vue'

const handleClick = (ctx) => {
console.log(ctx)
}
</script>
复制代码

子组件

<template>
<span @click="sonClick">msg: {{ props.msg }}</span>
</template>

<script setup>
import { useContext, defineProps, defineEmit } from 'vue'

const emit = defineEmit(['child-click'])
const ctx = useContext()
const props = defineProps({
msg: String,
})

const sonClick = () => {
emit('child-click', ctx)
}
</script>

复制代码

咱们点击一下子组件

能够看到context被打印了进去,其中的attrs、emit、slots、expose属性和办法仍然能够应用。props也能够输入在页面上,事件也胜利派发。

其余知识点

接下来介绍一下我应用Vue3过程中遇到的问题或者小技巧,不全面,想起什么就写什么吧

script setup语法糖请留神

如果在父组件中通过ref='xxx'的办法来获取子组件实例,子组件应用了script setup语法糖,那么子组件的数据须要用expose的形式导出,否则会因为获取不到数据而报错。

代码演示

父组件

<template>
<div>

<h2>我是父组件!</h2><Child ref='son' />

</div>
</template>

<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const son = ref(null)
console.log('~ son:', son)
</script>
复制代码

子组件先不应用语法糖

<template>
<div>

我是子组件{{msg}}

</div>
</template>

<script >
import { ref } from 'vue'

export default {
setup() {

const msg = ref('hello')return {  msg,}

},
}
复制代码

能够看到是能够获取到咱们在子组件中定义的msg属性的

当初把子组件换成script setup语法糖再来试一试

<template>
<div>

我是子组件{{msg}}

</div>
</template>

<script setup>
import { ref } from 'vue'
const msg = ref('hello')
</script>

复制代码

能够看到当初是获取不到子组件定义的msg属性的

Emit派发事件能够对参数进行验证

父组件

<template>
<div>

<h2>我是父组件!</h2><Child @sonClick='sonClick' />

</div>
</template>

<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const sonClick = (value) => {
console.log(value)
}
</script>
复制代码

子组件

<template>
<div>

我是子组件{{ msg }}

</div>
<button @click="handleClick(1)">我是按钮1</button>
<button @click="handleClick(2)">我是按钮2</button>
</template>

<script>
import { ref } from 'vue'
export default {
name: '',
emits: {

sonClick: (value) => {  if (value === 1) {    return true  } else {    return false  }},

},
setup(props, { emit }) {

const msg = ref('hello')const handleClick = (value) => {  emit('sonClick', value)}return {  msg,  handleClick,}

},
}
</script>
复制代码

咱们别离点一下按钮1和按钮2,能够看到当咱们点了按钮2的时候,控制台会收回正告,然而程序会继续执行,还没想到什么适宜的利用场景,然而要晓得这个知识点,小伙伴们能够在这搞事件。

跨组件通信mitt.js

Vue2中怎么实现跨组件通信呢,很多人第一想法就是event bus。然而Vue3移除了$on,$once,$off导致不能应用这个办法。然而Vue官网给大家举荐了mitt.js,它的原理就是event bus。

代码演示

先装置

npm i mitt -s
复制代码

而后封装一个hook

//mitt.js
import mitt from 'mitt'
const emitter = mitt();

export default emitter;
复制代码

父组件

<template>
<div>

<h2>我是父组件!</h2><Child1 /><Child2 />

</div>
</template>

<script setup>
import Child1 from './components/Child1.vue'
import Child2 from './components/Child2.vue'
</script>
复制代码

子组件1

<template>
<div>

我是子组件1<h1>{{msg}}</h1>

</div>
</template>

<script>
import { ref, onUnmounted } from 'vue'
import emitter from '../mitt'
export default {
name: '',

setup() {

//初始化const msg = ref('hello')const changeMsg = () => {  msg.value = 'world'}// 监听事件,更新数据emitter.on('change-msg', changeMsg)// 显式卸载onUnmounted(() => {  emitter.off('change-msg', changeMsg)})return {  msg,  changeMsg,}

},
}
</script>
复制代码

子组件2

<template>
<div>

我是子组件2

</div>
<button @click='changeMsg'>点击批改msg</button>
</template>

<script>
import { ref } from 'vue'
import emitter from '../mitt'

export default {
name: '',

setup() {

const changeMsg = () => {  emitter.emit('change-msg')}return {  changeMsg,}

},
}
</script>
复制代码

自定义指令

先看看Vue2自定义指令的钩子

bind:当指令绑定在对应元素时触发。只会触发一次。
inserted:当对应元素被插入到 DOM 的父元素时触发。
update:当元素更新时,这个钩子会被触发(此时元素的后辈元素还没有触发更新)。
componentUpdated:当整个组件(包含子组件)实现更新后,这个钩子触发。
unbind:当指令被从元素上移除时,这个钩子会被触发。也只触发一次。

在 Vue3 中,官网为了更有助于代码的可读性和格调对立,把自定义指令的钩子名称改的更像是组件生命周期,只管他们是两回事

bind => beforeMount
inserted => mounted
beforeUpdate: 新的钩子,会在元素本身更新前触发
update => 移除!
componentUpdated => updated
beforeUnmount: 新的钩子,当元素本身被卸载前触发
unbind => unmounted
过渡动画

这个没有什么大的改变,只是批改了两个class名字,正是因为没有什么大的改变,导致我已经在这里栽了大跟头,写完了怎么都不对,起初查官网才晓得。

以下是间接援用 官网的原文

v-enter-from:定义进入过渡的开始状态。在元素被插入之前失效,在元素被插入之后的下一帧移除。

v-enter-active:定义进入过渡失效时的状态。在整个进入过渡的阶段中利用,在元素被插入之前失效,在过渡/动画实现之后移除。这个类能够被用来定义进入过渡的过程工夫,提早和曲线函数。

v-enter-to:定义进入过渡的完结状态。在元素被插入之后下一帧失效 (与此同时 v-enter-from 被移除),在过渡/动画实现之后移除。

v-leave-from:定义来到过渡的开始状态。在来到过渡被触发时立即失效,下一帧被移除。

v-leave-active:定义来到过渡失效时的状态。在整个来到过渡的阶段中利用,在来到过渡被触发时立即失效,在过渡/动画实现之后移除。这个类能够被用来定义来到过渡的过程工夫,提早和曲线函数。

v-leave-to:来到过渡的完结状态。在来到过渡被触发之后下一帧失效 (与此同时 v-leave-from 被删除),在过渡/动画实现之后移除。

特地留神的是v-enter改成了v-enter-form,v-leave改成了v-leave-from。