专注前端开发,每年100集免费视频。
首页/视频教程/ Vue3.x+TypeScript 基础课程-2020 年新版/
Vue3.x+TypeScript 基础课程-2020 年新版
2020-09-26 视频教程 1924011

Vue3视频教程 终于 Vue3 的正式版发布了,两年多的开发,99 位贡献者的努力 ,2600 次提交 628 次 PR。凝聚了这么多优秀开发者的智慧和努力,注定 Vue3 会成为下一个前端主流开发框架。这篇文章说是教程,但更多的是我的学习过程。因为 Vue3 刚出没几天,谁也不敢说自己就是这个领域的大神(除了尤雨溪以外)。

前端就是这样,要时刻保持学习,每个月都有新技术的产生。如果每个知识都学,显然不现实,所以也要有选择性的学习。但无论如何 Vue3 都是目前最值得一学的前端框架。

有的小伙伴这时候会说,我们公司还没开始使用,可以先不学。确实是这样,我们公司也没有使用,但无论什么技术的产生都会有个过程,这个过程中有一个阶段是可以充分享受技术红利的。你现在学,无论技术红利什么时候到来,你都可以从容的抓住技术红利期,获得最大的收益。

所以建议你还是每天花点时间,跟着技术胖一期学习。每天也就十几分钟,不会给你太大的压力。

如果你缺少学习的伙伴,可以扫码加入 QQ 群和上千小伙伴一起学习。QQ 群号:273225311

01.课程介绍和 Vue3 简介

在 2020 年 9 月 19 日 Vue3 更新了 正式版本,正式版本一出,代表着不会再有太大的改动了,也意味着你可以开始学习了。我个人觉的大家跟着我的步伐学习就可以了,不用太着急。因为这个技术的应用和大面积普及,至少还会有 4-5 个月时间。你跟着技术胖一点点学,是完全够用的。我们也尽量保持一周 4-5 集的更新。

现在就给大家交个实地:此套课程会是个系列课程,从基础到实战都会有所涉及,用心学习可完全达到工作水平,而且完全免费(没套路更轻松)。

当然我也真诚希望你能在留言区或者 QQ 群指出我文章的错误(Vue3 刚出,我也个初学者),也感谢大家的包容,让我们一起完成这个 Vue3 的教程。如果你提出了宝贵的意见,并且我采纳了,你的名字就会出现在下方的贡献者名单中。(谢谢大家的支持)

此教程贡献者

技术胖 ,

课程的前置知识

虽然几乎是零基础的教学,但是还是对你有一些奢望的,如果会学习这门课程会简单很多。

  1. 希望你会 TypeScript,本套课程会全程使用 TS 的语法来编写程序。如果不会,技术胖有完全免费的视频课程,地址:TypeScript 从入门到精通图文视频教程-2020 年新版

  2. 希望你做过或者有 Vue2 的基础就更好了。如果不会,技术胖有完全免免费的视频课程:Vue2.x 学习路线

  3. 希望你会基本的 npm 或者 yarn 的包管理应用。对不起,这个专门的课程我还没出,但课程中我会详细讲解。

你说我就是都不会,能不能学这个课程。也能,但是你可能要多动手和多听两边视频,我尽量会站在一个初学者的角度来讲这些内容。

夸一夸 Vue3 的一些新特性

必须要夸一夸 Vue3,它真实可谓“千呼万唤使出来”,听说是尤大神每天抱着孩子完成的。故事已经不能说明 Vue3 的伟大了,我们用下面一组数字来了解一下 Vue3.

Vue3:两年开发,99 位程序员成为贡献者,2600 次提交,628 次 PR

这些数字可以看出 Vue3 的工作量之大,我在一年前就开始关注 Vue3 的开发进展,虽然没能力成为 Vue3 的贡献者之一,但是我热爱的心不可否认。

官方网站地址: v3.vuejs.org

那我们这节课先来了解一下 Vue3 让人惊艳的一些新特性啊。

Vue3新特性

  • 首先是向下兼容,Vue3 支持大多数 Vue2 的特性。我们同事甚至开玩笑说,我就拿 Vue2 的语法开发 Vue3,也是没有任何问题的。

  • 性能的提升,每个人都希望使用的框架更快,更轻。Vue3 做到了,给开发者一个极致的体验。官方网站给出的数据是:打包大小减少 41%,初次渲染快 55%,更新快 133%,内存使用减少 54%(惊艳到的请把惊艳两个字打到公屏上)。

  • 新推出的Composition API ,在 Vue2 中遇到的问题就是复杂组件的代码变的非常麻烦,甚至不可维护。说白了就是封装不好,重用不畅。这个Composition API一推出,立马解决了这个问题,本套课程中也会重点介绍这部分内容。它是一系列 API 的合集。

  • 其他新特性:Teleport(瞬移组件)、Suspense(解决异步加载组件问题)和全局 API 的修改和优化。

  • 更好TypeScript支持,我以前在开发 Vue2 的时候,是不适用TypeScript的,因为集成时很困难,疼点太多。但 Vue3 解决了这个问题,Vue3 的源代码就是使用TypeScript进行开发的。所以在新的版本上使用TS也更加顺畅无阻。

这些就是 Vue3 的大部分新特性了,如果你更感兴趣,可以到 B 站去看一下尤大的发布会视频。

B 站 Vue3 发布会视频:https://www.bilibili.com/video/BV1iA411J7cA?from=search&seid=2979047174353974296

好了,这节课先到这里,下届我们用vue-cli配置 Vue3 的开发环境。

02.vue-cli 搭建 Vue3 开发环境

我相信小伙伴已经摩拳擦掌,迫不及待的去创建一个 Vue3 的项目了。你可能会认为创建 Vue3 的项目非常麻烦,如果你自己动手作确实非常麻烦。官方非常贴心的准备了项目创建工具vue-cli

安装 Vue-cli

Vue-cli :Vue.js 开发的标准工具 , 新版的 vue-cli 还提供了图形界面,如果你对命令行陌生,也可以使用图形界面。

简单理解Vue-cli的作用就是能够让你省去复杂的项目配置过程,快速生成标准化的 Vue 开发环境。

安装:

npm install -g @vue/cli
# OR
yarn global add @vue/cli

建议使用npm进行安装,而且要做全局安装。因为我在使用yarn进行安装后,也可以安装成功,但是安装完成不能使用vue命令。

安装时间两分钟左右,安装完成会有success的提示。

如果你以前安装过,需要检查一下版本,升级到最新版本,因为只有最新版本(V4.5.4 以上版本)才有创建 Vue3 的选项。

//检查版本命令为:

vue --version

这时候可以展示出类似这样的版本信息@vue/cli 4.5.6。如果你的版本低于这个,可以再使用npm install -g @vue/cli来进行安装。

使用 vue-cli 命令行创建项目

通过 9 步对话式的询问,你就可以轻松的创建一个 Vue3 项目。

这里我先用命令行的方式创建一个Vue3项目,直接在命令行中输入vue create vue3-1,输入完成后,他会有这样一句询问。

Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n)

意思是你不能科学上网,建议你使用淘宝源,这时候你需要选择Y,也就是使用淘宝源进行创建。如果你已经配置淘宝源不会显示这个选项。

当你选择Y之后,就会跳出三个菜单让你选择。

? Please pick a preset: (Use arrow keys)            //请选择预选项
> Default ([Vue 2] babel, eslint)                   //使用Vue2默认模板进行创建
  Default (Vue 3 Preview) ([Vue 3] babel, eslint)   //使用Vue3默认模板进行创建
  Manually select features                          //手动选择(自定义)的意思

因为你要使用TypeScript进行开发 Vue3 的代码,所以不能直接使用第二项默认模板,这时候我们选择第三项手动选择。选择的时候按回车就可以实现。(如果这时候你没有上面的三个选项,说明的 vue-cli 是旧版本,需要你更新。)

这时候就会出现很多可插拔的选项让你自定义选择:

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Choose Vue version
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 ( ) CSS Pre-processors             //CSS预处理器
 (*) Linter / Formatter             //格式化工具
 ( ) Unit Testing                   //单元测试
 ( ) E2E Testing                    //E2E测试

这里我们需要再多选一个TypeScript的选项,然后再按回车进入下一层选择。

? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
> 2.x
  3.x (Preview)

这里要选择 3.x 的版本,点击回车,然后会提示你是否需要使用class-style,教学中旧不使用这个类样式语法了,所以我们选择n

 Use class-style component syntax?

然后会出现下面的选项 ,意思是否使用TypeScriptBabel的形式编译 JSX.这里我们也选择n

Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n)

然后会出现ESLint的一些配置,这里我们选择第一项,默认就好,因为下面这些规则并不是这个课程的重点。

? Pick a linter / formatter config: (Use arrow keys)
> ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
  TSLint (deprecated)

回车后会让你选择增加lint的特性功能。

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Lint on save         //保存的时候进行Lint
 ( ) Lint and fix on commit   //需要帮你进行fix(修理),这项我们不进行选择

回车后让你选择这些配置文件时单独存放,还是直接存放在package.json文件里。这里选择放在单独的文件里。

Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files

最后一个问题,是问你需不需要把这些配置保存下来,下次好直接进行使用。我这里选择不用(n)。淡然你可以自行选择

Save this as a preset for future projects? (y/N)

如果你同时安装了npmyarn来个包管理软件,它还会作最后一次询问,让你选择使用什么进行下载。

? Pick the package manager to use when installing dependencies:
> Use Yarn
  Use NPM

我选择了yarn进行安装,也可能是心里问题,我老觉的 yarn 更快一些,我这里只用了 10 几秒就完成了下载和构建。 出现下面的信息,说明我们已经安装完成了。

Done in 10.33s.


 $ cd vue3-1
 $ yarn serve

根据提示在命令行输入cd vue3-1进入项目,然后再输入yarn serve开启项目预览。这时候就会给出两个地址,都可以访问到现在的项目.

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.0.118:8080/

  Note that the development build is not optimized.
  To create a production build, run yarn build.

把地址放到浏览器的地址栏,如果看到下面的页面,说明安装正常了。 https://newimg.jspang.com/Vue3-2-1.png

03.用 vue-cli 图形界面搭建 Vue3 环境

上节你已经能用命令行或者说终端配合Vue-cli构建 Vue3 的项目了,这节看一下Vue-cli如何用图形界面构建项目。因为是图形界面,所以代码很少,多是界面。本节课程强烈推荐看视频学习。

启动 Vue-cli 中的图形界面

当你安装了最新版的Vue-cli就可以使用 vue ui这个命令,开启一个 UI 界面,然后会出现下面的提示。

Starting GUI.
Ready on http://localhost:80

出现提示后,把http://localhost:80地址拷贝到浏览器地址栏中,就会出现下面的界面。

Vue3

这时候点击创建按钮,然后选择页面下方的在此处创建新项目。这时候会让你输入项目名称和包管理器。我再这里输入了vue3-2,并使用了yarn作为管理器。

Vue3

可以点击下一步了,之后会让你选择预设模板,这里选择手动。 Vue3

之后就和命令行基本一样了,根据自己的项目来进行配置。(视频中会作详细的演示) Vue3

这不完成后,可以选择“创建项目”,然后弹出提示,问是不是保存这个配置,这里依然是不保存。

Vue3

这时候如果你注意VSCode中的终端,会发现它开始为我们构建项目。大概一分钟左右,会跳出下面的页面,说明项目已经构建完成。 Vue3

这时候再回到 VSCode 的终端中,进入项目cd vue3-2,然后启动服务npm serve,等到服务启动后在浏览器地址栏输入http://localhost:8080/,就可以看到下面的界面了。

https://newimg.jspang.com/Vue3-2-1.png

看到这个界面,正面你的 Vue3+TypeScript 项目已经创建好了。下节课学习一下里边的基本结构。

04. 项目初始结构和重要文件讲解

这节主要讲一下用Vue-cli构建好项目后,最初始的文件结构是怎么样的?我们需要由一个最基本的了解,只有了解后才能进行开发。

项目基本目录讲解

以一个目录树状结构进行展示。后边的作用我也写到了下面

|-node_modules       -- 所有的项目依赖包都放在这个目录下
|-public             -- 公共文件夹
---|favicon.ico      -- 网站的显示图标
---|index.html       -- 入口的html文件
|-src                -- 源文件目录,编写的代码基本都在这个目录下
---|assets           -- 放置静态文件的目录,比如logo.pn就放在这里
---|components       -- Vue的组件文件,自定义的组件都会放到这
---|App.vue          -- 根组件,这个在Vue2中也有
---|main.ts          -- 入口文件,因为采用了TypeScript所以是ts结尾
---|shims-vue.d.ts   -- 类文件(也叫定义文件),因为.vue结尾的文件在ts中不认可,所以要有定义文件
|-.browserslistrc    -- 在不同前端工具之间公用目标浏览器和node版本的配置文件,作用是设置兼容性
|-.eslintrc.js       -- Eslint的配置文件,不用作过多介绍
|-.gitignore         -- 用来配置那些文件不归git管理
|-package.json       -- 命令配置和包管理文件
|-README.md          -- 项目的说明文件,使用markdown语法进行编写
|-tsconfig.json      -- 关于TypoScript的配置文件
|-yarn.lock          -- 使用yarn后自动生成的文件,由Yarn管理,安装yarn包时的重要信息存储到yarn.lock文件中

这就是基本目录结构和用处了,你可以在表中自查。

package.json 中的三条命令

上两节课你可以使用npm run serveyarn serve查看项目效果,就是因为有package.json中的scripts起到了作用。先来看一下这三条命令。

{
  //----
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  //----
}

能使用vue-cli-service是因为vue-cli自动安装了cli-service这个工具,此处可以在devDependencies中看出哦。

这三个命令的意思是:

  • serve : 在开发时用于查看效果的命令,视频中演示看一下效果
  • build : 打包打码,一般用于生产环境中使用
  • lint : 检查代码中的编写规范

我们顺便讲一下package.json中另外两个比较重要的配置项dependenciesdevDependencies。这两个都是用来记录安装包信息的,但如果要想完全搞清楚他们的区别,你先要弄清楚什么是开发环境和生产环境。

  • 开发环境: 作为一个程序员,每天作的事情都是在开发环境中,编写代码、测试代码、修改 Bug。也就说这些代码没有上线。

  • 生产环境:就是代码已经上线,放到了正式的服务器上,公司开始运营去赚钱的代码。

明白了这两个概念后,dependencies下的包是生产环境中必须用到的,当然开发环境也需要。devDependencies是只有开发环境中使用的,上线后这些包就没用了,打包后也不会打包进去的代码。

从 main.ts 文件讲起

项目里边还有一个非常重要的文件main.ts文件,你可以把它叫做入口文件,这里边只有简单的三行代码。

import { createApp } from "vue"; // 引入vue文件,并导出`createApp`
import App from "./App.vue"; // 引入自定义组件,你在页面上看的东西基本都在这个组件里

createApp(App).mount("#app"); // 把App挂载到#app节点上,在public目录下的index.html找节点

顺着这个线索你可以找到App.vue这个组件,打开这个组件,看到里边的内容还是很多的,甚至你可能还有些东西看不明白。

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from './components/HelloWorld.vue';

export default defineComponent({
  name: 'App',
  components: {
    HelloWorld
  }
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

在这个根组件里模板、vue 的 js 业务逻辑代码和 css 代码。在业务逻辑代码中,你可以看到引入了一个HelloWorld.vue的自定义组件。

这个自定义组件里边就是放了一些链接和模板用的 html 代码了,可以试着删除一些 html 代码,然后查看效果。

05. setup()和 ref()函数制作大宝剑点餐

这节课你要通过一个简单的大宝剑点餐流程,初步了解一下 Vue3 中 Ref 的魅力。这个点餐很简单,所以你学习的时候不要有任何的压力。 如果你真的听起来非常难,请一定在听过之后动手敲一下这段代码,你会有更深的领悟。

### 清理无用的代码

在用vue-cli生产的 Vue3 项目中,有一些默认的代码,为了方便学习,这些代码需要清理掉无用的代码。

打开根组件App.vue文件,去掉HelloWorld自定义组件相关代码。

<template>
  <img alt="Vue logo" src="./assets/logo.png" />

</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "App",
  components: {},
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

这时候再进行浏览就没有其他的元素了,只剩下一个Vue的图标。就可以继续开发啦。这时候你可以在终端中运行yarn serve,在浏览器中预览一下效果。

编写红浪漫服务程序

App.vue里添加如下代码,我先修改了template,增加了两行代码和一个按钮。

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
    <div>请选择一位美女为你服务</div>
  </div>
  <div>
    <button> </button>
  </div>
</template>

然后我开始改写<script>部分,使用setup()新语法,写了这个就不需要再写data这样的东西了。然后在setup中加入一个girls变量,为了能让模板中进行使用,还需要返回。(有的小伙伴此时可能会感觉有点复杂,没有 Vue2 直接写 data 那么直观,但这正式 Vue3 的先进之处,不用暴漏在界面中的变量就可以不进行返回了。精确控制那些方法和变量被导出和使用)。

<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
  name: "App",
  setup() {
    const girls = ref(["大脚", "刘英", "晓红"]);
    return {
      girls
    };
  },
});
</script>

写完后可以把这三个美女用按钮的形式展示在页面上,这里使用v-for语法。代码如下:

<button v-for="(item, index) in girls" v-bind:key="index">
  {{ index }} : {{ item }}
</button>

现在要实现的就是当我们点击按钮的时候,触发一个方法selectGirlFun,方法绑定一个选定值selectGirl,具体实现代码如下。

<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
  name: "App",
  setup() {
    const girls = ref(["大脚", "刘英", "晓红"]);
    const selectGirl = ref("");
    const selectGirlFun = (index: number) => {
      selectGirl.value = girls.value[index];
    };
    //因为在模板中这些变量和方法都需要条用,所以需要return出去。
    return {
      girls,
      selectGirl,
      selectGirlFun,
    };
  },
});
</script>

修改template代码,为Button绑定selectGirlFun事件,实现联动效果。

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
    <div>请选择一位美女为你服务</div>
  </div>
  <div>
    <button
      v-for="(item, index) in girls"
      v-bind:key="index"
      @click="selectGirlFun(index)"
    >
      {{ index }} : {{ item }}
    </button>
  </div>
  <div>你选择了【{{ selectGirl }}】为你服务</div>
</template>

这样我们这个最简单的点餐小程序就制作完了。

课程总结

我们通过一个简单的大宝剑点餐需求,讲解了一些 Vue3 的新知识点,现在来总结一下:

  • setup 函数的用法,可以代替 Vue2 中的 date 和 methods 属性,直接把逻辑卸载 setup 里就可以
  • ref 函数的使用,它是一个神奇的函数,我们这节只是初次相遇,要在template中使用的变量,必须用ref包装一下。
  • return出去的数据和方法,在模板中才可以使用,这样可以精准的控制暴漏的变量和方法。

这节课我们就学这么多,需要提醒小伙伴的是一定要跟着技术胖一起学习,把代码敲出来。只听是学不会的,我在所有的课程中反复强调这个问题,目的只有一个,就是让你能学有所成。

06. 用 reactive()函数优化程序

上节课学习了setup()ref(),也算和 Vue3 代码有了一次亲密接触,你现在也做出了一个“大宝剑餐单”。这节我们就学一下reactive对语法和规范,然后用它来优化上节课的代码。所以此刻没有打上节课代码的同学,请暂停一下,把上节课的代码打出来,再继续学习。

优化程序

上节课的代码可以说没什么章法可言,所有的变量和方法都混淆在一起,我最不能忍受的是在setup中要改变和读取一个值的时候,还要加上value。这种代码一定是可以优化的,需要引入一个新的 APIreactive。它也是一个函数(方法),只不过里边接受的参数是一个 Object(对象)。

然后无论是变量和方法,都可以作为 Object 中的一个属性,而且在改变selectGirl值的时候也不用再加讨厌的value属性了。再return返回的时候也不用一个个返回了,只需要返回一个data,就可以了。

<script lang="ts">
import { ref, reactive } from "vue";
export default {
  name: "App",
  setup() {
    const data = reactive({
      girls: ["大脚", "刘英", "晓红"],
      selectGirl: "",
      selectGirlFun: (index: number) => {
        data.selectGirl = data.girls[index];
      },
    });

    return {
      data,
    };
  },
};
</script>

修改完成<script>部分的代码后,还需要修改template部分的代码,因为我们这时候返回的只有data,所以模板部分的字面量前要加入data

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
    <div>请选择一位美女为你服务</div>
  </div>
  <div>
    <button
      v-for="(item, index) in data.girls"
      v-bind:key="index"
      @click="data.selectGirlFun(index)"
    >
      {{ index }} : {{ item }}
    </button>
  </div>
  <div>你选择了【{{ data.selectGirl }}】为你服务</div>
</template>

这个修改完成后,可以在Terminal终端里打开yarn serve,查看一下效果了,如果没有错误,应该和原来的效果一样。效果虽然一样,但是这时候代码,要比上节课优雅了很多。着一些的功劳要归属于reactive函数。

给 data 增加类型注解

这时的代码虽然可以完美的运行,但是细心的小伙伴可以发现data这个变量,我们并没有作类型注解,而是采用了TypeScript的类型推断。

这样的代码,在我们公司是不允许出现的,必须要增加类型注解。所以我们先定义一个接口,用接口(interface)来作类型注解。

interface DataProps {
  girls: string[];
  selectGirl: string;
  selectGirlFun: (index: number) => void;
}

编写完成后,你在显示的为 data 变量作一个类型注解.

cosnt data: DataProps = ...

这时候我们的代码才是严谨的。

用 toRefs()继续优化

现在template中,每次输出变量前面都要加一个data,这是可以优化的。有的小伙伴说了,我用...扩展运算符就可以解决这个问题了。

在这里我就可以告诉你不行,因为结构后就变成了普通变量,不再具有响应式的能力。所以要解决这个问题,需要使用 Vue3 的一个新函数toRefs()。使用前需要先进行引入。

import { reactive, toRefs } from "vue";

引入后就可以对data进行包装,把 data 变成refData,这样就可以使用扩展运算符的方式了。具体代码如下:

export default {
  name: "App",
  setup() {
    // const girls = ref(["大脚", "刘英", "晓红"]);
    // const selectGirl = ref("");
    // const selectGirlFun = (index: number) => {
    //   selectGirl.value = girls.value[index];
    // };
    const data: DataProps = reactive({
      girls: ["大脚", "刘英", "晓红"],
      selectGirl: "",
      selectGirlFun: (index: number) => {
        data.selectGirl = data.girls[index];
      },
    });
    const refData = toRefs(data);

    return {
      ...refData,
    };
  },
};

这样写之后,你的template就应该去掉 data,而是直接使用变量名和方法,就可以了。

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
    <div>请选择一位美女为你服务</div>
  </div>
  <div>
    <button
      v-for="(item, index) in girls"
      v-bind:key="index"
      @click="selectGirlFun(index)"
    >
      {{ index }} : {{ item }}
    </button>
  </div>
  <div>你选择了【{{ selectGirl }}】为你服务</div>
</template>

如何选择 Ref()和 reactive()

网络上对这两个方法的争论还是不少的,但到目前为止,还没有什么实质性的理论到底是用Ref()好,还是reactive()好,也就是两种方法都可以。他们的作用都是生成响应式对象,目前来看只是编写上有所不同。

我个人更倾向于使用reactive(),因为它让程序看起来更规范。如果你学到这里还犹豫不定,也没关系,随着你进一步的深入学习,一定会有你自己的最佳选择。

07. Vue3.x 的生命周期和钩子函数

Vue3 版本的生命周期和 Vue2 比有了些变化,所以我先站在一个初学者的角度(没有学过 Vue2 版本的新手),从新讲一下 Vue3.x 的生命周期,等你完全理解之后,我们再来和 Vue2.x 的生命周期作一个对比。

什么是生命周期

Vue 是组件化编程,从一个组件诞生到消亡,会经历很多过程,这些过程就叫做生命周期。

来个比喻,生命周期和人从出生到入土是一样的。有少年时期、有青年时期、有中年时期、有老年时期。每个时期都应该有不同的任务,可以作不同的事。

当你理解了什么是生命周期,你还了解一个概念“钩子函数”。

钩子函数: 伴随着生命周期,给用户使用的函数,操控生命周期,主要是操控钩子函数。

Vue3 的生命周期比较多,我们需要一个个给大家讲。

  • setup() :开始创建组件之前,在beforeCreatecreated之前执行。创建的是datamethod
  • onBeforeMount() : 组件挂载到节点上之前执行的函数。
  • onMounted() : 组件挂载完成后执行的函数。
  • onBeforeUpdate(): 组件更新之前执行的函数。
  • onUpdated(): 组件更新完成之后执行的函数。
  • onBeforeUnmount(): 组件卸载之前执行的函数。
  • onUnmounted(): 组件卸载完成后执行的函数
  • onActivated(): 被包含在<keep-alive>中的组件,会多出两个生命周期钩子函数。被激活时执行。
  • onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。
  • onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数(以后用到再讲,不好展现)。

注:使用<keep-alive>组件会将数据保留在内存中,比如我们不想每次看到一个页面都重新加载数据,就可以使用<keep-alive>组件解决。

钩子函数的使用

来到上节课的“红浪漫点餐程序”,在这个程序中依次输出对应的生命周期函数,来看看结果。

Vue3.x 生命周期在调用前需要先进行引入,我们先暂时演示前五个生命周期。

import {
  reactive,
  toRefs,
  onMounted,
  onBeforeMount,
  onBeforeUpdate,
  onUpdated,
} from "vue";

先来说setup(),setup 这个函数是在beforeCreatecreated之前运行的,所以你可以用它来代替这两个钩子函数。

为了看出钩子函数执行的时机,我在setup()函数里,编写了下面的代码:


<script lang="ts">

//....
const app = {
  name: "App",
  setup() {
    console.log("1-开始创建组件-----setup()");
    const data: DataProps = reactive({
      girls: ["大脚", "刘英", "晓红"],
      selectGirl: "",
      selectGirlFun: (index: number) => {
        data.selectGirl = data.girls[index];
      },
    });
    onBeforeMount(() => {
      console.log("2-组件挂载到页面之前执行-----onBeforeMount()");
    });

    onMounted(() => {
      console.log("3-组件挂载到页面之后执行-----onMounted()");
    });
    onBeforeUpdate(() => {
      console.log("4-组件更新之前-----onBeforeUpdate()");
    });

    onUpdated(() => {
      console.log("5-组件更新之后-----onUpdated()");
    });

    const refData = toRefs(data);

    return {
      ...refData,
    };
  },
};
export default app;
</script>

写完后可以到浏览器看一下效果,效果和你想象的应该是一样的。

1 - 开始创建组件---- - setup();
2 - 组件挂载到页面之前执行---- - onBeforeMount();
3 - 组件挂载到页面之后执行---- - onMounted();
4 - 组件更新之前---- - onBeforeUpdate();
5 - 组件更新之后---- - onUpdated();

你这时候一定会有个疑问,那Vue2.X版本的生命周期函数还可以使用吗?答案是肯定的。

你可以在setup()函数之后编写Vue2的生命周期函数,代码如下:

beforeCreate() {
  console.log("1-组件创建之前-----beforeCreate()");
},
beforeMount() {
  console.log("2-组件挂载到页面之前执行-----BeforeMount()");
},
mounted() {
  console.log("3-组件挂载到页面之后执行-----Mounted()");
},
beforeUpdate() {
  console.log("4-组件更新之前-----BeforeUpdate()");
},
updated() {
  console.log("5-组件更新之后-----Updated()");
},

这时候可以看到,原来的生命周期也是完全可以使用。

Vue2.x 和 Vue3.x 生命周期对比

你也许会问,那我到底是使用Vue2.x还是Vue3.x的生命周期钩子函数?其实这个无所谓,但是不愿混用,如果你用 setup 这种Vue3的生命周期函数,就不要再使用Vue2的了。为了你更好的掌握,我作了一个函数对比:


Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
errorCaptured -> onErrorCaptured

通过这样对比,可以很容易的看出 vue3 的钩子函数基本是再 vue2 的基础上加了一个on,但也有两个钩子函数发生了变化。

  • BeforeDestroy变成了onBeforeUnmount
  • destroyed变成了onUnmounted

尤大神的介绍是mountDestroy更形象,也和beforeMount相对应。

除了这些钩子函数外,Vue3.x还增加了onRenderTrackedonRenderTriggered函数,这两个函数放到下节课再讲解。这节就先到这里了。

08. onRenderTracked()和 onRenderTriggered()钩子函数的使用

这两个钩子函数是Vue3.x版本新加的两个钩子函数,官方说是用来调试使用的,但是目前还没有给出具体的调试案例。

对新旧钩子函数的使用原则

Vue 官方的文档里,明确指出了。如果你使用 Vue3,请尽量使用新的生命周期钩子函数,也就是上节课写在setup()函数中带on的这些钩子函数。

onRenderTracked 状态跟踪

onRenderTracked直译过来就是状态跟踪,它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,他都会跟踪。只要页面有update的情况,他就会跟踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在。

使用onRenderTracked同样要使用import进行引入。

import { .... ,onRenderTracked,} from "vue";

引用后就可以在setup()函数中进行引用了。

onRenderTracked((event) => {
  console.log("状态跟踪组件----------->");
  console.log(event);
});

写完后可以到终端中启动测试服务yarn serve,然后看一下效果,在组件没有更新的时候onRenderTracked是不会执行的,组件更新时,他会跟组里边每个值和方法的变化。

onRenderTriggered 状态触发

onRenderTriggered直译过来是状态触发,它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。

如果把onRenderTracked比喻成散弹枪,每个值都进行跟踪,那onRenderTriggered就是狙击枪,只精确跟踪发生变化的值,进行针对性调试。

使用它同样要先用import进行引入

import { .... ,onRenderTriggered,} from "vue";

在使用onRenderTriggered前,记得注释相应的onRenderTracked代码,这样看起来会直观很多。 然后把onRenderTriggered()函数,写在setup()函数里边,

onRenderTriggered((event) => {
  console.log("状态触发组件--------------->");
  console.log(event);
});

对 event 对象属性的详细介绍:

- key 那边变量发生了变化
- newValue 更新后变量的值
- oldValue 更新前变量的值
- target 目前页面中的响应变量和函数

通过这些你能很好的对代码进行调试。这些调试用的钩子函数,如果你能正确合理的使用,是真的可以快速解决问题的。

有的小伙伴看到这里肯定会觉的,这个和watch很像,那下节课我们再讲一下watch的使用吧,这个也有了很大的变化。

09. Vu3中Watch的使用和注意事项

Vue2中也有watch-监听器(侦听器),作用是用来侦测响应式数据的变化,并且可以得到newValue新值和oldValue老值。如果你熟悉Vue2一定熟悉这个函数,但在Vue3中watch有了一些细微的变化,我们来学习一下。

修改标题引出的需求和界面修改

现在我们的“红浪漫洗浴中心”老板有新的需求了,当你点击按钮,点餐完毕,WEB标题也要跟着改变,这时候你好像没办法变成自动相应,双向绑定了。今天的主角就排上用场了,watch监听器隆重登场。

类似的情况也会有,比如根据值的变化,进行网络请求,根据值的变化进行组件的生成和销毁(我们经常成为这类操作为副作用)。把这类需求写在watch监听器里就是不错的选择。

在写代码之前,你可以删除前两节课学习生命周期时的钩子函数,让代码变得干净一些。

现在你可以先作一个按钮的响应值和改变值的方法,并写在setup()函数中,这里我使用了ref来生成响应式数据,你可以跟着我一起复习一下。

{
  //.....
  const overText = ref("红浪漫");
  const overAction = () => {
    overText.value = overText.value + "点餐完成 | ";
  };
  return { ...refData,  overText,   overAction};

}

写完js代码后,在template模板中,编写下面的代码,这样可以在点击按钮时,调用overAction函数。

 <div><button @click="overAction">点餐完毕</button></div>
 <div>{{ overText }}</div>

现在完成老板的需求,我们在改变的时候直接用js修改WEB的title。

const overAction = () => {
      overText.value = overText.value + "点餐完成 | ";
      document.title = overText.value;
    };

都完成后,可以到浏览器中看一下你写的效果。发现我们写的根本没有用处,跟我们想的一点都不一样。这时候就需要Watch来救场啦。

watch监听器的实现

使用watch同样需要先进行导入.

import {... , watch} from "vue"

引入后编写watch函数,它接受两个参数,第一个是要监听的值,这里是overText,然后是一个回调函数。在函数中你可以获得到新知和老值。

 watch(overText, (newValue, oldValue) => {
    document.title = newValue;
  });

为了看到效果,我用console.log输出一下新值和老值。

watch(overText, (newValue, oldValue) => {
    console.log(`new--->${newValue}`);
    console.log(`old--->${oldValue}`);
    document.title = newValue;
  });

watch多个值时

当你要监听多个值的时候,不是写多个watch函数,而是要传入数组的形式。比如现在我们同时要监听data中你选择了那个女孩,也就是selectGirl时,我们可以使用数组的形式。

我们把程序写成这个样子,然后到浏览器中预览。

 watch([overText, data.selectGirl], (newValue, oldValue) => {
      console.log(`new--->${newValue}`);
      console.log(`old--->${oldValue}`);
      document.title = newValue[0];  //返回的newValue也是一个数组
  });

发现报错了,它告诉我们可以用一个函数解决reactive中的值的问题。把程序写成这个下面的样子就不报错了。

 watch([overText, () => data.selectGirl], (newValue, oldValue) => {
    console.log(`new--->${newValue}`);
    console.log(`old--->${oldValue}`);
    document.title = newValue[0];
  });

现在程序就可以正常运行了,有人会说Vue3不能监听reactive里边的值是不是一个Bug,我想说的这并不是Bug,而是为了保持和Vue2的一致性,因为在Vue2中也时这种结果,解决方案是要么是ref或者这种get/set方法的形式。要么你你开启设置watchOptions的deep为true,也就是深度监听模式。

好了,这节课的内容就到这里了,下节课我们继续学习。

10. Vu3中模块化介绍-作一个时间更新模块

Vue3.x版本最大的一个提升,就是有更好的重用机制,你可以把任何你想独立的模块独立出去。比如在上节课的基础上,加一个显示当前时间的功能(例如:17:30:20)。并且这个功能要在不同的页面进行反复调用。

使用Vue2.x的版本,一定会使用mixins进行代码的重用。当有Vue3.x

让程序变的感情

为了方便学习,我们把程序中大部分代码删除掉,修改为下面的样子。

<template>
  <div>

  </div>
</template>
<script lang="ts">
import { ref } from "vue";
const app = {
  name: "App",
  setup() {

  },
};
export default app;
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

然后就可以编写代码了

先实现功能

先来看不重用的写法,也就是我们把程序直接写在App.vue这个组件里。这里你可以先顶一个ref变量nowTime,然后通过getNowTime的方法,让他可以显示并一直更新当前时间。最后在return里返回这个变量和方法。

//....
const app = {
  name: "App",
  setup() {
    //.....
    const nowTime = ref("00:00:00");
    const getNowTime = () => {
      const now = new Date();
      const hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
      const minu =now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
      const sec =now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
      nowTime.value = hour + ":" + minu + ":" + sec;
      setTimeout(getNowTime, 1000);   //每一秒执行一次这个方法
    };
    //...
    return {
      //....
      nowTime,
      getNowTime,
    };
  },
};
export default app;

然后你需要在template里使用他们,代码如下.

<div>{{ nowTime }}</div>
<div><button @click="getNowTime">显示时间</button></div>

这样就可以在浏览器里看到初始时间00:00:00,点击按钮后,开始显示当前时间,并一直更新。

独立模块化的使用

这个显示时间的方法,可能在其他页面中也会使用,所以现在的需求是把这个时间显示的功能进行模块和重用化。

可以在src目录下,新建一个文件夹hooks(所有抽离出来的功能模块都可以放到这个文件夹里),然后再新建一个文件useNowTime.ts,这里使用use开头是一个使用习惯,代表是一个抽离出来的模块。

有了模块之后,我们就可以把写的代码复制到useNowTime.ts文件里了。然后进行必要的修改。

import { ref } from "vue";

const nowTime = ref("00:00:00");
const getNowTime = () => {
    const now = new Date();
    const hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
    const minu =
        now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
    const sec =
        now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
    nowTime.value = hour + ":" + minu + ":" + sec;

    setTimeout(getNowTime, 1000);
};

export { nowTime, getNowTime }

需要注意的是,你需要在代码的最前面用import进行引入ref,在最后用export的方式,导出nowTimegetNowTime.

引入并使用模块

模块写好了,回到App.vue页面,现在可以引入并使用模块了。

引入代码:

import { nowTime, getNowTime } from "./hooks/useNowTime";

然后记得,要用return进行导出哦

return {nowTime,getNowTime};

现在可以看出这种方式,比vue2中要好很多,不用再使用mixins(混入)要好很多。我觉的这个算是Vue3.x一个非常重要的改进。

11. Vu3中模块化深入-随机出现小姐姐

这时候“红浪漫”洗浴的老板有了新的项目,要求来的顾客可以随机选择一位美女服务,增加刺激性,我们的任务也是作一个随机选择的菜单,每次刷新都会随机出现大脚、刘英或者是晓红。趁这个机会,我们正好也练习一下Vue3.x中的模块化。

让程序变的干净

以前我们写了很多程序,看起来有些杂乱无章了,所以这节我们先把一些无用的代码删除掉。然后再用模块化的概念编写今天的随机选美女的程序。

<template>
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
    <div>随机选择一位美女为你服务</div>
  </div>
</template>
<script lang="ts">
import { reactive, toRefs, ref, watch } from "vue";
const app = {
  name: "App",
  setup() {
    return {};
  },
};
export default app;
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

我们删除掉了大部分的代码,只留了几个文字。这样代码看起来就清爽的多了,也可以开始编写代码了。

编写远程调用API组件

这里我们使用axios来进行远程随机获得图片,但是我们这里作的不是远程随机获得图片,而是模块化一个通用的远程调用API的组件,这个组件可以远程请求一个指定的URL,并且返回所得到的值。 先用npm的方式安装axios.

npm install axios --save

这个的安装的时间会稍微有一点长。

在上节课的文件夹里,新建一个文件,叫做useURLAxios.ts,然后先引入refaxios.在文件里写一个useUrlAxios方法,在方法里声明四个响应式变量resultloadingloadederror。声明好后,使用axios进行访问远程链接。最后记得要进行returnexport default

import { ref } from 'vue'
import axios from 'axios'

function useUrlAxios(url: string) {
    const result = ref(null)
    const loading = ref(true)
    const loaded = ref(false)
    const error = ref(null)

    axios.get(url).then((res) => {
        loading.value = false
        loaded.value = true
        result.value = res.data
    }).catch(e => {

        error.value = e
        loading.value = false
    })
    return {
        result,
        loading,
        loaded,
        error
    }

}

export default useUrlAxios

随机美女API介绍

我自己作了一个随机美女的API,你直接调用就可以了,不用传任何参数,只要进行get请求就可以得到随机出现大脚、刘英和晓红的图片的地址。

随机美女API:https://apiblog.jspang.com/default/getGirl

也请小伙伴手下留情,不要随意攻击此接口,方便其他小伙伴们学习。

App.vue的实现

我们先来实现进入页面随机显示一个美女图片,然后刷新会出现不同的美女。

<template>
  <div>
    <h2>欢迎光临红浪漫洗浴中心</h2>
     <div>随机选择一位美女为你服务</div>
    <div v-if="loading">Loading.....</div>
    <img v-if="loaded" :src="result.message" />
    <div></div>
  </div>
</template>
<script lang="ts">
import { ref } from "vue";
import useUrlAxios from "./hooks/useUrlAxios";
const app = {
  name: "App",
  setup() {
    const { result, loading, loaded } = useUrlAxios(
      "https://dog.ceo/api/breeds/image/random"
    );

    return { result, loading, loaded };
  },
};
export default app;
</script>

好了,我们只要刷新,都可以随机显示一张美女的照片。但这不是重点,重点是你要学会这种独立模块化的方式,让我们的代码可以复用。建议这个代码要多写两边,养成这种模块化的思维方式。

真诚感谢您的留言,我会亲自查收每一条留言并进行回复,审核后显示在文章底部。
您的昵称
电子邮件
最新留言

No Data

技术胖
专注于WEB和移动前端开发
光头Coder12年经验业余讲师免费视频被访问
只要50元/年 得3项福利

视频离线高清版下载-400集

每周至少两篇文章分享

每天回答所提问题(选择性回答)