标签: vue3

  • 【视频教程】技术栈大升级:Vue3 到 Nuxt3(4)深入理解 SSR 和 `useAsyncData`

    【视频教程】技术栈大升级:Vue3 到 Nuxt3(4)深入理解 SSR 和 `useAsyncData`

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    这次的视频更偏理论,重点讲解 Nuxt3 如何处理 useAsyncData,以及为了兼顾 SSR 和前端开发所做的渲染策略设计。这部分知识我其实很晚才掌握,因为文档里说的也不太详细;所以既是好消息也是坏消息。好消息是,哪怕你没有掌握,也不太耽误使用 Nuxt3 开发项目;坏消息是,保不齐就会遇到一些奇怪的问题,难以复现和排错。

    视频要点:

    1. 现代化 SSR 的优势
    2. 深入理解 useAsyncData
    3. 使用 Pinia 传递数据
    4. 理解生命周期钩子变化

    如果你对 Vue3 开发、Nuxt3 开发、SSR 感兴趣,欢迎关注我的本系列。如果你对这些话题有疑问,欢迎留言讨论。

  • 【视频教程】技术栈大升级:Vue3 到 Nuxt3(2-3)升级实战 – 基础知识,适配 SSR,页面路由

    【视频教程】技术栈大升级:Vue3 到 Nuxt3(2-3)升级实战 – 基础知识,适配 SSR,页面路由

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临到很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    继上次的知识科普视频之后,我们开始实战。连续三次直播都比较失败,所以更新比较慢。第二期视频包含以下升级要点:

    1. 处理项目开发脚手架
    2. 迁移静态资源
    3. 修改引用地址
    4. 利用 process.client<client-only> 组件处理不能 SSR 的功能
    5. 处理 TailwindCSS
    6. 使用 useCookie 替代 localStorage

    第三期视频包含以下要点:

    1. 处理页面路由,理解页面嵌套
    2. 全局使用 css
    3. 附赠内容(拖时长):关于读源码

    后面应该还会再录制两期,分别是:服务器 API 开发;深入理解 SSR 与 useAsyncData+Pinia。

    如果你对 Vue3 开发、Nuxt3 开发、SSR 感兴趣,欢迎关注我的本系列。如果你对这些话题有疑问,欢迎留言讨论。

  • 【视频】技术栈大升级:Vue3 到 Nuxt3(1)基础知识篇

    【视频】技术栈大升级:Vue3 到 Nuxt3(1)基础知识篇

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临到很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    本期视频主要介绍 SSR 所需的知识和概念,为下一阶段正式重构项目做准备。

    1. 什么是 SSR?为什么要用 SSR?
    2. SSR 的一般构成
    3. Nuxt3 的 SSR 组件
    4. Nuxt3 的渲染规则与缓存处理
    5. 如何鉴别用户身份

    视频中的课件:从 SPA 到 SSR,从 Vue3 到 Nuxt3

    有任何问题、意见、建议,欢迎留言弹幕私信与我交流。如果你觉得视频对你有所帮助,还请留下宝贵的一键三连,并完播分享,谢谢。

  • Nuxt3 如何传递 Token

    Nuxt3 如何传递 Token

    昨天我在思否上看到这个问题:nuxt3 请求 token 要怎么传?我之前也被这个问题困扰过,我猜测不少刚刚从 Vue3(SPA) 转向 Nuxt3(SSR) 开发的同学也会受困于这个问题,所以就把答案扩展一下,写成博文,分享给大家。

    Vue3(SPA)里使用 Token

    在 Vue3 开发的单页应用(Single Page Applicati,SPA)里使用 Token 比较简单。一般来说,我们会在项目初始化的时候读取 localStorage,拿到标记用户身份的 token,然后放到内存当中,在请求时放到 header 里面发出。如果找不到 token,就认为用户没有登录,那么就通过路由将用户指引到登录页,或者不需要登录也能看的页面。

    使用 Token 可以避免 CSRF 攻击,因为从外部网站无法同时满足访问 localStorage,和将信息放入 http header 这两个条件。所以在单页应用里,使用 token 验证用户身份非常常见,有着各种开源、强壮、高效的实现。

    这个过程相信做过 SPA 的同学都很熟悉,不多说了。

    Nuxt3 请求的特点

    从 Vue3(SPA) 到 Nuxt3(SSR),主要涉及一个思路的转换。

    在 Vue(SPA)里,所有请求都是  请求,即完成网页加载、JS 执行完毕后,再发起请求。这些请求,有以下特点:

    1. 可以认为完全由开发者控制,即开发者确定请求发起的条件,然后在基本确定的时候发起请求。
    2. 这些请求大部分只请求数据,且有明显的特征,比如 HTTP Header 里包含 Authorization
    3. 这些请求里基本不包含静态资源。

    在 Nuxt 里,因为 SSR 的存在,所以请求至少可以分成两类:

    1. 数据交互类,跟 SPA 里基本一致。
    2. 页面渲染类,SSR 核心所在。

    后者最大的变化是:它会影响到 HTML 的内容,而通常来说,HTML 会被视作静态资源。我们知道,在网络环境里,存在大量缓存节点,假如跟用户相关的敏感数据渲染成 HTML,缓存到 CDN 当中,会是非常严重的安全问题。所以 Nuxt 在 SSR 时,不会携带 cookie;只有当页面渲染完成,由于用户操作而主动发起的请求里,才会携带 cookie。

    怎么识别 SSR 请求

    Nuxt2 时期,使用 Option API 的时候,有一个很明确的 asyncData() 函数,它会在 SSR 阶段被调用,发起请求获取数据。

    Nuxt3 时期,Composition API 会稍嫌模糊一些。这个时候,整个 setup() 函数都会在 SSR 期间执行,而 useFetchuseAsyncData 则负责在这个阶段发起请求,获取数据。因为这个阶段是在服务器的 node.js 环境里执行的,所以自然无法使用用户的 localStorage,也无法使用用户本地存储的 token。

    但是因为打开网页的请求是由用户发起的,所以其实用户有把自己的 cookie 发给服务器。如果我们希望 SSR 阶段用 cookie 鉴别用户身份,可以手动将 cookie 放在 useFetchuseAsyncData 产生的请求当中,参考 官方文档 useRequestHeaders

    基本上,假如我们不了解 Nuxt3 的设计思路,简单看了眼文档就上手写代码,大概率所有页面数据相关的请求都会是 SSR 请求。至少我是如此。

    使用 server: false 仅在网页里发起请求

    当然,Nuxt3 提供了只在网页里发起请求的方法,也就是基本等效于我们之前在 SPA 里发起请求的方法,那就是在 useFetchoptions 里标记 server: false

    const { pending, data: posts } = useFetch('/api/comments', {
    server: false
    })

    再演示个更扣题的方式

    const { pending, data: posts } = useAsyncData(
    'posts',
    async () => {
    const token = localStorage.getItem('token');
    const data = await $fetch('/api/comments', {
    headers: {
    Authorization: `Bearer ${token}`,
    },
    });
    return data;
    },
    {
    server: false,
    }
    );

    (代码高亮插件还是崩的,大家凑合看,等我回头修……)

    详情请看 官方文档

    这样的请求就会在页面完成渲染后,才会发起请求。在这些请求里,如果需要使用 token,就按照以往的方式使用,即可。

    server: falselazy: true 的区别

    如果大家仔细看 Nuxt3 官方文档,会发现还有一个参数:lazy: true,以及两个语法糖函数:useLazyFetchuseLazyAsyncData

    这两个函数也是先加载页面,再加载数据。它们与 server: false 的区别在于,后者是把全部请求都放在网页端进行;而 lazy: true 则只在网页跳转的时候起作用。

    不使用 lazy: true 的情况下,当我们从 A 页面进入 B 页面时,如果 B 页面里需要加载数据,Nuxt3 就会等待数据加载完成之后,再进行页面渲染。如果你使用一个比较慢的网络,页面切换就会卡卡的,体验非常明显。

    如果使用 lazy: true,页面切换一下就完成了,但是数据可能还没加载到,此时我们需要手动处理加载状态。比如放个转转的菊花在页面中间。但是如果我们直接打开 B 页面,Nuxt3 还是会先把数据请求回来,完成页面渲染,然后呈现完整的 HTML 给我们,这样可以确保 SEO 效果。

    server: false,则会彻底放弃这部分数据的 SSR,对于用户身份相关的数据,就比较合适。

    总结

    其实就跟当年从前端学 Node.js 一样,新技术最大的挑战在于:使用场景不同、运行环境不同,思路需要很大变化,需要不同的理解,不能照搬以前的做法。

    Nuxt3 涉及到网页渲染,涉及到网络链路上的缓存层,为了防止出现信息泄漏,它会主动放弃一些数据传输。同时,由于它的一部分运行环境在服务器上,所以有一些用户数据它没法使用。于是在开发 Nuxt3 应用的时候,我们必须搞清楚这些变化,然后作出适当的调整。

    希望上面文章对大家有所帮助。如果文中有问题,请不吝指出。如果你对 Vue3、Nuxt3 开发有兴趣,有疑问,欢迎留言评论。

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(5):部署到 Vercel+开发统计功能

    【视频】Nuxt3+Vercel+Serverless 全栈开发(5):部署到 Vercel+开发统计功能

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    https://www.bilibili.com/video/BV16h411N762/ (请 B 站有号的同学帮忙点赞)

    本次课程内容:

    • 将作品部署到 Vercel
    • 使用自定义域名保障国内访问
    • 开发统计功能页面

    终于讲到部署环节了。其实 Vercel 对现代化 Web 全栈开发是非常重要的组成部分,它自带的 Serverless 功能是实现服务器端渲染(SSR)的关键,而且我们也需要使用 Serverless 来完成数据交互。部署到 Vercel 非常简单,点几下就能完成。

    Vercel 官方网站 vercel.com 在中国大陆可以无障碍访问,但是免费提供的二级域名 *.vercel.app 不行。解决方案很简单,自己注册一个域名,然后 CNAME 过去即可。注册域名的选项很多,各大云平台如阿里云、腾讯云均可。自己的小域名如果不提供大规模服务,不备案也可以用。价格大概一年十几块吧。

    然后讲解制作统计页面,主要涉及 Redis 的操作和前后端数据交互。之前埋下的数据结构设计,在此可以更好的演示。

    至此,这个系列基本连载完成。从技术选型、到项目搭建、到前后端开发、到最终部署上线,都覆盖到了。其它想讲的内容还有很多,不过都属于锦上添花,对于有开发经验的同学来说,相信现在已经可以动手。未来当然会继续深入,把统计功能加强一些,把关系型数据库也纳入进来。进阶课也在规划中,比如面对内容更庞大的网站,这个项目中太过简单的数据交互、缓存处理、SEO 都不够用,需要进阶强化。敬请期待吧。

    本周正好端午节,休息一周,周三(6月21日)晚上直播答疑,欢迎围观。


    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    本次课程内容:

    • 创建 Post 接口,完成投票
    • 显示投票结果数据
    • 了解服务器端渲染

    我们先利用 Nuxt3 的路由机制,创建 /api/rate.post.ts 接口,用来处理用户投票,将数据记录进入 Redis 数据库的动作。

    为了保证数据安全,我每次会写入两次数据,一个键值是 $$$_{uid},主 key,用来日常显示;另一个键值是 {uid}_{小时},用来备份。这样假如某些情况下我们的投票系统被攻击,也能快速会滚到最近一小时的数据。并且这个备份频率也可以按需调整。

    然后我们在前端使用 $fetch 方法调用接口完成投票。并介绍了计算成绩的逻辑。

    最后介绍了 SSR 的结果,这样就能解释,为什么我们要使用 Nuxt3 内建的 useAsyncDatauseFetch 而不是平时常见的远程请求库手动请求。

    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube

  • 【视频】Vue3 开发扫雷游戏 Workshop 视频录像

    【视频】Vue3 开发扫雷游戏 Workshop 视频录像

    经过连续几周的奋斗,终于把这套教程做完了,共四期,从入门开始,直到在本地搭建开发环境,并使用 pinia 记录游戏成绩。所有视频都在 B 站,欢迎各位读者观看,敬请三连。

    第一期:启动项目,基础知识

    1. Vue 组件开发游乐场,免环境学开发的神器
    2. 什么是 MVVM 框架
    3. Vue3 基础
    4. 使用 display:grid 画地图
    5. 生成地雷
    6. 生成游戏地图

    第二期:组件式开发

    1. 父子组件间传递数据的方式
    2. defineEmitsdefinePropsdefineExpose 的使用
    3. 使用变量切换状态
    4. 递归变更节点状态(最后拼错了导致翻车

    第三期:游戏逻辑 => 数理逻辑

    1. 添加胜利效果
    2. 添加难度选择

    第四期:本地开发 Vite,状态管理 Pinia

    1. 总结,梳理回顾代码
    2. 修改布雷时机,让游戏更好玩
    3. 将项目迁移到本地,使用 Vite 搭建开发环境
    4. 使用 pinia 存储记录

    参考代码

    扫雷相关代码在这个仓库:meathill/minesweeper: yet another minesweeper game (github.com),欢迎学习,有任何问题均欢迎提问。目前我也时不时更新一下。

    想试玩的话这里有 DEMO


    写在第一期之后

    周日,Workshop 如期开始。有 5、6 位同学到场,出勤率 50%,还不错。

    这次 Workshop 我选择用浏览器 SFC Playground 的形式,减少环境部署的需求,希望大家集中精神在其它技术内容上。

    Vue3 开发扫雷游戏比想象中复杂,一节课讲不完,这节课的知识点有:

    1. Vue 组件开发游乐场,免环境学开发的神器
    2. 什么是 MVVM 框架
    3. Vue3 基础
    4. 使用 display:grid 画地图
    5. 生成地雷
    6. 生成游戏地图

    没有到现场的同学可以看录像,敬请一键三连:

    (视频挪到上面了)

    因为我上午清理 Sentry 的时候不小心断网,把服务器搞挂了,所以提前下播加班维护服务器,所以时间比预期要少,只有 1.5 小时。但是我觉得强度还是太大了,对我对同学来说都是。下次理想时间是讲 1 小时,分析和作业 半小时;课间休息 10 分钟。

    不出意外的话,本周日下午 3 点继续,欢迎听过的没听过的同学一起来参加。没来过的同学可以加我微信:wakabanga。

    布置一个作业:我计算每个砖块四周有几个炸弹的算法,可以优化。提出你的优化点并实现它,发给我,我就送你一本技术类书籍。大家都来试试吧。

  • 免费线上讲习班:使用 vue3 开发扫雷游戏

    免费线上讲习班:使用 vue3 开发扫雷游戏

    【2022-09-03 更新】把游戏先做出来了,以后可以扫自己的雷了:meathill/minesweeper: yet another minesweeper game (github.com)

    不过也发现,一次 workshop 肯定讲不完,考虑到现场的情况、各位同学的状态,估计初版开发要两次课。于是我干脆把后面的 Workshop 也规划出来了。


    好了伤疤忘了痛,我又想搞 Workshop 了。这次想做一次 Vue3 相关的,考虑了一下,觉得扫雷游戏比较合适:

    1. 界面简单,操作简单
    2. 覆盖全面,布局、JS、交互都有需求
    3. 不需要前后端数据交互,控制学习范围和难度
    4. 本身有一定可玩性

    可以学到的知识技能

    1. Vue3 开发应用
    2. Vue3 组件式开发
    3. CSS 高级用法
      1. CSS 布局
      2. CSS grid
      3. CSS 变量
    4. vite 脚手架

    难度

    • 中低难度
    • 逻辑较简单
    • 纯前端,无后端,无数据交互
    • 不需要开发环境,在浏览器里完成编码

    预备知识

    • HTML、CSS、JS 的基本语法
    • Vue 的基本用法

    开始时间

    (暂定)2022-09-18(周日)下午 3~5点

    报名方式

    微信直接找我口头报名即可。未加我微信的同学,请扫码

    参与方式

    我会把所有报名的同学拉到一个群里。workshop 开始时,我会创建一个腾讯会议,然后把会议链接发到群里,大家通过链接进入参加。

    事先准备

    Workshop 强调参与,不建议大家只是看,所以最好提前做一些准备:

    1. 一台支持浏览器的设备,最好是电脑
      • 可以的话,最好多准备一台设备,可以边看边敲
    2. 现代化浏览器,推荐 Edge
    3. 提前打开 sfc.vuejs.org
    4. 自行熟悉扫雷游戏
    5. 最好实现了解网页开发,HTML+CSS+JS

    欢迎报名。达到两位或两位以上同学报名,就按时开始。已达到启动标准,我开始准备了。

    我会同步开启直播,有兴趣但无法参加 workshop 的同学可以到我的直播间观看:https://live.bilibili.com/5126601


    什么是 Workshop(讲习班)

    Workshop,中文叫讲习班,工作坊。大概方式是:

    1. 由讲师讲解一些技术知识点
    2. 其他参与者针对讲过的技术知识点做现场演练
    3. 讲师及时答疑、讲解
    4. 考虑到时间因素,一般针对一些小专题,非系统性的培训

    与直播不同,直播是讲师一个人说+做,workshop 则强调给大家一个现场练习与答疑的机会。

  • 复盘 mywordle.org

    复盘 mywordle.org

    去年,有位开发者设计了一个填字游戏 wordle,取得了巨大的成功,最后被纽约时报斥资百万收购。就像众多成功产品一样,wordle 也有很多追随者和模仿者,其中就包括我们做的 mywordle.org

    刚上线时,因为优化得当,排名不错;如今,随着 wordle 游戏的关注度消退,这个产品已经趋于平静,访问量跌入谷底。于是写篇文章总结下技术、产品、运营方面的经验得失。

    技术向

    技术栈

    之前发过笔记:使用 Vite+Vue3+TypeScript+Tailwind CSS 开发 Wordle

    • Vue3 + Vue-router + Vuex
    • Vite
    • TypeScript
    • TailwindCSS
    • 骨架屏
    • nginx
    • i18n (编辑本地 json)
    • PWA

    纯静态页面,通过构建脚本一次性发布,后面就不需要服务器运算,只需要 CDN,运维成本很低,容易扩展。

    前端通过适当的分包实现按需加载,加快打开速度,提升用户体验。实际效果不错,搜索排名和留存都相当好。Lighthouse 一度基本满分。

    挑战0:全新技术栈

    项目启动时,Vite、Vue3、TypeScript 的内容不算很多,技术生态也没有完全适配,花了不少时间去学习。不过好在当时有时间,慢慢也捋顺了,虽然有一些问题到今天也没能妥善解决,但并没有影响整体进度。

    挑战1:多语言多模式共存

    当时存在两个模式:

    • hourly,每小时一个词
    • unlimited,随便玩

    以及十几种语言。因为我们是静态网站,想实现 /:lang/:type 和 /:type/:lang 共存,就要同时打包这么多组目录组合。如果将来又增加其它类型,就还要成倍增加。但是几个目录里的内容又是完全一样的,很浪费。

    现在想想,应该通过 nginx 来解决这个问题,不要放在前端构建脚本端。

    挑战2:WebRTC

    我们准备尝试用 WebRTC 实现多人对战,如果能成的话,将来还有很多应用场景。可惜 WebRTC 比我想象中复杂很多,不是抽点时间看看文档就能搞定的。当时我已经开始在 code.fun 的全职工作,时间不如启动时充足。

    于是此功能最终停留在 demo,未能整合进产品,更别提上线。

    未解决问题

    • import 类型的时候必须 import type { xxx } from '@/some/types',经常出错
    • TailwindCSS 添加新样式时无法即时生效,需要等下一次更新,或者手动刷新页面
    • ESLint 有很多误报,主要是 <script setup> 导致的未使用变量问题

    产品/运营向

    原始版 wordle 一天只能猜一次,一个词。很多玩家感觉不过瘾,所以搜索 wordle unlimited 就很多,我们也是那会儿做好,然后优化得当,排名很靠前,Google 前4(最好前3),吃了不少流量。

    但是很快,wordle unlimited 的搜索量就下降了,到现在跌了90%,只有一成。

    这是流量统计,外国人也是上班摸鱼,周末不玩页游 [Facepalm]

    这部分流量流去了 quodle 关键词,还是这个猜词游戏,但是一次猜 4 个词,更考验技巧和统筹能力。

    有趣的是,quodle 主流分两个模式:daily 和 practice。daily 还是一天一次,用的是高频词,比较好猜;practice 相当于我们做的 unlimited,不限次数,但是,用的是全部词库,几乎猜不到。

    本来有两个方向,quodle 和 pvp,我说服朋友搞 pvp:我说 quodle 这种玩法太硬核了,没人爱玩;pvp 用 WebRTC 搞联机,成本低效果好,用户粘性大。结果还是我的锅,以前没搞过 WebRTC,搞了两周没搞出来,工作一忙就扔掉了……

    总结,wordle 是个比较轻量的游戏,玩法简单,可玩性有限。daily 模式可能更合适;unlimited 有些饮鸩止渴,快速消耗掉了玩家的热情。quodle 的开发者注意到这一点,一方面提供新的玩法刺激用户,另一方面利用全量词库难以游戏的特点尽量将玩家留在每天一次的游戏里。

    总结

    从这个项目中,我学到很多技术之外的知识,产品和运营方面都刷新了我的知识边界、扩展了我的视野,很有意思。

    比如,mywordle.org 是纯静态网站,运维只需要 CDN,加上优化得当,费用很低。凭借早发优势和一些 SEO,流量和广告收入都不错。即使以我的工资标准和开发习惯(动不动重构、选择新技术栈,等)来支付开发费用,也能达到不错的收益结果(目前折算 1/3 吧)。后期收入虽低,但很稳定,也不需要继续投入研发成本,而且还能作为高质量搜索导入来源。以后我应该多做几个类似的网站。

    项目启动时,我刚被金山开除,于是可以投入大量的时间去学习使用没接触过的技术栈;后面开始继续全职工作了,就只有一点时间可以支配,以至于 WebRTC 都没能用上。不知道将来还有没有类似的机会——我的心情很矛盾,既希望有,又希望没有,哈哈。

  • 理解 Vue3 里的 defineProps 和 defineEmits

    理解 Vue3 里的 defineProps 和 defineEmits

    大家请先看这个问题:https://segmentfault.com/q/1010000041497872/a-1020000041498716,看看你们能不能给出答案。

    Vue3 增加了 Composition API,是一个很大的改进。一方面可以提升代码复用效率,另一方面通过更好的 tree-shaking,打包体积也会小很多:作为参考,前面博客中提到 mywordle.org,打包后 vendor.js 只有区区 96kB,里面可是用到了 vue3 全家桶。

    最初的 Composition API 是在 Options API 基础上改进的,不仅需要使用 setup() 函数,还要在 setup() 末尾返回所有模版需要用到的变量和函数,使用起来相当繁琐。于是后面就增加了 <script setup> 语法糖:

    1. 从生命周期来讲,相当于 created
    2. 支持顶层 await(因为实际上这还是个 setup() 函数)
    3. 所有 import 的内容、声明的变量和函数默认都返回
    4. 至少省了两层缩进

    但是由于少了 export,没法传参,也不方便暴露接口,所以作者就增加了三个工具方法:

    • defineProps
    • defineEmits
    • defineExpose

    注意,这三个工具方法只是帮助 Vue 编译器构建组件,它们不会出现在最终代码里,我们也不能预期它们会像普通函数那样工作。比如下面这段代码,就得不到常见的结果:

    const props = defineProps({
      userMenu: {
        type: Array,
        default() {
          return []
        }
      }
    })
    console.log(props) // 该对象中的 userName 总是有值
    console.log(props.userMenu) // 该对象始终是一个空数据

    因为 Vue 是 MVVM 框架,它的视图会在数据变化后自动渲染,于是通常情况下,props 里的值什么时候被填充并不重要,Vue 开发团队也不想追求 defineProps 工作的一般化。所以使用目前版本,上面这段代码,访问到的 props 是的 reactive 对象,数据被填充后就能看到 userName 里有值;而 props.userMenu 在访问时还没有被填充,所以得到的是 default() 返回的默认值,一直是空的。

    同时大家还要知道,console.log() 输出的是对象的指针,而非快照。所以里面的值只跟你展开时有关,跟运行时关系不大。