• 路由的变化
    • 路由的使用
    • 路由的history
      • createMemoryHistory
      • createWebHashHistory
      • createWebHistory
  • 组件的变化
    • 异步组件
      • render函数
      • 异步页面
    • 内置Teleport组件

路由的变化

  • 安装
    1. # 在Vue3要安装路由时使用
    2. npm i vue-router@next
    3. yarn add vue-router@next

    路由的使用

    Vue2中使用路由的方法如下:
    1. import VueRouter from 'vue-router'
    Vue3中使用路由的方法如下: ```javascript // src/router/index.js import {createRouter} from ‘vue-router’

// main.js import router from ‘./router’ createApp(App).use(router).mount(‘#app’)

  1. <a name="cbi2T"></a>
  2. #### 路由的history
  3. 在原来Vue2中,路由中原来模式的用法
  4. ```javascript
  5. const router = new VueRouter({
  6. mode: 'history', // hash
  7. routes: [...]
  8. })

而在Vue3的路由中则新增了三个函数

  • createMemoryHistory
  • createWebHashHistory
  • createWebHistory
    1. import { createRouter, createWebHistory } from 'vue-router'
    2. export default createRouter({
    3. history: createWebHistory(),
    4. routes: [...]
    5. })

组件的变化

在Vue3中使用异步组件的方法和Vue2有所不同。Vue3中新增了一个defineAsyncComponent方法来返回一个异步组件。

  • 基本用法。将回调函数传入defineAsyncComponent方法,并返回一个import语句。

    1. import { defineAsyncComponent} from 'vue'
    2. const Block = defineAsyncComponent(() => import('../components/Block.vue')) // Block就是一个异步的组件

    这里回调函数返回的是一个Promise对象。

  • 对于进阶用法。defineAsyncComponent也可以接受一个对象(具体见官方文档)。

    1. defineAsyncComponent({
    2. loader: () => import(path),
    3. loadingComponent: Loading,
    4. errorComponent: MyError
    5. })

    其中,loader是一个函数,返回一个通过import导入组件的对象。
    loadingComponent是加载时要显示的组件。
    errorComponent是当抛出错误时要显示的组件。

这里看另一种写法:

  1. defineAsyncComponent({
  2. loader: () => import(path),
  3. loadingComponent: Loading,
  4. errorComponent: {
  5. render(h) {
  6. return h(Comp, 'error')
  7. }
  8. }
  9. })

在Vue2中,render函数会有h的形参。但是在Vue3中,则将h函数从参数中去除,而是通过import {h} from 'vue'导入并使用。所以上述代码会报错,正确的使用应该如下

  1. import { defineAsyncComponent, h } from 'vue'
  2. defineAsyncComponent({
  3. loader: () => import(path),
  4. loadingComponent: Loading,
  5. errorComponent: {
  6. render() {
  7. return h(Comp, 'error')
  8. }
  9. }
  10. })

一个组件可以进行异步加载,那么页面是否也可以异步加载呢?这是可以的,页面其实也是组件。但是在router中,页面的组件是这样使用的。

  1. import Home from '../views/Home.vue'
  2. import About from '../views/About.vue'
  3. const routes = [
  4. {
  5. path: '/',
  6. component: Home
  7. },
  8. {
  9. path: '/about',
  10. component: About
  11. },
  12. ]

这样的页面组件还是同步的,在这段代码中,先将需要的组件import,然后将其放到router中。那么既然异步组件是通过defineAsyncComponent包装后变为异步组件,那么页面组件也同样使用同样的方法包装后成为异步的页面组件。

  1. const Home = getAsyncPage('../views/Home.vue')
  2. const About = getAsyncPage('../views/About.vue')

这里getAsyncPage(path)是一个封装好的方法,接受一个path(组件路径)并返回一个包装好的异步组件。这样就将页面组件也转为了异步的页面组件。

  1. /**
  2. * 生产异步页面
  3. * @param {String} path 组件路径
  4. */
  5. export function getAsyncPage (path) {
  6. return defineAsyncComponent({
  7. loader: async () => {
  8. NPorgress.start()
  9. await delay(500)
  10. const comp = await import(path)
  11. NPorgress.done()
  12. return comp
  13. },
  14. loadingComponent: Loading, // 当Promise在pendding时显示的组件。
  15. })
  16. }

Teleport组件

在日常模态框的功能中,模态框组件一般都是和模态框相关的逻辑放在一起。但是这就造成了在HTML结构中,模态框相关的节点是放在相应的节点周围。
但是在模态框在HTML结构中,应该作为body的直接子元素。在Vue3中提供了一个内置组件Teleport,提供了一个to属性。to属性接受一个css选择器(如#app,body,.class)。

  1. <Teleport to="body">
  2. <Modal></Modal>
  3. </Teleport>

将Modal组件包裹在Teleport中,通过to指定body,就达到了尽管在vue组件中modal和相关逻辑在一起,但是在最终HTML结构中,modal放在了body的子结点上。