Vue3.2的官方文档
Young村长B站视频

升级 Vue3.2

  • 升级 node,到 14 以上吧,安装下 vite,然后运行 npm init @vitejs/app 然后一路选择 vue 或 vue-ts,如果要用 ts 的话

  • 现有 Vue 项目升级 3.2 版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    npm i vue // 升级到 3.2
    npm i @vue/compiler-sfc -D // 满足 Vite 工具对 SFC(就是平常所说的 .vue 文件) 的编译需求

    // 升级后查看 package.json 配置信息
    "dependencies": {
    "vue": "^3.2.20"
    },
    "devDependencies": {
    "@vue/compiler-sfc": "^3.2.20",
    "vite": "^1.0.0-rc.13"
    }

Vue3.2 新特性

  • script setup 写法升级

    • 废除 useContext,其功能被新增 API 替代了
    • 新增 defineExpose,暴露接口供外界使用,不需要导入,在代码中直接用
      1
      2
      3
      4
      5
      defineExpose({
      someMethos() {
      console.log("Some message from HelloWorld");
      }
      })
    • 定义属性 defineProps (定义输入)、事件 defineEmits (定义输出)
      1
      2
      3
      4
      5
      6
      7
      // 均不再需要导入
      defineProps({
      msg: String,
      })

      const emit = defineEmits(["my-click"]);
      emit('my-click');
    • 插槽信息和属性信息,新增 useSlots 和 useAttrs
      1
      2
      3
      4
      import { useAttrs, useSlots } from "vue"; // 用 use 开头的是需要明确引入的

      console.log(useAttrs()); // 输出组件的非属性信息
      console.log(useSlots()); // 输出组件的插槽信息
  • Web Components 应用
    在 vite + vue3 项目中使用 web components 需要三步:

    1. 定义 web components,main.js
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      import { defineCustomElement, h } from 'vue';
      // 返回值是构造函数
      const MyVueElement = defineCustomElement({
      // 通用 vue 组件选项
      props: ["foo"],
      render() {
      return h("div", "my-vue-element:" + this.foo);
      },
      // 仅适用于 defineCustomElement: CSS 将被注入到 shadow root
      styles: [`div { border: 1px solid green }`],
      })
    2. 注册 web components,main.js
      1
      customElements.define("my-vue-element", MyVueElement); // 定义这个后意味着浏览器会接管 my-vue-element 这个元素,浏览器接管,Vue 就要取消接管,进行步骤三
    3. 配置 vite 自定义组件白名单,vite.config.js
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      export default defineConfig({
      plugins: [
      vue({
      template: {
      compilerOptions: {
      // vue 将跳过 my-vue-element 解析
      isCustomElement: (tag) => tag === "my-vue-element",
      }
      }
      })
      ]
      })

      使用 web components:跟 vue 组件并没有什么区别

      1
      <my-vue-element foo="foo"></my-vue-element>
  • 服务端渲染
    @vue/server-renderer 包提供一个 ES 模块创建,并与 node.js 解耦,这样有可能让服务端可以运行在不是 node 的环境中
    验证一下, main.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { createSSRApp } from "vue";
    // 2、安装 @vue/server-renderer 库,npm i @vue/server-renderer -S
    import { renderToString } from "@vue/server-renderer";

    // 1、创建一个 SSR 应用程序实例
    const app = createSSRApp({
    data: () => ({ msg: "白醭飙尘" }),
    render() {
    return h('div', this.msg)
    }
    })

    // renderToString 返回一个 promise,用 async 方式去写
    (async () => {
    // 3、把 SSR 实例渲染成一个 html 字符串,前端就可以把这个字符串设置成某个页面内容的 innerHTML 显示出来,这样就完成了服务端渲染
    const html = await renderToString(app);
    console.log(html);
    })();

    注:npm i -S 等同于 npm i –save, 在运行命令的目录中下载指定的包到 node_modules, 如果 package.json 存在的话, 同时写入到 package.json 的 dependencies 字段;
    npm i -D 等同于 npm i –save-dev, 在运行命令的目录中下载指定的包到 node_modules, 如果 package.json 存在的话, 同时写入到 package.json 的 devDependencies 字段。

  • Effect Scope API
    新的 Effect Scope API 可以直接控制响应式副作用的释放时间,在用到响应式时,可能会有副作用耗内存,影响性能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import { watch, watchEffect } from "@vue/runtime-core";
    import { effectScope, computed, ref } from "@vue/reactivity";

    const counter = ref(1)
    setInterval(() => {
    counter.value++
    }, 1000);

    // 创建一个 scope 作用域
    const scope = effectScope()

    // 通过 scope.run() 将其中执行的代码产生的副作用进行收集,比如每隔一秒计算 couter 在计算属性中占用内存
    scope.run(() => {
    const doubled = computed(() => counter.value * 2)
    watch(doubled, () => console.log(doubled.value))
    watchEffect(() => console.log('Count: ', doubled.value))
    })

    // 把 scope 中的所有副作用一次性全部释放
    setTimeout(() => {
    scope.stop()
    }, 5000);