Skip to content

1.slot语法更简短

统一成v-slot,包括局部作用域

html
<foo>
  <template v-slot:header="{ msg }">
    {{ msg }}
  </template>
</foo>

#号简写

html
<foo>
  <template #header="{ msg }">
    Message from header: {{ msg }}
  </template>

   <template #footer>
    A static footer
  </template>
</foo>

2.动态指令参数

html
<div :[key]="value"></div>
<div @[event]="handler"></div>

3.树摇

变化

Currently in 2.x, all global APIs are exposed on the single Vue object:

js
import Vue from 'vue'
Vue.nextTick(() => {})
const obj = Vue.observable({})

In 3.x, they can only be accessed as named imports:

js
import Vue, { nextTick, observable } from 'vue'
Vue.nextTick // undefined
nextTick(() => {})
const obj = observable({})

Affected 2.x APIs

  • Vue.nextTick
  • Vue.observable
  • Vue.version
  • Vue.compile (only in full builds)
  • Vue.set (only in compat builds)
  • Vue.delete (only in compat builds)

4.增强v-model

Instead of:

html
<MyComponent v-bind:title.sync="title" />

the syntax would be:

html
<MyComponent v-model:title="title" />

5.全局方法改成实例方法

Before

javascript
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')

After

javascript
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')

6.自定义指令

动机

自定义指令钩子名称和组件生命周期钩子名称一致

Before

const MyDirective = {
  bind(el, binding, vnode, prevVnode) {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {}
}

After

const MyDirective = {
  beforeMount(el, binding, vnode, prevVnode) {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeUnmount() {}, // new
  unmounted() {}
}

7.composition api

html
<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

8.移除filter

移除动机

  • filter操作符|和逻辑或冲突
  • 创造了js不支持的新语法
  • 可以被方法和计算属性代替
  • 增加实现成本和框架复杂度
html
<!-- before -->
{{ msg | format }}
<!-- after -->
{{ format(msg) }}

9.移除keycode

移除动机

  • KeyboardEvent.keyCode可以用KeyboardEvent.key替代
html
<input @keyup.page-down="onArrowUp">

10.移除inline-template

移除动机

  • inline-template让模板作用域不一致
html
<!-- before -->
<my-comp inline-template :msg="parentMsg">
  {{ msg }} {{ childState }}
</my-comp>

<!-- after -->
<my-comp v-slot="{ childState }">
  {{ parentMsg }} {{ childState }}
</my-comp>

11.vue实例上移除事件方法

Remove $on, $off and $once instance methods.

移除动机

  • event emitter API不是组件数据流的一部分

12.移除inline-template

Remove $on, $off and $once instance methods.

移除动机

  • 保持和css命令一致
html
<style scoped>
/* deep selectors */
::v-deep(.foo) {}
/* shorthand */
:deep(.foo) {}

/* targeting slot content */
::v-slotted(.foo) {}
/* shorthand */
:slotted(.foo) {}

/* one-off global rule */
::v-global(.foo) {}
/* shorthand */
:global(.foo) {}
</style>

13.data对象声明

javascript
import { createApp, h } from 'vue'

createApp().mount({
// 这里只能用函数
  data() {
    return {
      counter: 1,
    }
  }
})

参考

has loaded