尽管 vue2 到 vue3 的同时实现大改,但在用语上变动基本上并不大,较为显著的两个变动是加进了 setup(){} 表达式了,基本上上大部份的实用性变为了以表达式的形式展开表述。即便是这种,但小更动却是许多的。本文主要就撷取的是 vue 2.x 与 vue 3.x 间许多常用用语的差别。尽管历史记录的不多,但也算不上少。
总之这儿预设你早已熟练了 vue 2.x 的采用,上面他们就来看一看。
一、追加composition-api
1.方式论F83E43Se和标识符组织机构
这是 vue 3.0 的两个核心理念更改了。除改了他们表述状况的手写形式外,也为他们提供更多新体验更棒的方式论F83E43Se和标识符组织机构,捷伊形式能让你把同一销售业务方式论的标识符(状况,计算特性,方式等)都放在几块。这听出来可能将有点儿无缘无故,但假如你写过非常复杂的模块,你就会辨认出,那个好。
2.更快的类别推测
更快的全力支持 TypeScript。
teleport 模块
teleport 模块它只是单纯的把表述在其内部的内容转移到目标元素中,在元素结构上不会产生多余的元素,总之也不会影响到模块树,它相关于透明的存在。为什么要有那个模块?为了有更快的标识符组织机构新体验。比如:有时,模块模板的一部分在方式论上属于此模块,但从技术角度来看(如:样式化需求),最好将模板的这一部分移动到 DOM 中的其他位置。
比如:许多 UI 模块库的 模态窗、对话框、通知,下拉菜单等需要通知 z-index 来控制层级关系,假如都只是在不同的模块或者元素层级中,那么 z-index 的层级顺序就难以保证。可能将你会说许多 UI 库不是都早已是这种的同时实现了的吗?至于那个 UI 库是如何同时实现的,我猜应该是直接操作 DOM。为什么还要提供更多那个 teleport 模块呢?可能将是因为vue 本身的使命使然:尽量不让开发者直接操作 DOM,这些事都统一由 VUE 来完成。开发者能把更多的时间放在销售业务的开发上。
<teleport to=”#modals”> <div>A</div></teleport><teleport to=”#modals”> <div>B</div></teleport><!– result–><div id=”modals”> <div>A</div> <div>B</div></div>复制标识符
Suspense
加载异步模块,在异步模块加载完成成并完全渲染之前 suspense 会先显示 #fallback 插槽的内容 。
<Suspense> <template> <Suspended-component /> </template> <template #fallback> Loading… </template></Suspense>复制标识符
#fallback 其实是插件 v-solt 的简写,而第两个 template 没有给,则为预设插槽。
更改
插槽 slot 语法
适用版本:Version: 2.x,Version: 3.x
未来版本的 vue 中能说合二为一了(slot 和 slot-scope)
<!– 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>复制标识符
我觉得这是好事,合二为一,不会让人有一点点的困惑。
简写
<TestComponent> <template #one=”{ name }”>Hello {{ name }}</template></TestComponent>复制标识符
指令动态参数
适用版本:Version: 2.x,Version: 3.x
<!– 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
适用版本:Version: 3.x
在 vue 3 中不会把大部份的 api 都打包进来,只会 打包你用到的 api
<!– vue 2.x –>import Vue from vueVue.nextTick(() => {})const obj = Vue.observable({})<!– vue 3.x –>import Vue, { nextTick, observable } from vueVue.nextTick // undefinednextTick(() => {})const obj = observable({})复制标识符
即他们在项目中用什么什么,就只会打包什么,不会像 vue 2.x 那样全部 api 都打包。
.sync 大变样
适用版本: vue 3.x
<!– vue 2.x –><MyComponent v-bind:title.sync=”title” /><!– vue 3.x –><MyComponent v-model:title=”title” />复制标识符
也是说,vue 3.0 又去掉了 .sync ,合并到了 v-model 里,而 v-model 的内部同时实现也有了小调整
元素
<input v-model=”xxx”><!– would be shorthand for: –><input :model-value=”xxx” @update:model-value=”newValue => { xxx = newValue }”>复制标识符
模块
<MyComponent v-model:aaa=”xxx”/><!– would be shorthand for: –><MyComponent :aaa=”xxx” @update:aaa=”newValue => { xxx = newValue }”/>复制标识符
不过好像组 alpha 版本的还不全力支持 v-model:aaa=”xxx”
表达式模块
适用版本: vue 3.x
<!– vue 2.x –>const FunctionalComp = { functional: true, render(h) { return h(div, `Hello! ${props.name}`) }} <!– vue 3.x –>import { h } from vueconst FunctionalComp = (props, { slots, attrs, emit }) => { return h(div, `Hello! ${props.name}`)}复制标识符
不再需要 functional:true 选项,<template functional> 不再支付
异步模块也必需通过 api 方式创建
import { defineAsyncComponent } from vueconst AsyncComp = defineAsyncComponent(() => import(./Foo.vue))复制标识符
全局 api
适用版本: vue 3.x
在 vue 2.x 中
import Vue from vueimport App from ./App.vueVue.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 vueimport App from ./App.vueconst 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)复制标识符
能看到,创建实例的形式也改变了。许多全局的 api 方式也不在全局上了,而是放在了实例上。
v-model
适用版本:Version 3.x
1.原来的形式保留
<input v-model=”foo”>复制标识符
2.可绑定多个 v-model
<InviteeForm v-model:name=”inviteeName” v-model:email=”inviteeEmail”/>复制标识符
其实上面这种形式就相当于之前的 .sync 。
3.额外处理
<Comp v-model:foo.trim=”text” v-model:bar.number=”number” />复制标识符
他们能给那个特性加进额外的处理
指令的钩子表达式
适用版本:Version 3.x
在 vue 3.x 中 指令的钩子表达式仿照了模块中的钩子表达式命名规则
vue 2.x 时
const MyDirective = { bind(el, binding, vnode, prevVnode) {}, inserted() {}, update() {}, componentUpdated() {}, unbind() {}}复制标识符
vue 3.0 中
const MyDirective = { beforeMount(el, binding, vnode, prevVnode) {}, mounted() {}, beforeUpdate() {}, updated() {}, beforeUnmount() {}, // new unmounted() {}}复制标识符
transition
适用版本:Version 3.x
当 <transition> 作为模块的根元素时,外部切换不会触发过渡效果
vue 2.x
<!– modal component –><template> <transition> <div class=”modal”><slot/></div> </transition></template><!– usage –><modal v-if=”showModal”>hello</modal>复制标识符
vue 3.x
<!– modal component –><template> <transition> <div v-if=”show” class=”modal”><slot/></div> </transition></template><!– usage –><modal :show=”showModal”>hello</modal>复制标识符
也是说他们只能在 <sransition> 内采用切换。
transition-class
重命名两个过渡类
v-enter 重命名成.v-enter-from,v-leave重命名成 .v-enter-from。
.v-enter-from, .v-leave-to { opacity: 0;}.v-leave-from, .v-enter-to { opacity: 1}复制标识符
Router
适合版本:Version: Vue (2.x / 3.x) Vue Router (3.x / 4.x)
1.router-link 加进 scoped-slot API 和 custom 特性,并移除 tag 特性和 event 特性。
加进 scoped-slot 有什么用呢?以前只能通知 active-class 来改变元素样式的,现在有了 scoped-slot 之后,他们就更加灵活了,能根据 scoped-slot 回传的状况自表述,不管是样式却是类。
<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>复制标识符
也是说,新版本的 Router 就更加的纯粹,只提供更多给他们许多参数,让他们自己利用这些参数来同时实现不同的场景。
2.meta 合并
{ path: /parent, meta: { requiresAuth: true, isChild: false }, children: [ { path: child, meta: { isChild: true }} ]}复制标识符
当访问 /parent/child 时,子路由中的 meta 如下:
{ requiresAuth: true, isChild: true }复制标识符
合并策略与 Object.assign 类似
样式 scoped
适用版本:Version: 2.x, 3.x
旧版本写法
/* 深度选择器 *//*方式一:*/>>> .foo{ }/*形式二:*//deep/ .foo{ }/*形式三*/::v-deep .foo{ }复制标识符
新版本写法
/* 深度选择器 */::v-deep(.foo) {}复制标识符
除上面的深度选择器外,还有上面的两个,写法也差不多
/* slot content 起作用 */::v-slotted(.foo) {}/* 全局 */::v-global(.foo) {}复制代码
特性值修正
适用版本:Version: 3.x
vue 本身会对元素的特性作相应的处理。在旧版本的 vue 中处理如下:
新版本处理形式:
在新版本中基本上保持了原样,也是他们给元素加进什么特性值,最好 vue 处理完后却是什么特性值。
异步模块
import { defineAsyncComponent } from “vue”// simple usageconst AsyncFoo = defineAsyncComponent(() => import(“./Foo.vue”))复制标识符
写法上与之前有些不一样。
动态路由
适用版本 Router 4
加进了几个方式
router.addRoute(route: RouteRecord) 动态加进路由router.removeRoute(name: string | symbol),动态删除路由router.hasRoute(name: string | symbol): boolean ,判断路由是否存在router.addRoute({ path: /new-route, name: NewRoute, component: NewRoute})// add to the children of an existing routerouter.addRoute(ParentRoute, { path: new-route, name: NewRoute, component: NewRoute})router.removeRoute(NewRoute)// normalized version of the records addedconst routeRecords = router.getRoutes()复制标识符
emits-option
const Foo = defineComponent({ emits: { submit: (payload: { email: string; password: string }) => { // perform runtime validation } }, methods: { onSubmit() { this.$emit(submit, { email: [email protected], password: 123 // Type error! }) this.$emit(non-declared-event) // Type error! } }})复制标识符
现在的 $emit() 方式在用语上没变,但需要额外多表述 emits 对象,但要注意的是现在 alpha 版本还不全力支持 TypeScript
模块根元素数量
vue 3 后模块不再限制 template 中根元素的个数(旧的版本之前是只能有两个根元素)。
vue 3.x 中费弃
filterskeycodeinline-templatedata-objectoff 和 $once阅读完责任编辑我相信你大概对 vue 3 有了两个基本上的认识。尽管责任编辑会不让你瞬间成为 vue 3.x 的驾驭者,但怎么说也让你含蓄地新体验了一把 vue 3.x 的新特性。特别是 composition API 即便责任编辑没有详细写出来,但通知补充的链接,你也能阅读到它的大部份。我觉得 composition API 真的很棒。