Vue3.0-one Piece

avatar

本文主要记录v3.0至v2.0的变动

喜大普庆,vue终于发布3.0版本,代号为One-Piece,原文链接:v3.0.0

slot

适用v2.0与v3.0

slot插槽的改变,在v2.6版本已经在官方文档上支持v-slot,#缩写等,所以不多赘述
原文链接:slot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- vue 2.x -->
<foo>
<bar slot="one" slot-scope="one">
<div slot-scope="bar">
{{ one }} {{ bar }}
</div>
</bar>

<bar slot="two" slot-scope="two">
<div slot-scope="bar">
{{ two }} {{ bar }}
</div>
</bar>
</foo>

<!-- vue 3.x -->
<foo>
<template v-slot:one="one">
<bar v-slot="bar">
<div>{{ one }} {{ bar }}</div>
</bar>
</template>

<template v-slot:two="two">
<bar v-slot="bar">
<div>{{ two }} {{ bar }}</div>
</bar>
</template>
</foo>

指令动态参数

适用v2.0与v3.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- v-bind with dynamic key -->
<div v-bind:[key]="value"></div>

<!-- v-bind shorthand with dynamic key -->
<div :[key]="value"></div>

<!-- v-on with dynamic event -->
<div v-on:[event]="handler"></div>

<!-- v-on shorthand with dynamic event -->
<div @[event]="handler"></div>

<!-- v-slot with dynamic name -->
<foo>
<template v-slot:[name]>
Hello
</template>
</foo>

<!-- v-slot shorthand with dynamic name -->
<!-- pending #3 -->
<foo>
<template #[name]>
Default slot
</template>
</foo>

Tree-shaking

适用v3.0
在vue3.0中api等使用方式有极大变化,而这种变化对文件压缩大小的优化有好处,不便之处就是写起来较麻烦了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- vue 2.x -->
import Vue from 'vue'

Vue.nextTick(() => {})

const obj = Vue.observable({})

<!-- vue 3.x -->
import Vue, { nextTick, observable } from 'vue'

Vue.nextTick // undefined

nextTick(() => {})

const obj = observable({})

.sync与v-model

这两项变动是互相影响的,.sync在v3.0直接移除,转而支持v-model多配置,具体代码如下:

1
2
3
4
5
<!-- vue 2.x -->
<MyComponent v-bind:title.sync="title" />

<!-- vue 3.x -->
<MyComponent v-model:title="title" v-model:name="name" />
1
2
3
4
5
6
<!-- vue 2.x -->
<input v-bind="xxx" v-on:change="$emit('change', $event.target.checked)">

<!-- vue 3.x -->
<input
:model-value="xxx" v-on:['update:model-value']="newValue => { xxx = newValue }">

函数组件

适用v3.0
不再需要 functional:true 选项, <template functional>\ 标签也不支持

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- vue 2.x -->
const FunctionalComp = {
functional: true,
render(h) {
return h('div', `Hello! ${props.name}`)
}
}

<!-- vue 3.x -->
import { h } from 'vue'
const FunctionalComp = (props, { slots, attrs, emit }) => {
return h('div', `Hello! ${props.name}`)
}

全局api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- vue 2.x -->
import Vue from 'vue'
import App from './App.vue'

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

Vue.prototype.customProperty = () => {}

new Vue({
render: h => h(App)
}).$mount('#app')

<!-- vue 3.x -->
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.isCustomElement = tag => tag.startsWith('app-')
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.config.globalProperties.customProperty = () => {}

app.mount(App, '#app')

指令钩子函数

适用v3.0
在vue 3.x中指令内部的钩子函数仿照组件声明周期了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- vue 2.x -->
const MyDirective = {
bind(el, binding, vnode, prevVnode) {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {}
}

<!-- vue 3.x -->
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}

transition、transition-class

适用v3.0
template作为组件的根元素时,外部切换不会触发过渡效果
v-enter 重命名为v-enter-fromv-leave重命名为v-leave-from

1
2
3
4
5
<template>
<transition>
<div v-if="show" class="modal"><slot/></div>
</transition>
</template>
1
2
3
4
5
6
.v-enter-from, .v-leave-to {
opacity: 0;
}
.v-leave-from, .v-enter-to {
opacity: 1
}

Router

适用v3.0

router-link 新增 scope-slotcustom 属性,移除 tagevent
这点对于封装视图组件或菜单组件尤为重要,使组件更具有语义及更纯粹

1
2
3
4
5
6
7
<router-link to="/" custom v-slot="{ href, navigate, isActive }">
<li :class="{ 'active': isActive }">
<a :href="href" @click="navigate">
<Icon>home</Icon><span class="xs-hidden">Home</span>
</a>
</li>
</router-link>

路由匹配所有

以往匹配所有路由的写法{ path:'*' }即可,现改为{ path: '/:catchAll(.*)' }

获取当前路由信息

1
2
3
4
5
6
7
import router from '../router'
export default {
setup () {
const currentRoute = router.currentRoute.value
console.log(currentRoute)
}
}

router为定义vue路由的文件

1
2
3
4
5
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes
})

异步组件

通过 defineAsyncComponent 函数创建

1
2
3
4
import { defineAsyncComponent } from "vue"

// simple usage
const AsyncFoo = defineAsyncComponent(() => import("./Foo.vue"))

动态路由

router.addRoutes 是v2.x版本的新增路由方法,先新增如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// router.addRoute(route: RouteRecord) 动态添加路由
// router.removeRoute(name: string | symbol),动态删除路由
// router.hasRoute(name: string | symbol): boolean ,判断路由是否存在
// router.getRoutes(): RouteRecord[] 获取路由列表

router.addRoute({
path: '/new-route',
name: 'NewRoute',
component: NewRoute
})

// add to the children of an existing route
router.addRoute('ParentRoute', {
path: 'new-route',
name: 'NewRoute',
component: NewRoute
})

router.removeRoute('NewRoute')

// normalized version of the records added
const routeRecords = router.getRoutes()

样式 scoped

1
2
3
4
5
6
7
8
/* 深度选择器 */
::v-deep(.foo) {}

/* slot content 起作用 */
::v-slotted(.foo) {}

/* 全局 */
::v-global(.foo) {}

emits-option

与v2.x版本相比,多了要先定义emit出去的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const Foo = defineComponent({
emits: {
submit: (payload: { email: string; password: string }) => {
// perform runtime validation
}
},

methods: {
onSubmit() {
this.$emit('submit', {
email: 'foo@bar.com',
password: 123 // Type error!
})

this.$emit('non-declared-event') // Type error!
}
}
})

组件根元素数量

template 不在是限制只有一个,在v3.x中可以存在多个根元素

v3.x中废弃

  • beforeCreate、created
  • filters
  • keycode
  • inline-template
  • data-object
  • on,off 和 $once

结语

1
2
3
4
5
6
7
8
9
10
11
//定义部分
st=>start: coding beginning
e=>end: 秃秃秃秃,继续coding
op1=>operation: 框架更新拉
sub1=>subroutine: 继续使用老框架
cond=>condition: 是否学习?:>https://cn.vuejs.org/
io=>inputoutput: 技能提升,升职加薪

st->op1->cond
cond(yes)->io->e
cond(no)->sub1(right)->op1