安装vite

npx create-vite-app myvue3-app
npm install
npm run dev

composition api

composition api 为vue代码提供更好的逻辑复用和代码组织

<template>
<div>
    <h1>{{ msg }}</h1>
    <button @click="count++">count is: {{ count }}</button>
    <p>Edit <code>components/HelloWorld.vue</code> to test hot module replacement.</p>
    <p>{{counter}}</p>
    <p>{{doubleCounter}}</p>
    <p>{{msg2}}</p>
    <div ref="desc"></div>
</div>
</template>

<script>
import {
    reactive,
    ref,
    toRefs,
    computed,
    watch,
    onMounted,
    onUnmounted
} from 'vue'
export default {
    name: 'HelloWorld',
    props: {
        msg: String
    },
    setup(props) {
        const {
            counter,
            doubleCounter
        } = useCounter();
        const msg2 = ref('message');
        // 使用元素引用
        const desc = ref(null);
        watch(counter, (val, oldVal) => {
            const p = desc.value;
            p.textContent = `counter change from ${oldVal} to ${val}`
        })
        return {
            counter,
            doubleCounter,
            msg2,
            desc
        }
    }
}

function useCounter() {
    // counter相关
    const data = reactive({
        counter: 1,
        doubleCounter: computed(() => data.counter * 2)
    })
    let timer
    onMounted(() => {
        timer = setInterval(() => {
            data.counter++
        }, 1000)
    })
    onUnmounted(() => {
        clearInterval(timer)
    })

    return toRefs(data)
}
</script>

Teleport

传送门组件提供一种简洁的方式可以指定它里面内容的父元素

<template>
<div>
    <button @click="modaleOpen = true">弹出一个模态窗口</button>
    <teleport to="body">
        <div v-if="modaleOpen" class="modal">
            <div>
                这是一个弹窗, 父元素是body
                <button @click="modaleOpen = false">关闭</button>
            </div>

        </div>
    </teleport>
</div>
</template>

<script>
export default {
    data() {
        return {
            modaleOpen: false
        }
    },
}
</script>

<style scoped>
.modal {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, .5);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.modal div {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: white;
    width: 300px;
    height: 300px;
    padding: 5px;
}
</style>

Fragments

vue3中组件可以拥有多个根

<template>
 <header>...</header>
 <main v-bind="$attrs">...</main>
 <footer>...</footer>
</template>

Emits Component Options

vue3中组件发送的自定义事件需要定义在emits选项中:

  • 原生事件会触发两次, 比如click
  • 更好的指示组件的工作方式

Global Api改为应用程序实例调用

vue2中有很多全局api可以改变vue的行为,比如Vue.component

  • vue2没有app概念, new Vue()得到的根实例被作为app, 这样的话所有创建的根实例是共享相同的全局配置,
  • 全局配置也导致没有办法在单页面创建不同全局配置的多个app实例

vue3中使用createApp返回app实例, 由它暴露一系列全局api

import { createApp, h } from 'vue'
import App from './App.vue'
import './index.css'

createApp(App)
.component('comp', {
    render() {
        return h('div', 'weqew')
    },
})
.mount('#app')
2.xGlobal3.xGlobal
Vue.configapp.config
Vue.config.productionTip废除
Vue.config.ignoredElementsapp.config.isCustomElement
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.filter废除

Global and internal APIS重构为可做摇树优化

vue2中不少global api是作为静态函数直接挂在构造函数上的, 例如Vue.nextTick(), 如果我们从未在代码中用过它们,就会形成所谓的dead code, 这类global-api造成的dead code无法使用webpack的tree-shaking排除掉

例如在vue2中

import Vue from 'vue'
Vue.nextTick(() => {
    // do something
}) 

vue3.0做了相应的变化. 将它们抽取成为独立函数, 这样打包工具的摇树优化可以将这些dead code排除掉

import {nextTick} from 'vue'
nextTick(()=>{
    // do something
})

受影响api:

  • Vue.nextTick()
  • Vue.observable
  • Vue.version
  • Vue.compile
  • Vue.set
  • Vue.delete

model选项和v-bind的sync修饰符被移除,统一为v-model参数形式

<div id="app">
 <h3>{{data}}</h3> 
 <comp v-model="data"></comp>
</div>
app.component('comp', {
 template: `
 <div @click="$emit('update:modelValue', 'new value')">
 i am comp, {{modelValue}}
 </div>
`,
 props: ['modelValue'],
})

###

lolo
12 声望0 粉丝