0%

pseudo-trigger.gif
可以触发元素上的伪类,以研究元素(例如,将元素悬停在元素上)如何反应。您可以右键单击“元素”面板中的节点,然后选择“强制元素状态”。或者,可以在“样式”子窗格中单击“切换”元素状态图标。

当一个元素应用了某种状态时,您将在节点的开始标签左侧看到一个视觉指示器,在某些情况下,也将在关闭标签左侧(如果它们相距很远)。

我们可以触发:活动类(:active),焦点类(:focus),悬停类(:hover)和访问过的(:visited)伪类。

补充

一般伪类是:PseudoClass,伪元素是::PseudoElement,虽然伪元素也能写一个冒号,但是最好区分开来

copy-as-curl.gif
网络面板中显示的资源有一个上下文菜单,该菜单允许您复制为cURL,这将进入剪贴板,此时您可以将其粘贴到命令行中,必要时进行修改,然后查看响应。请求标头也包括在内。

补充

  1. Numbers API给个数字,会返回这个数字相关的信息。其实有很多免费的API很有趣,可以自行收集下,比如天气的,历史上的今天,新冠疫情数据,这样我们没有自己的服务器也能做出有意思的应用。
  2. Windows 系统没有curl命令行工具(除非自己安装),可以使用Copy as PowerShell进行请求重播,复制成fetch代码也不错,做接口测试的时候就省代码了
    image.png

将网络回复复制到剪贴板

copy-response.gif

snippets.gif
DevTools中提供了一个名为Snippets的功能,使您可以注入可在网页上运行的JavaScript代码(与在控制台面板中重新键入JavaScript代码相比,这更方便)。尝试一下:

  • 转到“来源”>“代码段”(位于左侧边栏中)
  • 在摘要窗口中单击鼠标右键,然后选择“新建”。
  • 输入文件名和所需的代码段
  • 右键点击代码段,然后选择运行(或Ctrl / Cmd + Enter)

您还会注意到,它具有多行编辑功能,并且可以确认退出而不保存。

这是大量的DevTools片段集合:https : //github.com/bgrins/devtools-snippets

补充

代码段可以直接在 Console面板执行的,但是在里面不好调整格式,也没有自动完成,也不能保存。所以这种方式挺好的。

总能遇到一些本地环境不能调试的代码,直接使用代码段功能在测试环境执行我们的代码,省去了打包上环境的时间,也确保了代码的正确性。

思考与尝试

尝试下打断点,触发断点后,再执行代码段,不知道此时的变量作用域怎么样的呢?有兴趣的同学可以自己试试,评论区见答案。

local-mods.gif

本地修改使您可以查看(通过DevTools)对某些源文件进行了哪些更改。

进行更改并保存后,右键单击“源代码”面板中的文件,然后选择“本地修改”。每个修改都将列为新的更改,并且每个修改都可以单独还原。

本地修改有助于跟踪,进行了哪些更改,何时进行了这些更改以及对哪些文件进行了更改。

您可能还对较新的DevTools更改面板感兴趣。

补充

  1. 一般IDE(IDEA,VSCODE)自带的diff比较工具都挺好用的,但是如果去比较两个文件夹,还是建议使用Beyond Compare 4
  2. git 自身的diff工具如果用的不舒服,可以改成vscode呢!这个文章是写怎么设置的,其他工具设置方法类似https://blog.csdn.net/LeonBec/article/details/78989149
  3. 可视化的git工具,小乌龟我用的还是很习惯的,建议下载一个。https://tortoisegit.org/
  4. 真的很讨厌用命令行装B,骗骗外行还行,这里怼一下那些天天 git add . 提交所有文件,也不diff一下的菜鸡

    思考与尝试

    devtools自带的diff工具,不知道git 命令行能不能设置成这个工具,知道的小伙伴评论区见哈!

record-timeline-undocked.gif
当您需要在Mac上执行时间线录制时,请尝试将DevTools停靠到一个单独的窗口中,以便将录制按钮放在需要执行操作的页面部分附近。

或者,使用快捷键Cmd + E启动和停止录制。

通过这种方式进行录制,可以使录制的内容简短而甜美,并且可以减少录制时的“杂音”,因为您无需长时间在页面上移动鼠标。

补充

  1. 录制时间线的重点就是,缩短录制时间,仅仅录制要分析的操作,这样大大减少了分析成本。这个小技巧就是干这个的。
  2. 有时候输入法的快捷键会跟我们的IDE快捷键冲突,比如 ctrl shift f在vscode中是聚焦到搜索面板,搜狗输入法是繁简体切换,Hotkey Commander [ 下载 ]这个工具可以检测快捷键的冲突
    image.png

    思考

    假如我们写一个vscode 插件,怎么尽可能的不与现有的快捷键冲突

目标读者

WEB 应用 设计& 开发 & 测试 & 重度用户

关于调试

WEB应用开发者中,设计=》开发=》测试=》BUG修复=》回归测试=》发布=》部署。Chrome Devtool 都是必须要掌握的知识。在项目中,发现很多同事写代码还行,遇到问题就解决的很慢,或者无从下手。玩转调试可以:

  1. 增加开发效率
  2. 快速定位问题
  3. 降低沟通成本

阅读前

请先阅读 Google Chrome DevTools 官方文档(https://developers.google.cn/web/tools/chrome-devtools/)

来源与改进

文章主要来源于(https://umaar.com/dev-tips/) ,并做以下改进

  1. 汉化
  2. 部分过时的gif重录
  3. 加上自己的理解

计划

三月底完成!

目录

  1. Port Forwarding 允许localhost URL 在移动设备调试
  2. 如何使用DevTools触发CSS伪类
  3. 使用cURL复制功能重播Network面板的请求
  4. 在任何网页上运行预定义的代码段
  5. 通过本地修改查看您的更改
  6. 轻松的使用性能面板录制时间线
  7. 将图片复制为base64编码data URI
  8. 资源面板Source中的快捷键
  9. 多光标编辑 框选
  10. Console面板的一些API
  11. Network 网络面板过滤器
  12. Element面板
  13. 通过快捷键快速切换 devtools 附着状态
  14. 断点调试相关的技巧
  15. 颜色拾取器增强
  16. 动画调试
  17. 调试jquery 事件监听
  18. 隐藏网络请求报错的console.error
  19. 使用console.table 更好的展示对象 数组信息
  20. Element面板快速切换class查看效果
  21. 降低CPU的性能与网络速度来观测性能
  22. 使用 Sources 面板 Threads 调试
  23. 使用sourceMap 调试ESNext语法
  24. 在“Network”中查看来自其他应用程序的网络流量
  25. 通过Performance面板录制,行级别查看代码耗时
  26. Store as global variable 存储成全局变量
  27. 利用Quick Source 快速写样式
  28. Chrome带参数启动
  29. 自定义Network面板的显示列,展示我们关心的响应头
  30. devtools支持热更新调试Nodejs
  31. Blackboxing 获得更好的调试会话
  32. lighthouse 面板检查网页状态
  33. css tracker面板查看未使用的css
  34. 通过服务器增加 Server-Timing 响应头展示时间信息
  35. Network 查看实际访问的IP
  36. 自定义时间测量API
  37. 查看帧率FPS
  38. 复制完整的调用栈
  39. 网页全页截图

通过事件解耦和隔离代码是javascript的一个原生特性,参考浏览器的DOM事件模型

3.1 基于事件的好处

  • 应用程序都与消息传递有关
  • 拿到其他对象的消息
    全局对象(易污染)
    函数参数传入(参数过多)
    函数参数注入(要维护注入列表)
    局部初始化(紧耦合)
  • 函数是javascript的第一公民
  • 浏览器 DOM是事件模型
  • nodejs 利用回调实现异步编程

    3.2事件集线器

  • 一个中央处理器(110接警中心)
  • 向中央处理器注册事件的处理器(派出所,交警,刑警,消防,120急救中心,等)
  • 事件触发器(打110报警的用户)
    1
    2
    3
    4
    5
    eventHub.fire('着火了',{address:'南山腾讯大厦',leave:'烧了10层'})
    eventHub.listen('着火了',killFire)
    function killFire(msg){
    console.log(`出动消防车到${msg.address}去灭火,火灾等级${leave}`)
    }
    集线器属于公共耦合,但在集线器对象里,没有共享的状态

    3.2.1使用事件集线器

    3.2.2事件的响应

    3.2.3基于事件的架构与MVC架构(思想一致)

    MVC倡导 关注点分离与模块化,基于事件的架构都满足
    事件集线器==Controller
    事件传递的数据==Model数据库的行
    事件推送的数据==View查询模型获得数据

    3.2.4基于事件架构与面向对象编程(不冲突,可以一起用)

    面向对象=》继承耦合
    面向对象=》没有链式交互对象
    事件架构=》数据都是私有的,仅通过事件API暴露
    事件架构=》没有生命周期问题,对象存在于整个应用程序生命周期,不需要析构

    3.2.5 基于事件的架构与软件及服务(促进关系)

    软件及服务(SaaS),每个独立的服务都可以加入事件集线器

3.3 web应用程序

web应用程序大多与web服务器搅合在一起
让事件集线器成为web应用程序的中心,而不是web服务器
使用socke.io可以解决http同源的问题

3.4测试基于事件的架构

略……

3.5基于事件的架构说明

  1. 可伸缩性
    集线器宕机,则整个app宕机,所以,搞一组集线器负载匀衡
  2. 广播
    广播给所有客户端会产生大量通信流量,所以慎用
  3. 运行时检查
    函数和方法名 拼写错误,编译器能检查到,但是事件是字符串不能检查到,建议使用枚举值
  4. 安全性
    事件集线器实现“可信任”客户端身份验证
    socket.io支持数据加密
  5. 状态
    web服务器通过会话cookie记录状态
    事件集线器本身会将会话注入到事件中

3.6更智能的集线器,事件交换机

事件分组:广播,单播
特性:节省网络带宽,自动防故障安全部署

3.6.1部署

新版本部署=重启web服务(一般的web应用)
目标:模块完全独立于web服务的部署(跟微服务的架构很像啊)
条件:停用事件监听而不删除事件
方式:事件交换机

1
2
3
4
5
6
7
8
9
10
11
12
13
eventSwitch.on('depositMoney',function(data){
cash+=data.depositAmount;
eventSwitch.emit('depositMoney',cash)
},{type:'unicast'})//告知注册的是单播事件
//eventClient:done 这个事件不能由已连接的客户端触发
//单播
eventHub.on('eventClient:done',function(event){
process.exit(0)
})
//广播
eventHub.on('eventClient:done',function(event){
eventHub.removeAllListeers(event)
})

3.6.2一种实现

https://github.com/zzo/EventHub
npm install EventHub安装
npm start EventHub启动 默认监听5883端口

3.6.3 会话

1
2
3
4
5
eventHub=require('EventHub/clients/server/eventClient.js')
.getClientHub('http://localhost:5886?token=secret')
eventHub.on('user',function(obj){
var sessionID=obj['eventHub:session']
})

3.6.4 可拓展性

socket.io 支持多种客户端,多种语言,不仅仅是javascript
一个例子https:github.com/zzo/BidSilent

3.7 小结

  • 基于事件的架构
    高度模块化
    松耦合
    小依赖
    高可重用性
    便于创建可测试javascript

  • 事件集线器构建在 socket.io 上

  • MVC实际上是用事件进行了增强

  • 基于事件的架构开启了软件即服务,根据需要对小而独立的功能进行动态增删

  • 使用事件交换机部署基于事件的模块非常容易,允许单独关闭旧模块,而不丢任何事件

  • 测试已经隔离的模块更简单

目录

  1. 代码大小
  2. JSLint
  3. 圈复杂度
  4. 重用
  5. 扇出
  6. 扇入
  7. 耦合(耦合度由大到小排列)
    内容耦合
    公共耦合
    控制耦合
    印记耦合
    数据耦合
    无耦合
    实例化
  8. 耦合性度量
  9. 现实中耦合
  10. 依赖注入
  11. 注释
    YUIDoc JSDoc Docco/Rocco
  12. 人工测试
  13. 小结

1.代码大小

定义:函数的行数(包括注释行数)
减少该复杂度的方式 拆函数

  • 命令(command)和 查询(query)分离
    命令(command):没有return 的函数
    查询(query):带return 的函数

    2.JSLint

  • *规范书写语法**,简洁代码,减少复杂度

    3.圈复杂度

  • *定义:获得100%代码覆盖率需要编写的单元测试个数(if/else/switch/then 的使用)
    最佳实践:
    方法的圈复杂度应该小于10个**,>25个一定有bug;>100个,bug越改越多
    检测工具:jscheckstyle

    npm i -g jscheckstyle

理论与实践
我做的项目中有一个判断基站颜色显示的逻辑,绘制canvas站点的fillStyle
入参包括

  • 是否规划站 黄色
  • 是否现网站 蓝色
  • 是否新建站 绿色
  • 天线型号 2t2t 4t4r 8t8r 16t16r 基于站点类型增加颜色饱和度
  • 是否离线站点 灰色
  • 是否搜索结果 红色
    这些放在一个方法里面的圈复杂度应该是
    圈复杂度=天线4站点类型3是否离线2*是否搜索结果2=48
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function getColor(siteType,trType,isSearchResult,isOffAir){
    var color='blue'
    if(isSearchResult){
    return color='red'
    }
    if(isOffAir){
    return color='gray'
    }
    //这里项目中用的if else if else 的嵌套结构,太恶心,这里用switch优化了下
    switch(siteType){
    case 'current':
    if(trType=='2t2r')color='淡蓝'
    if(trType=='4t4r')color='浅蓝'
    if(trType=='8t8r')color='蓝'
    if(trType=='16t16r')color='深蓝'
    break;
    case 'new':
    if(trType=='2t2r')color='淡绿'
    if(trType=='4t24')color='浅绿'
    if(trType=='8t8r')color='绿'
    if(trType=='16t16r')color='深绿'
    break;
    case 'plan':
    if(trType=='2t2r')color='淡黄'
    if(trType=='4t24')color='浅黄'
    if(trType=='8t8r')color=' 黄'
    if(trType=='16t16r')color='深黄'
    break;
    default:

    }
    return color
    }
    尝试降低上面这个方法的圈复杂度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    getColor(siteType,trType,isSearchResult,isOffAir){
    var colorMap={
    current:{
    '2t2r':'淡蓝',
    '4t4r':'浅蓝',
    '8t8r':'蓝',
    '16t16r':'深蓝'
    },
    'new':{
    '2t2r':'淡蓝',
    '4t4r':'浅蓝',
    '8t8r':'蓝',
    '16t16r':'深蓝'
    },
    plan:{
    '2t2r':'淡蓝',
    '4t4r':'浅蓝',
    '8t8r':'蓝',
    '16t16r':'深蓝'
    }
    }
    var color='blue'
    if(isSearchResult){
    return color='red'
    }
    if(isOffAir){
    return color='gray'
    }

    try{
    color =colorMap[siteType][trType]
    }catch(e){
    console.log('colorMap 中没有定义这个颜色')
    }

    return color
    }
    后续如果增加新的站点类型或者天线类型,只要维护mapColor这个hash表就行了,不会再增加代码的圈复杂度,代码的可读与可维护性大大增强

    4.重用

  • 同样的代码不要写两次* 没什么好说的,就像出轨有了第一次就一定有第二次……
    另外就是能使用框架,就不要自己造轮子

    5.扇出Fan-Out(这个词好难理解),对应的还有扇入Fan-In

  • *定义**:函数直接或间接使用的模块或者对象数量
    个人理解:扇出就衡量一个函数做多少事。类比于人做事情,就是这个人指挥别人做的+他自己做的
  • *复杂度计算公式**: (fan_in * fan_out)²
  • *扇出计算公式**:扇出=内部流程数量(指挥别人做的)+所更新数据结构数量(自己做的)
  • *最佳实践:函数的扇出应该小于等于4**,绝对不要大于7,超过的话就需要重构
    解决方式:拆分模块,依赖注入
    例子:requirejs定义一个模块,下面的就需要拆分了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //拆分前
    define([a,b,c,d,e,f,g,h],function(a,b,c,d,e,f,g,h){//定义一个模块,依赖了7个小模块
    var module={
    a,b,c,d,e,f,g,h
    }
    return module
    })
    //拆分后
    define([],function(a,b,c,d){
    function SubModule(){
    this.a=new a()
    this.b=new b()
    this.c=new c()
    this.d=new d()
    }
    subModule.prototype.getA=function(){return this.a}
    subModule.prototype.getB=function(){return this.b}
    subModule.prototype.getC=function(){return this.c}
    subModule.prototype.getD=function(){return this.d}
    return subModule
    })
    define([subModule,e,f,g,h],function(subModule,e,f,g,h){//仅仅减小扇出,但无实际意义
    var module={
    a:subModule.getA(),
    b:subModule.getB(),
    c:subModule.getC(),
    d:subModule.getD(),
    e,f,g,h
    }
    return module
    })

    6.扇入(入参?)

    定义:过程A的扇入是 过程A的内部流程数量 与 欲从过程A中获取信息的数据结构总和
    高扇入复用程度越高,底层函数应该扇入高,扇出低。上层函数应该扇入低,扇出高。这样能保证函数的复杂度都比较低。

    7.耦合

    《编写可测试javascript》 第二章 复杂度(二)

制作支付宝的商家收钱码电子版

申请商家收款码

此过程通过支付宝官方渠道获取

电脑获取收款码照片

手机拍照,然后通过QQ或者微信上传到电脑都可以

识别二维码内容

上传二维码照片,识别出里面的网址
image

生成新的二维码图片

复制扫描结果,生成新的二维码,然后就可以拿着这个去打印店打印各种尺寸的收款码了

image

修改_config.yml文件

  1. 在gems中增加jekyll-feed依赖
  2. 配置插件jekyll-feed
  3. 页面中启用RSS按钮的显示
1
2
3
4
5
6
7
plugins:
- jekyll-feed


gems:[jekyll-feed]

RSS: true

根目录下应该有 feed.xml

具体可以参考为Jekyll博客添加RSS feed订阅功能