12 | 调试:提高开发效率必备的Vue Devtools

你好,我是大圣。

跟随我的脚步,通过对前面数讲内容的学习,相信你现在对Vue+Vuex+vue-router都已经比较熟悉了。在开启课程后续的复杂项目之前,学会如何调试项目也是我们必须要掌握的一个技能。

在项目开发中,我们会碰到各种各样的问题,有样式错误、有不符合预期的代码报错、有前后端联调失败等问题。也因此,一个能全盘帮我们监控项目的方方面面,甚至在监控时,能精确到源码每一行的运行状态的调试工具,就显得非常有必要了。

而Chrome的开发者工具Devtools,就是Vue的调试工具中最好的选择。由于Chrome也公开了Devtools开发的规范,因而各大框架比如Vue和React,都会在Chrome Devtools的基础之上,开发自己框架的调试插件,这样就可以更方便地调试框架内部的代码。Vue Devtools就是Vue官方开发的一个基于Chrome浏览器的插件,作为调试工具,它可以帮助我们更好地调试Vuejs代码。

这节课,我会先为你讲解如何借助Chrome和VS Code搭建高效的开发环境,然后再教你使用Vue 的官方调试插件 Vue Devtools 来进行项目调试工作。

Chrome调试工具

首先,我们来了解一下Chrome的调试工具,也就是Chrome的开发者工具Chrome DevTools。在Chrome浏览器中,我们打开任意一个页面,点击鼠标右键,再点击审查元素(检查),或者直接点击F12就可以看到调试窗口了。

图片

我们看下截图中的调试窗口,里面有几个页面是我们经常用到的:Elements页面可以帮助我们调试页面的HTML和CSS;Console页面是我们用得最多的页面,它可以帮助我们调试JavaScript;Source页面可以帮助我们调试开发中的源码;Application页面可以帮助我们调试本地存储和一些浏览器服务,比如Cookie、Localstorage、通知等等。

Network页面在我们开发前后端交互接口的时候,可以让我们看到每个网络请求的状态和参数;Performance页面则用来调试网页性能。Lighthouse是Google官方开发的插件,用来获取网页性能报告,今天我也会教你用lighthouse评测一下极客时间官网首页的性能。

以上说的这些调试窗口中的页面,都是Chrome的开发者工具中自带的选项,而调试窗口最后面的Vue页面就是需要额外安装的Vue Devtools,也就是调试Vue必备的工具。

图片

上图所示的是项目开发中用到最多的页面,而在调试窗口右侧的工具栏中,你还可以选中More tools来开启更多自带的插件。如下图所示,More tools中的Animations用于调试动画,Security用于调试安全特性等等。

图片

下面,我们重点介绍一下调试窗口中的Elements页面和Console页面。这两个页面用来调试页面中的HTML+CSS+JavaScript,是使用频率最高的两个页面。

在Elements页面中,首先映入眼帘的是开发的Vue项目在浏览器里的状态。调试窗口的左侧是正在调试的前端页面的HTML结构,当我们把鼠标放到HTML代码的任何元素上时,在调试的前端页面上,对应元素在前端页面中所在的位置都会高亮起来。

当我们点击一个元素之后,调试窗口右侧就会显示出当前元素所有的CSS样式,这对于我们开发的页面布局和样式调整非常有帮助。并且,我们还可以在Elements页面左侧的代码中,任意修改页面的HTML和CSS代码。

比如,以我在这里给出的调试页面为例,我们可以选中调试页面(清单应用)的div标签,再点击调试页面右侧的element.style,这样就可以直接新增background和padding属性,也即会得到下图的效果。此外,有一些页面布局上的bug可以用这种方式,在网页里实时调整后,再去更新代码。

图片

然后,我们再来看一下在调试中用得最多的Console页面。在这个页面内,我们可以直接调试JavaScript,并且页面中也会显示JavaScript出现的报错信息。

举个小例子,我们来到项目里的src/main.js文件内,把createApp修改成createApp1,然后回到浏览器的Console调试页面,就会看到以下的报错内容,红色报错信息清晰地告诉我们代码执行出现错误的原因。

图片

我们点击报错信息的最右侧,还能精确地定位到项目中的文件以及代码的行数。尤其是对于新手程序员来说,精确的报错定位可以极大地提高我们的开发效率。国外甚至有程序员还直接在报错信息里加上stackoverflow搜索地址,也算是把Console玩出花样了。

图片

参考我们提到的国外程序员的做法,我们在src/main.js里加入下面这段代码 ,这样就可以在日志信息中直接复制报错内容中的链接,去Stack Overflow中寻找答案。

window.onerror = function(e){
    console.log(['https://stackoverflow.com/search?q=[js]+'+e])
}

其实Console页面的用法非常多,当我们在代码里使用cosole.log打印信息时,console页面里就会显示log传递的参数,这也是程序员用得最多的调试方法。

除了console.log,还有console.info、console.error等方法可以显示不同级别的报错信息。而在log之外,我们还可以使用console.table更便捷地打印数组消息。在MDN的Console页面中,有对Console的全部API的介绍,你也可以去参考一下。

关于Console,后续的课程中还会持续地用到,我在这里还可以分享一个我喜欢用的前端面试题,题目来自贺老的面试题。那就是我会把电脑给面试者,让他在Console页面里写代码,统计极客时间官网一共有多少种HTML标签。

你也可以上手体验一下,打开极客时间的官网,再打开调试窗口,在Console页面输入下面的代码,你就可以看到答案。这其实是一个比较考验应试者前端基础的一道题,你可以自己试一试。

new Set([...document.querySelectorAll('*')].map(n=>n.nodeName)).size

Vue Devtools

然后,我们再来介绍一下调试窗口里最后面的Vue页面,这个页面其实就是我们在Chrome浏览器中安装的第三方的插件Vue Devtools。

首先我们要做的是安装一下Vue Devtools。Vue Devtools的官网上有详细的安装教程,这里就不过多讲解了。安装完毕后,如果调试的前端页面中有Vue相关的代码,就会激活这个tab。进入到Vue这个调试页面后,你就会看到下面的示意图。

图片

从上面的图中你可以看到,Vue Devtools可以算是一个Elements页面的Vue定制版本,调试页面左侧的显示内容并不是HTML,而是Vue的组件嵌套关系。我们可以从中清晰地看到整个项目中最外层的App组件,也能看到App组件内部的RouterView下面的Todo组件。

并且,在调试页面的左侧中,当我们点击组件的时候,我们所调试的前端页面中也会高亮清单组件的覆盖范围。调试页面的右侧则显示着todo组件内部所有的数据和方法。我们可以清晰地看到setup配置下,有todos、animate、active等诸多变量,并且这些变量也是和页面实时同步的数据,我们在页面中输入新的清单后,可以看到active和all的数据也随之发生了变化。

同时,我们也可以直接修改调试窗口里面的数据,这样,正在调试的前端页面也会同步数据的显示效果。有了Vue的调试页面,当我们碰到页面中的数据和标签不同步的情况时,就可以很轻松地定位出是哪里出现了问题。

然后在Component的下拉框那里,我们还可以选择Vuex和Router页面,分别用来调试Vuex和vue-router。

图片

我们先来点击Vuex页面试一下,这个页面里的操作可以帮助我们把Vuex的执行过程从黑盒变成一个白盒。简单来说,我们可以在调试窗口的右侧看到Vuex内部所有的数据变化,包括state、getters等。

图片

我们点击Vuex下拉框里的Routes页面,这个页面里显示了整个应用路由的配置、匹配状态、参数等,这里就不做过多的解释了。相信有了Vue Devtools后,你能够更快地调试Vue项目的内部运行状态,从而极大地提高开发效率。

图片

这里还有一个小技巧,你可以了解一下:在Components页面下,你选中一个组件后,调试窗口的右侧就会出现4个小工具。

如下图所示,在我用红框标记的四个工具中,最右边的那个工具可以让你直接在编辑器里打开这个代码。这样,调试组件的时候就不用根据路径再去VS Code里搜索代码文件了,这算是一个非常好用的小功能。

图片

断点调试

正常情况下,我们用好Elements、Console和Vue这三个页面就可以处理大部分的调试结果了。不过太多的Console信息会让页面显得非常臃肿,所以还出现过专门去掉Console代码的webpack插件。

如果代码逻辑比较复杂,过多的Console信息也会让我们难以调试。这种情况就需要使用断点调试的功能,Chrome的调试窗口会识别代码中的debugger关键字,并中断代码的执行。

还是通过小例子直观感受一下。我们打开src/components目录下的todo.vue文件,下面是清单应用的代码,我们在addTodo函数内的第一行写上debugger。然后到前端的清单应用的页面中,我们输入任意一条信息,点击回车,你就会发现页面暂停了,并且调试窗口跳转到了source页面。

  function addTodo() {
    debugger
    if(!title.value){
      showModal.value = true
      setTimeout(()=>{
        showModal.value = false
      },1500)
      return 
    }
    todos.value.push({
      title: title.value,
      done: false,
    });
    title.value = "";
}    

上面的代码在调试窗口中的效果如下图所示,点击图中用红框圈出的按钮,你就可以在debugger暂停的地方,逐行执行代码。并且鼠标放在任意变量上,都可以看到这个变量在代码执行的结果。对于复杂代码逻辑的调试来说,使用断点调试,可以让整个代码执行过程清晰可见。debugger也是高级程序员必备的断点调试法,你一定要掌握

图片

性能相关的调试

了解了页面代码的调试方法后,我们再来分享一下页面的性能调试方法。比如,在你遇到页面交互略有卡顿的时候,你可以在调试窗口中点击Performance页面中的录制按钮,然后重复你卡顿的操作后,点击结束,就可以清晰看到你在和页面进行交互操作时,浏览器中性能的变化。

以极客时间的官网页面作为具体的例子,我们在调试窗口中点击Performance页面中的录制按钮,然后进行刷新页面的操作,并点击首页轮播图,之后我们可以看到如下的效果:

图片

我们可以滑动鼠标,这样就能很清晰地看到极客时间页面加载的过程。然后,我们重点看下首屏加载中的性能指标,通过下方的饼图,你可以看到整个刷新过程中耗时的比例,其中JS代码391ms,整体624ms。

图片

在Performace页面中,我们还可以详细地看到每个函数的执行时间。我们录制一下清单应用新增清单的操作之后,就会显示下面的示意图,从中可以清晰地看到键盘keydown事件之后执行的函数,在图中可以找到我们写的addTodo方法,以及mountElement等Vue源码里的函数。关于Chrome性能页面更多的使用方法 ,你可以到Chrome官方文档上去查看。

图片

如果你觉得上面手动录制页面的性能报告的方法过于繁琐,还可以直接使用lighthouse插件。我们进入到lighthouse页面,选择desktop桌面版后,点击生成报告。lighthouse在浏览器上模拟刷新的操作后,给出一个网页评分。这里我们可以看到,极客时间网站首页的评分是72分,在合格的标准线上。

图片

此外,根据性能、可访问性、最佳实践、SEO和PWA五个维度的评分,我们可以看出,在前面四个维度中,极客时间都是及格的,第五个指标置灰,说明极客时间首页还没有支持PWA。

我们先看下性能指标,下图中详细地给出了FCP、TTI、LCP等常见性能指标,并且还很贴心地给出了建议,包括字体、图标宽高、DOM操作等等,其实我们按照这些建议依次修改,就可以实现对网页的性能优化了。并且网页优化后,性能分数的提升还可以很好地量化优化的结果。

图片

关于极客时间首页lighthouse其余几个指标,你可以点开这个链接查看结果,相信结合这个实例演示,你一定会对性能优化手段有所体会。

总结

好,今天这一讲的主要内容,也即调试Vue应用的方法,就讲完了,我们一起来回顾一下吧。

首先,我给你讲解了在Chrome浏览器中,进行项目调试的方法。除了最基本的Console,我们还可以借助Chrome提供的其他调试工具提高效率,例如元素面板、源码面板等等。每个面板都带来了透视Vue应用的方式,从样式到性能都是我们提高效率最高的工具。

Elements和Console页面可以完成页面的布局和JavaScript的调试工作,并且调试窗口还会识别代码中的debugger语句,可以让我们在Chrome中进行断点调试。Performance和lighthouse页面则提供了对页面做性能测试的方法,从而能帮助我们更好地查看页面中性能的指标。

然后,我们介绍了Vue团队开发的插件Vue Devtools,你可以把Vue Devtools理解为是对Chrome调试工具的一个扩展。Vue Devtools中,我们可以很方便地调试Vue的应用,比如查看Vue的组件嵌套、查看Vue组件内部的data等属性

此外,当我们遇见页面中的数据和渲染结果不一致的bug时,我们可以很方便地使用Vue Devtools精确地定位问题,从而极大地提高了开发效率。并且Vue Devtools还支持了Vue和vue-router的调试页面,这让整个页面的Vuex数据和路由都清晰可见。

相信今天这一讲结束后,当你在开发应用时再遇到了bug,你就能通过调试工具快速地定位问题,并借助今天我们讲到的内容,顺利地解决掉bug。

思考题

Vue的Devtools操作比较简单,进阶的知识并不算多。在讲Console页面时,我分享了一个与Vue Devtools相关的常见的手写面试题,而今天的思考题就是这个面试题的升级版:如何在Console页面写一段代码,来统计极客时间首页出现次数最多的3种HTML标签呢?

欢迎在留言区分享你的答案,我们可以一起探讨高效调试Vue的新方法。也欢迎你把这一讲的内容分享给你周围的朋友、同事,我们下一讲见!

精选留言

  • 元宝

    2021-11-12 10:22:24

    Object.entries([...document.querySelectorAll("*")].map(n=>n.tagName).reduce((pre, cur)=>{
    pre[cur] = (pre[cur] || 0) + 1;
    return pre;
    }, {})).sort((a, b)=>b[1]-a[1]).slice(0, 3)
    作者回复

    cool,和我写的简直一毛一样 给你点个赞 最后用console.table打印一下

    2021-11-13 10:23:16

  • 若川

    2021-11-12 10:26:03

    debugger 也是高级程序员必备的断点调试法,你一定要掌握。

    很赞同大圣老师的这句话。我觉得是基本必备技能。但我发现真的有很多人不太会,甚至没调试过代码,没安装过vue-devtools。

    其实vue官方文档有写怎么调试。《在 VS Code 中调试》https://cn.vuejs.org/v2/cookbook/debugging-in-vscode.html

    更是少数人知道 vue-devtools 可以直接打开页面对应的组件源文件,不需要问同事,定位半天。
    我之前也写过文章分析这个功能原理。《据说 99% 的人不知道 vue-devtools 还能直接打开对应组件文件?本文原理揭秘》https://juejin.cn/post/6959348263547830280
    作者回复

    给力给力,没翻墙的同学可以看下这个文章的devtools安装方法

    2021-11-13 10:22:55

  • ch3cknull

    2021-11-12 21:37:11

    vue-devtools有两个,其中一个是不支持vue3的

    下面是Google应用商店的扩展的链接,这个链接指向的插件是支持vue3的

    http://chrome.google.com/webstore/detail/ljjemllljcmogpfapbkkighbhhppjdbg
  • Kobe的篮球

    2021-12-13 15:21:45

    vue3项目通过vite打包后,如何支持dev-tools啊
    作者回复

    新增这个命令 "build:dev": "vue-tsc --noEmit && vite build --mode=development",

    这样就打包了一个支持devtools的打包版

    2021-12-13 19:55:38

  • 花果山大圣

    2021-11-12 18:40:38

    参考答案之一, 其实这一题还可以扩展很多,比如不让你用sort,比如如果三四五名词的次数一样,怎么把这些并列的也打出来等等
    let ret = Object.entries([...document.querySelectorAll('*')].map(node => node.nodeName).reduce((ret,n)=>{
    ret[n] = ret[n]?ret[n]+1:1
    return ret
    },{})).sort((a,b)=>b[1]-a[1]).slice(0,3)
    console.table(ret)
  • ll

    2021-11-13 17:01:37

    devTool 是很牛的“谁用谁知道”,通过这节,如果没用过的小伙伴赶紧尝试下;
    这节课后有如下感想:
    1. 调试是工程的重要一环。
    2. 想要提高调试环节的效率,要有好的方法,更要有趁手的工具
    3. 在 web 开发领域,不夸张的说,最优秀和专业的非 Chrome devtoool 莫属。
    4. 针对特定框架,更更专业的工具是各个“框架公司”基于 devtool 开发的“专属”测试工具。
    5. 掌握方法论,并且熟练使用工具;是提高开发效率的明智选择。
    6. 如果对 devtool 这么“神奇”抱有好奇,想知道这个是怎么实现的,其实结合思考题,就
    能略知一二,其实原理是相通的
  • Beauty~fish🐬

    2021-11-30 10:23:39

    贺老面试题。。。还有其他的题吗,在哪里可以学习呢
    作者回复

    贺老有个live 很久之前听的

    2021-12-13 21:09:47

  • 轻飘飘过

    2021-11-17 16:45:02

    看大家的写法都挺优秀的,大圣老师说的不用sort 和并列打印数据的问题,个人思考用桶排序求解🤔,代码如下,互相学习。
    function main() {
    let tags = Array.from(document.querySelectorAll('*'));
    let tMap = {}, max = min = 1;
    tags.forEach(tag => {
    let v = tag.tagName;
    if (!tMap[v]) tMap[v] = 0;
    tMap[v]++;
    max = Math.max(tMap[v], max);
    min = Math.min(tMap[v], min);
    });

    let bucket = new Array(max - min + 1);
    Object.keys(tMap).forEach(v => {
    if (!bucket[tMap[v] - min]) bucket[tMap[v] - min] = [];
    bucket[tMap[v] - min].push(v);
    });

    let res = [], count = 3, i = bucket.length - 1;
    while (count > 0 && i >= 0) {
    if (bucket[i]) {
    count--;
    res.push(bucket[i]);
    }
    i--;
    }
    return res;
    };
    作者回复

    cool

    2021-11-18 21:36:07

  • 飞翔国度

    2021-11-16 17:00:15

    发现公司的vue项目都屏蔽了vuetools...在生产上开着是不是有点不安全?
    作者回复

    生产上确实不要开devtools,而且默认build的时候也会吧devtools相关的代码屏蔽

    2021-12-13 21:26:19

  • 郭纯

    2021-11-12 16:40:06

    Object.entries(Array.from(document.querySelectorAll('*')).reduce((res, { tagName }) => ((tagName in res) ? (res[tagName] ++ ) : (res[tagName] = 1), res), {})).sort(([tagNameA, countA],[tagNameB, countB]) => countB - countA).map( ([tagName] ) => tagName ).slice(0,3)
  • 海阔天空

    2021-11-12 07:48:34

    长知识了,以前调试动画的时候,都是慢慢调的。原来动画还可以这样调。Vue Devtools没有过,可以试一下
  • 路漫漫

    2021-11-12 00:24:20

    先学为敬
  • 2024-06-05 10:29:01

    安装了好几次vue devtools,其中有一次在极客时间网站是亮着的,vue3项目是灰的;其他安装的插件都是灰的。这个东西真的能用吗,怎么就是搞不定这个插件呢
  • 2024-06-04 15:54:54

    安装了vue devtools后,在控制台没有显示vue面板怎么办呢。网上找了很多方法,怀疑vue devtools真的有人用过吗
  • Skelanimals

    2023-04-14 11:08:37

    Object.entries(Array.from([...$$('*')])
    .reduce((total, node) => {
    if(!total[node.nodeName])
    total[node.nodeName] = 0

    total[node.nodeName] += 1

    return total
    }, {}))
    .sort((a, b) => b[1] - a[1])
    .slice(0, 3)
  • 2022-06-26 10:06:23

    国内下载chrome插件有点困难 他们就不能搞个国内的下载链接么
  • 杨闯

    2022-04-12 23:01:31

    刚才的问题解决了,不用求助了,谢谢了
  • 杨闯

    2022-04-12 22:45:27

    试了好多办法都没有解决Vue.js is detected on this page,求助
  • 大鸟

    2022-02-17 18:14:28

    老师你好,我用的是webstorm开发的,我使用devtools在编辑器中打开对应的组件的时候总是在命令行中打开了文件内容而不是标签页。这种情况搜了很久都没搜到解决方法。
  • 南山

    2021-11-24 09:36:49

    大开眼界