OLong

OLong 查看完整档案

武汉编辑  |  填写毕业院校无业  |  求职 编辑填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

OLong 赞了文章 · 3月22日

推荐 7 个 Vue2、Vue3 源码解密分析的重磅开源项目 👍

大家好,我是你们的 猫哥,那个不喜欢吃鱼、又不喜欢喵 的超级猫 ~

1. 为什么要学习源码 ?

  1. 阅读优秀的代码的目的是让我们能够写出优秀的代码。
  2. 不给自己设限,不要让你周围人的技术上限成为你的上限。

其实就跟我们写作文一样,你看的高分作文越多,写出高分作文的概率就越大。

基于现在的程序员工作模式(模块化开发,只需要拿到需求做自己的部分),别说看源码,甚至就连项目里的代码都懒的去看,我认识的很多程序员就是这样的,一个项目摸了两三年,你要问他项目中 webpack 都干了哪些事情,他的回答是不知道,反而趾高气扬的告诉你,那些他从来都用不上,看了也没什么用,也看不懂,这里省略内心千字脏文。

阅读主要目的 是为了帮助我们 积累素材,不要书到用时方恨少,看到美女我们应该能有一万种词语去形容,如气若幽兰,美艳不可方物,一笑倾城,再笑倾国,世间尤物,而不是简短的几个字,我艹,美女!

功利性的阅读源码

功利性即指有目的性的,明确知道自己干完某一件事后能得到什么样的回报,所以首先你要知道你想得到什么?

看每一本书都有明确的目的,想学会理财,就得看理财相关的书,想学点技术,就得看点技术相关的书

看源码也是一样,你对 Vue.use 之后发生了什么比较好奇,或者是你觉得现在面试都需要会看点源码,这都很好,至少你有明确的诉求

凡事只要有了功利属性,才更容易走的下去,否则就是真香警告。

2. Vue2

Vue 虽然出到 Vue3 了,也出了不少 Vue3 的源码教程,但是 Vue2 还是很棒的框架,它的源码还是值得细读的,所以先推荐几个 Vue2 的源码项目。

2.1 vue-analysis

👍 Vue.js 源码分析

目前社区有很多 Vue.js 的源码解析文章,但是质量层次不齐,不够系统和全面,这本电子书的目标是全方位细致深度解析 Vue.js 的实现原理,让同学们可以彻底掌握 Vue.js。目前分析的版本是 Vue.js 的最新版本 Vue.js 2.5.17-beta.0,并且之后会随着版本升级而做相应的更新,充分发挥电子书的优势。

这本电子书是作为 《Vue.js 源码揭秘》 视频课程的辅助教材。电子书是开源的,同学们可以免费阅读,视频是收费的,25+小时纯干货课程,如果有需要的同学可以购买来学习,但请务必支持正版,请尊重作者的劳动成果

https://github.com/ustbhuangy...

2.2 vue-design

超级详细 - 逐行级别的分析

所谓逐行并非一行接着一行,逐行指的是讲解的详细程度,这套文章将致力于覆盖所有核心代码,毕竟每一句代码都有他存在的意思,假如我们不讲明白任何一句代码的意义,那又怎么敢说是源码分析呢?

深度分析 - 讲解 issue

我们知道 Vue 这个项目自诞生以来一直都在不断的更新完善,比如添加新的特性,修复已知bug等等。而在这个过程中源码也将越来越完善,这也意味着代码曾经并不完善,本套文章在分析源码时除了告诉你这段代码为什么这么写之外,还会根据相关 issue 分析这段代码之前是怎么写的以及存在的问题。

http://hcysun.me/vue-design/zh/

2.3 vue-family-mindmap

用一张思维导图总结了 Vue | Vue-Router | Vuex 源码与架构要点。

以上内容是笔者最近学习 Vue 源码时的收获与所做的笔记,本文内容大多是开源项目 Vue.js 技术揭秘 的内容,只不过是以思维导图的形式来展现,内容有省略,还加入了笔者的一点理解。

笔者之所以采用思维导图的形式来记录所学内容,是因为思维导图更能反映知识体系与结构,更能使人形成完整的知识架构,知识一旦形成一个体系,就会容易理解和不易忘记。

注意:文章的图片可能上传时会经过压缩,可能有点模糊,不过本文用到的 所有 超清图片 都已经放在 github 上,而且还有 pdf 格式、markdown 语法、思维导图 的原文件,自己可以根据 思维导图原文件 导出相应的超清图片。
https://github.com/biaochenxu...

2.4 learnVue

Vue.js 源码分析,记录了个人学习 Vue.js 源码的过程中的一些心得以及收获。以及对于 Vue 框架,周边库的一些个人见解。

在学习的过程中我为Vue.js(2.3.0)、Vuex(2.4.0)、Vue-router(3.0.1)加上了注释,分别在文件夹 vue-src、vuex-src 以及 vue-router-src 中,希望可以帮助有需要的同学更好地学习理解 Vue.js 及周边库的源码。

https://github.com/answershut...

2.5 vue

Vue 源码逐行注释分析 +40 多 M 的 Vue 源码程序流程图思维导图 (diff 部分待后续更新)

Vue 源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了 。

这个 Vue 源码逐行分析,我基本每一行都打上注释,加上整个框架的流程思维导图,基本上是小白也能看懂的 Vue 源码了。

https://github.com/qq28111327...

2.6 vue2.0-source

Vue 源码分析 -- 基于 2.2.6 版本

该源码分析,会带着大家一起学习 Vue 的大部分代码,而不是简单的讲一下它的原理,我会尽可能的多解释每一行主要的代码含义,另外一些辅助方法什么的,大家可以在学习的过程中,自己看一眼就知道了。

https://github.com/liutao/vue...

3. Vue3

3.1 中文学习网址

先给大家提供 2 个 Vue3 的中文学习网址。

Vue3 中文文档,国内 CDN 加速版

https://vue3js.cn/docs/zh/

Vue3 相关项目聚合网站

https://vue3js.cn/

3.2 Vue3 源码

https://vue3js.cn/start/

最后

更多关于 Vue3 的优质项目,请看往期精文: Vue3 的学习教程汇总、源码解释项目、支持的 UI 组件库、优质实战项目

公众号:前端GitHub,专注于挖掘优秀的前端开源项目,抹平你的前端信息不对称。

平时如何发现好的开源项目,可以看看这篇文章:GitHub 上能挖矿的神仙技巧 - 如何发现优秀开源项目


关于猫哥,大家可以看看我的年终总结 前端工程师的 2020 年终总结 - 乾坤未定,你我皆黑马

不知不觉,已经写到第 31 期了呢,往期精文请看下方宝藏仓库,请慎入!

https://github.com/FrontEndGitHub/FrontEndGitHub

微信搜 “前端GitHub”,回复 “电子书” 即可以获得 160 本前端精华书籍,回复 “1024”,获取前端精华学习视频。

往期精文

查看原文

赞 45 收藏 34 评论 0

OLong 赞了文章 · 3月22日

有哪些道理是我当了程序员后才知道的?

前几天在知乎给我推送了一个话题:有哪些道理是你当了程序员后才知道的?

然后当时我就花了几分钟的时间去回答了一下。

嘿,你猜怎么着?

我发现我一个知乎小透明,给这个回答点赞的人还挺多:

我也在公众号里面给大家分享一下吧,但是下面的这些观点,都是我的一家之言,理性讨论,不要开杠。

以下是原回答。

1
-

1.当你明白了技术永远是为了业务服务的时候,不再技术至上的时候,你就成长到程序员的下一个阶段了。

2.业务第一,产品第二,技术第三。

3.盈利了,是业务部门把钱搞来的,技术部门是支出部门。

4.年轻的时候什么都想学,后来发现学的速度永远跟不上技术迭代的速度。

5.不要想着在自媒体上,比如知乎、公众号进行学习(虽然我也在上面写技术文)。正经人谁在公众号里面学习?买几本书系统的学习不好吗?公众号鱼龙混杂,有优质的,但是很难碰到。上面只适合查漏补缺。

6.学一个技术的时候,永远不要问看哪本书比较好,特别是两本书口碑差不多的情况下。最好都买,对比着学。买一本书,看了就把一门技术掌握了?想啥呢?绝大部分都是勉强入个门而已。

7.不要好奇问同事薪资。问就是红线。关系好也不行,谁问谁尴尬。觉得自己钱少了就提涨薪或者跳槽,问别人多少钱干啥?想带着一起走啊?

8.技术面的时候面试官问期望薪资,99.99%都是出于好奇,要么打马虎回答一下,那么往低了说。

9.别老是埋头搞技术,也抬头看看自己,做好自己的健康管理。

10.入了这行,别想着把生活和工作分的很开,99.99%的程序猿都是生活工作相互交错。且工作多于生活。

11.技术人员认知的层次。第一阶段:技术为上。第二阶段:业务为上。第三阶段:技术业务均衡协调都不可缺。

12.业务是首位,但技术是核心竞争。

13.开发语言只是工具,不要崇尚某一个语言,也不要排斥某个语言。

14.如果你是一个情商比较低的程序猿,注意这方面的提升,对个人工作生活有帮助。

15.开发和产品似乎是对立面,但是尽量试着去理解产品经理,而不是对着干,投桃报李,不然大家干的都难受。

16.对测试同学客气一点,他们是你写的代码的最后一道防线。

17.面试成功率=6分实力+3分运气+1分眼缘。

18.作为你的领导或者协作者在工作的过程中,最不喜欢听到的应该是诸如“我试试,我尽量...”这样的话。比较负责任的,好一点的回答是:我将在....之前....(例如:我将在下周二之前完成这个任务)。

19.学会夸奖别人,学会识别捧杀。

20.圈子很重要,要努力的往更加优秀的圈子里面靠。虽然听起来挺没有意思的,但是如果想要职业生涯越走约好,选对圈子跟对人还是很重要的。

21.不仅要不断的学习新的技术,也要不断的学习职场之道,为人处世之道。

......

其实还有很多可以补充的,但是先不写了,想起了再更新吧,就这样,我要去学习,只要我学的够快,你们就卷不到我。

2
-

然后下面的一些评论也挺有意思的,我翻几个给大家看看:

首先是这个高赞评论。

是针对密薪制的。

说真的,我从来没有打听过别人的工资,我也知道这是资本主义的手段。曾经我对这个制度也感觉到困惑,现在释然了,所以我才从自己的角度去拥护了一下密薪制。

这个东西,见仁见智吧。

感觉没啥可以杠的。

这个评论确实是看的我一愣,评论者和我站的高度都不一样。

很明显,他的高度比我高很多。

我就是想着个人的职业生涯,他却心怀整个国家。

很欣慰,respect。

杀人是业务,枪是产品。

这个比喻,非常的 skr。

就在我写这篇文章的时候突然又收到了一个评论,只有八个字:

我看到后,啪的一下,很快啊,就是一个点赞。

一针见血。

当我还是一个年轻程序员的时候,当然我现在也很年轻,我真的特别喜欢一句话:你的指尖,有改变世界的力量。

想象着自己以后变成一个很厉害的人,被光环围绕。

现在呢?

见鬼去吧,我不想改变世界了。我就想做个普通人,养一条狗、一只猫,有一个小房子和一个爱人,有酒喝,有歌唱,就行了。

这就是成长,这也是异化。

还有一个哥们直接私信给我建议,我也送给大家吧:

那么有哪些道理是你当了程序员后才知道的呢?

在评论区分享一下吧。

查看原文

赞 7 收藏 3 评论 2

OLong 赞了文章 · 3月21日

涂鸦智能登陆纽交所!用 7 年打造出“全球 IoT 云平台第一股”

涂鸦智能

美国东部时间 3 月 18 日,全球领先的 IoT 云平台涂鸦智能(股票代码:TUYA)正式登陆纽约证劵交易所,宣告“全球 IoT 云平台第一股”成功挂牌上市。

在行使超额配售选择权让承销商购买任何额外的美国存托股份(ADS)之前,涂鸦智能共发行 4359 万股美国存托股份(ADS),每股 ADS 定价 21 美元,总发行规模约为 9.154 亿美元。


随着物联网以及通信行业的发展,全球已逐渐呈现一种新的趋势:全面拥抱数字化、智能化、线上化,人与人之间、物与物之间将全面连接起来,万物互联时代即将来临。

而从产业端来看,据《2020 年中国智能物联网(AIoT)白皮书》报告显示,全球 AIoT 开发者关注开发平台的三大特性:设备之间是否互联互通、应用开发、数据的存储和分享。而在全球范围内,真正满足这三个特性的开发者平台少之又少。涂鸦智能作为一家成立仅 7 年的公司,却正在从开发者的需求出发,试图打造出一个 All in one 的全链路 IoT 开发平台。

涂鸦智能成立于 2014 年,主营物联网平台开发,连接品牌、OEM 厂商、开发者以及连锁零售商的智能化需求,提供一站式人工智能物联网的 PaaS 级解决方案。

在 2020 年举办的全球硬科技开发者大会上,涂鸦智能创始人兼董事长陈燎罕发表了“AIoT 生态增殖 —— 从生态打造到生态自造”的主题演讲,分享了涂鸦 IoT 开发平台 2020 年开发者生态、全球渠道、商业落地和生态布局等全方位的战略成果,宣告涂鸦智能不只是一个 AIoT 平台,更有能力为全球各行各业的开发者输出生态,帮助开发者打造属于自己的智能生态。

根据陈燎罕在大会中的分享,涂鸦智能除了是一个 IoT 开发平台,更重要的角色是输出“生态”,即涂鸦智能为开发者提供产业链和技术等支持外,还助力开发者打造自有生态。如,通过涂鸦云开发平台,开发者可以构建出基于社区、公寓、酒店、安防等不同场景的 PaaS 解决方案。目前已有近 2 万名云开发者,和涂鸦智能共同打造了多个行业的智慧解决方案。


据《2020 年中国智能物联网(AIoT)白皮书》数据显示,预计到 2025 年,而中国 AIoT 市场规模突破 3000 亿大关,并直指 4000 亿量级。

同时,新冠疫情之下,无接触科技成为主流,这让终端用户更习惯于使用语音控制。并且,疫情让更多用户认识到智能家居的重要性,全球各地的智能设备销售需求也相应增长,目前,涂鸦智能全球合作的销售渠道已超10万个,包括:HomeDepot、沃尔玛、山姆会员店、Lidl等线上和线下渠道。涂鸦智能在技术、生态和渠道等层面的战略优势,也获得了市场的支持,目前已有近30家世界500强企业成为涂鸦智能的深度合作伙伴,包括:施耐德、三星、中国电信、微软、亚马逊、谷歌和京东等。

涂鸦智能

在杭州举行的云敲钟仪式上,包括涂鸦智能创始人兼CEO王学集、联席董事长兼总裁陈燎罕、董事兼CFO刘尧以及纽约证券交易所中国区首席代表杨旭在内的十余位嘉宾,共同敲响了上市钟声。

王学集在演讲中表示:“感谢政府领导、投资人、合作伙伴和团队的一路支持,涂鸦在一个不看好 IoT 赛道的年代创立,过去 7 年,我们披荆斩棘,秉持技术创新的精神和全球化的战略,在全球 IoT 领域开辟一条生路。涂鸦团队就好像 Tuya 的英文名:‘冰川下的火山’,远看是冰雪覆盖的高山,低调,但可能随时蓄势爆发。”

segmentfault 思否

查看原文

赞 2 收藏 0 评论 0

OLong 关注了用户 · 2月25日

kumfo @kumfo

程序生存法则:ฏ๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎ฏ๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎ฏ๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎
1.不要写死
2.不要相信产品⎝≧⏝⏝≦⎠
设计生存法则:
1.不要相信这是最终效果图
2.不要相信产品

测试生存法则:
1.不要立flag
2.不要相信程序
产品生存法则:
1.不要相信任何人
2.注意人身安全
运营生存法则:
1.不要相信任何人
2.躲在产品身后

关注 2077

OLong 发布了文章 · 2月24日

如何排查并修复内存泄漏

要如何找到内存泄漏的地方?

网络上大部分文章只会介绍一下基础知识,然后附上一下简单到令人发指的例子。但是问题是:实际项目根本不可能这么简单,内存泄漏隐藏在浩如烟海的代码山当中。想靠基础知识解决问题,几乎不可能。

或者告诉你如何使用Chrome开发者工具去记录和对比内存堆栈。于是看着内存变量列表里几十万个变量,犹如大海捞针。

代码多,文件多,找导致内存泄漏的问题代码必须要有条理。

按如下步骤来就行啦!

  1. 首先确定导致内存泄漏的模块和什么样的操作会导致内存泄漏。
  2. 确定出现了内存泄漏的文件范围。并找到这一块文件的总入口。
  3. 整理入口文件的依赖。把依赖过的所有文件列成表记下来。
  4. 按照表中的顺序,依次从代码中注释掉每个文件,去掉对其的依赖,并测试内存泄漏是否还在。
  5. 如果还会内存泄漏,则该文件是无辜的。如果不会,则找到了出现了内存泄漏的文件。由此缩小了问题文件的范围。
  6. 重复1~5的步骤,直到问题文件范围尽可能的小。
  7. 当问题文件范围小到剩下一个文件时,则把1~5的步骤的原理用在此文件的每一行代码中。
  8. 一行一行注释问题文件中的代码,并测试内存泄漏是否还在。
  9. 直到找到出问题的那一行或一部分代码。
  10. 找到问题代码之后去解决问题就行。

直到第10步,最终定位到了出问题的代码。内存泄漏的基础知识才会发挥作用。
比如我刚解决的实际问题中,出问题的代码是在频繁往Vuex中存一个巨大对象。如果我不知道Vue双向绑定的原理,我只会觉得这行代码正常得一逼。

以上是解决内存泄漏问题的一个行之有效的办法。

查看原文

赞 3 收藏 1 评论 3

OLong 发布了文章 · 2020-12-23

详解Vue中的$nextTick

当在代码中更新了数据,并希望等到对应的Dom更新之后,再执行一些逻辑。这时,我们就会用到$nextTick

funcion callback(){
 //等待Dom更新,然后搞点事。
}
$nextTick(callback);

官方文档对nextTick的解释是:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

那么,Vue是如何做的这一点的,是不是在调用修改Dom的Api之后(appendChild, textContent = "xxxxx" 诸如此类),调用了我们的回调函数?
实际上发生了什么呢。

源码

nextTick的实现逻辑在这个文件里:

vue/src/core/util/next-tick.js

我们调用的this.$nextTick实际上是这个方法:

export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    timerFunc()
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

可以看到

  1. 回调函数被存放到了一个数组里:callbacks。
  2. 如果没有传递回调函数,这个方法会返回一个Promise,然后吧reslove当成回调函数放到flushCallbacks中。所以文档解释了把本该当成回调函数的callbacks放到then里的用法。
  3. 然后,有一个变量叫pending,如果不在pending中,则执行函数timerFunc。而且pending默认等于false。
  4. flushCallbacks这个函数会一口气执行所有回调函数。

timerFunc

timerFunc定义在这里

可以看到timerFunc是在一个已resolve了的Promise的then 中执行了flushCallbacks.

利用了js事件循环的微任务的机制

所以,每当我们调用$nextTick,如果pending为false,就会调用timerFunc,然后timerFunc会把flushCallbacks给塞到事件循环的队尾,等待被调用。

if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
  }
}

flushCallbacks

然后在这个文件里还有一个函数叫:flushCallbacks
用来把保存的回调函数给全执行并清空。

function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}

pending

什么时候pending为true呢?

从timerFunc被调用到flushCallbacks被调用期间pending为true

即一个事件循环周期

在pending期间加入的回调函数,会被已经等待执行的flushCallbacks函数给执行。

核心机制

看完源码,发现除了利用了一个微任务的机制,和Dom更新一点关系都没有哇。

其实调用nextTick的不仅是开发者,Vue更新Dom时,也用到了nextTick。

开发者更新绑定的数据之后,Vue就会立刻调用nextTick,把更新Dom的回调函数作为微任务塞到事件循环里去。

于是,在微任务队列中,开发者调用的nextTick的回调函数,就一定在更行Dom的回调函数之后执行了。

但是问题又来了,根据浏览器的渲染机制,渲染线程是在微任务执行完成之后运行的。渲染线程没运行,怎么拿到Dom呢?

因为,渲染线程只是把Dom树渲染成UI而已,Vue更新Dom之后,在Dom树里,新的Dom节点已经存在了,js线程就已经可以拿到新的Dom了。除非开发者读取Dom的计算属性,触发了强制重流渲染线程才会打断js线程。

总结

  1. 首先timerFunc函数负责把回调函数们都丢到事件循环的队尾
  2. 然后,nextTick函数负责把回调函数们都保存起来。
  3. 调用nextTick函数时会调用timerFunc函数
  4. Vue更新Dom也会使用nextTick,而且在开发者调用nextTick之前。
  5. 因为4中的先后关系和事件循环的队列性质,确保了开发者的nextTick的回调一定在Dom更新之后
查看原文

赞 19 收藏 14 评论 2

OLong 赞了文章 · 2020-12-08

你知道 Chrome 为调试专门提供的这些函数吗?

在 Chrome 的 DevTools 中的控制台提供了一些 Debug 专用的函数,每一个都身怀绝技。

Console Utility Functions

这些函数只能用在 Chrome 的 console 中。当我在第一次看到这些函数时非常兴奋,把它们直接写到了自己的代码中,结果当然是跳出了各种 Uncaught ReferenceError:xxx is not defined 错误。

$_

$_ 会存储的执行结果,在控制台测试 JavaScript 的时候通常都需要逐步确认,这正是 $_ 的用武之地:

image.png

 

在遇到不能链式调用的函数时可以用 $_ 来避免游标被修改:

image.png

顺带提一句,将来也有可能会出现 Pipeline operator 来做到任意的函数链接,一次来促进提升性或避免修改内建原型。

let a;
a = 1
  |> ((n) => add(n, 5))
  |> double;

console.log(a); // 12

$, $$

$(selector[, element]), $$(selector[, element])

$$$ 分别就是 document.querySelectordocument.querySelectorAll 的缩写,其来源于大家都熟知的 JQuery。

第二个参数可以传入起始的元素,搭配 $0 就可以先检验一个元素,然后再从它开始搜寻。

$('.btn', $0)

我经常用 $$ 来快速测试一些东西,例如输出某个人 GitHub 页面的所有存储库名称:

image.png

不过如果已经把 JQuery 引入为 $ 的话,还是会正常执行 JQuery 的。

 

debug

debug(function)

参数为一个函数,只要执行到该函数就会触发调试器,可以用 undebug(fn) 来取消:

function a() {
  console.log(1);
}

debug(a);
// undebug(a);

其效果相当于:

function a() {
  console.log(1);
}
a = (function() {
  const origin = a;
  return function() {
    debugger;
    origin();
  }
})();

monitor

monitor(function)

用法和 debug 类似,monitor 函数被执行时会输出函数名称和参数,可用 unmonitor(function) 来停止,不过不能用于箭头函数,如果要监听箭头函数的执行就只能手动重写了。

monitorEvents

monitorEvents(element[, eventType])

可以监听并输出元素的特定事件,比较特别的是除了能监听单个事件,还能监听事件类型,例如输出 window 的点击事件和所有 touch 类别的事件:

image.png

效果和以下 JavaScript 相同:

window.addEventListener('click', console.log)
window.addEventListener('touchstart', console.log)
window.addEventListener('touchmove', console.log)
window.addEventListener('touchend', console.log)
window.addEventListener('touchcancel', console.log)

可以用 unmonitorEvents(element [, eventType])来停止监听。

image

getEventListeners

getEventListeners(element)

输出已注册在元素上的监听器,就拿刚才的例子来说,输入 monitorEvents(element) 后再输入 getEventListeners(element) 就会看到所有事件都被注册了一波:

image

展开的话可以看到监听器的各种属性:

  • listener:触发事件执行的函数
  • once:该监听器只会触发一次
  • passive:无法执行event.preventDefault(),通常用于提升监听器的性能,如 scroll
  • type:监听事件类型
  • useCapture:监听器会在 Capture 阶段拦截事件

以上属性都是在执行 addEventListener 时所能够提供的参数,别忘了在 removeEventListener 时也要填入相同的参数才能除监听器。

const options: {
  capture: true,
  passive: true,
  once: false
}
window.addEventListener('click', console.log, options);
// window.removeEventListener('click', console.log, options);

 

queryObjects

queryObjects(object)

官方说明是返回 Constructor 产生的所有实例,不过我的理解是:返回所有原型链中包含该原型的对象。

image.png

可以看到以 a 为原型创建的 b也会出现在 queryObjects(A) 的结果中。

另外由于 queryObjects 并不会直接返回数组,所以要点右键菜单中的 Store as global variable 把数组放进变量 temp1
 

copy

copy(object)

copy 能够把 DOM 或对象复制到剪贴板,我有时会用 copy 把对象转为 JSON 并粘贴到接口文档中,或者在控制台中快速创建或修改假数据。

image.png

还很贴心的加上了缩进

 

keys, values

keys(object), values(object)

输出对象本身的所有 key 或 value,效果与 Object.keys(object)Object.values(object)相同,为什么要强调自身呢?如果是用 in 来遍历对象的每个属性,就会把原型链上所有的属性全都拿出来出来跑一遍:

const object = Object.create({ foo: 1});
object.bar = 2;
for (let key in object) {
  console.log(key)
}
// bar
// foo
除了自身的 key,还要 enumerable or not.)。

如果想要确认属性是否是定义在对象本身可以用 Object.prototype.hasOwnProperty

for (let key in object) {
  if (Object.prototype.hasOwnProperty.call(object, key)) {
    console.log(key);
  }
}
// bar

至于为什么不用 object.hasWonProperty(key),请参考下面的代码:

const object1 = {
  hasOwnProperty: function() {
    return false;
  },
};
const object2 = Object.create(null);

object1.key = 'key';
object2.key = 'key';

object1.hasOwnProperty('key'); // ?
object2.hasOwnProperty('key'); // ?

clear

clear()

虽然点击左上角的 🚫 就可以把 Console 清理干净,但我还是习惯用 clear(),就像在终端中输入clear 那样。

image.png

注意在 Preserve log 开启的情况下不能用 clear 清空 Console。

 

173382ede7319973.gif


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章


欢迎继续阅读本专栏其它高赞文章:


查看原文

赞 27 收藏 21 评论 0

OLong 收藏了文章 · 2020-10-27

前端项目自动化部署——超详细教程(Jenkins、Github Actions)

本教程主要讲解了怎么使用 Jenkins 和 Github Actions 部署前端项目。

  1. 第一部分是使用 Gitea 配置局域网 git 服务器,再使用 Jenkins 将 Gitea 下的项目部署到局域网服务器。
  2. 第二部分是使用 Github Actions 将 Github 项目部署到 Github Page 和阿里云。

阅读本教程并不需要你提前了解 Jenkins 和 Github Actions 的知识,只要按照本教程的指引,就能够实现自动化部署项目。

PS:本人所用电脑操作系统为 windows,即以下所有的操作均在 windows 下运行。其他操作系统的配置大同小异,不会有太大差别。

Gitea + Jenkins 自动构建前端项目并部署到服务器

Gitea 用于构建 Git 局域网服务器,Jenkins 是 CI/CD 工具,用于部署前端项目。

配置 Gitea

  1. 下载 Gitea,选择一个喜欢的版本,例如 1.13,选择 gitea-1.13-windows-4.0-amd64.exe 下载。
  2. 下载完后,新建一个目录(例如 gitea),将下载的 Gitea 软件放到该目录下,双击运行。
  3. 打开 localhost:3000 就能看到 Gitea 已经运行在你的电脑上了。
  4. 点击注册,第一次会弹出一个初始配置页面,数据库选择 SQLite3。另外把 localhost 改成你电脑的局域网地址,例如我的电脑 IP 为 192.168.0.118

在这里插入图片描述
在这里插入图片描述

  1. 填完信息后,点击立即安装,等待一会,即可完成配置。
  2. 继续点击注册用户,第一个注册的用户将会成会管理员。
  3. 打开 Gitea 的安装目录,找到 custom\conf\app.ini,在里面加上一行代码 START_SSH_SERVER = true。这时就可以使用 ssh 进行 push 操作了。

在这里插入图片描述

  1. 如果使用 http 的方式无法克隆项目,请取消 git 代理。
git config --global --unset http.proxy
git config --global --unset https.proxy

配置 Jenkins

  1. 需要提前安装 JDK,JDK 安装教程网上很多,请自行搜索。
  2. 打开 Jenkins 下载页面。

在这里插入图片描述

  1. 安装过程中遇到 Logon Type 时,选择第一个。

在这里插入图片描述

  1. 端口默认为 8080,这里我填的是 8000。安装完会自动打开 http://localhost:8000 网站,这时需要等待一会,进行初始化。
  2. 按照提示找到对应的文件(直接复制路径在我的电脑中打开),其中有管理员密码。

在这里插入图片描述

  1. 安装插件,选择第一个。

在这里插入图片描述

  1. 创建管理员用户,点击完成并保存,然后一路下一步。

在这里插入图片描述

  1. 配置完成后自动进入首页,这时点击 Manage Jenkins -> Manage plugins 安装插件。

在这里插入图片描述

  1. 点击 可选插件,输入 nodejs,搜索插件,然后安装。
  2. 安装完成后回到首页,点击 Manage Jenkins -> Global Tool Configuration 配置 nodejs。如果你的电脑是 win7 的话,nodejs 版本最好不要太高,选择 v12 左右的就行。

在这里插入图片描述

创建静态服务器

  1. 建立一个空目录,在里面执行 npm init -y,初始化项目。
  2. 执行 npm i express 下载 express。
  3. 然后建立一个 server.js 文件,代码如下:
const express = require('express')
const app = express()
const port = 8080

app.use(express.static('dist'))

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

它将当前目录下的 dist 文件夹设为静态服务器资源目录,然后执行 node server.js 启动服务器。

由于现在没有 dist 文件夹,所以访问网站是空页面。
在这里插入图片描述
不过不要着急,一会就能看到内容了。

自动构建 + 部署到服务器

  1. 下载 Jenkins 提供的 demo 项目 building-a-multibranch-pipeline-project,然后在你的 Gitea 新建一个仓库,把内容克隆进去,并提交到 Gitea 服务器。

在这里插入图片描述

  1. 打开 Jenkins 首页,点击 新建 Item 创建项目。

在这里插入图片描述

  1. 选择源码管理,输入你的 Gitea 上的仓库地址。

在这里插入图片描述

  1. 你也可以尝试一下定时构建,下面这个代码表示每 5 分钟构建一次。

在这里插入图片描述

  1. 选择你的构建环境,这里选择刚才配置的 nodejs。

在这里插入图片描述

  1. 点击增加构建步骤,windows 要选 execute windows batch command,linux 要选 execute shell

  1. 输入 npm i && npm run build && xcopy .\build\* G:\node-server\dist\ /s/e/y,这行命令的作用是安装依赖,构建项目,并将构建后的静态资源复制到指定目录 G:\node-server\dist\ 。这个目录是静态服务器资源目录。

在这里插入图片描述

  1. 保存后,返回首页。点击项目旁边的小三角,选择 build now

在这里插入图片描述

  1. 开始构建项目,我们可以点击项目查看构建过程。

在这里插入图片描述

  1. 构建成功,打开 http://localhost:8080/ 看一下结果。

在这里插入图片描述
在这里插入图片描述

  1. 由于刚才设置了每 5 分钟构建一次,我们可以改变一下网站的内容,然后什么都不做,等待一会再打开网站看看。

在这里插入图片描述

  1. 把修改的内容提交到 Gitea 服务器,稍等一会。打开网站,发现内容已经发生了变化。

在这里插入图片描述

使用 pipeline 构建项目

使用流水线构建项目可以结合 Gitea 的 webhook 钩子,以便在执行 git push 的时候,自动构建项目。

  1. 点击首页右上角的用户名,选择设置

在这里插入图片描述

  1. 添加 token,记得将 token 保存起来。

在这里插入图片描述

  1. 打开 Jenkins 首页,点击 新建 Item 创建项目。

在这里插入图片描述

  1. 点击构建触发器,选择触发远程构建,填入刚才创建的 token。

在这里插入图片描述

  1. 选择流水线,按照提示输入内容,然后点击保存

在这里插入图片描述

  1. 打开 Jenkins 安装目录下的 jenkins.xml 文件,找到 <arguments> 标签,在里面加上 -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true。它的作用是关闭 CSRF 验证,不关的话,Gitea 的 webhook 会一直报 403 错误,无法使用。加好参数后,在该目录命令行下输入 jenkins.exe restart 重启 Jenkins。

在这里插入图片描述

  1. 回到首页,配置全局安全选项。勾上匿名用户具有可读权限,再保存。

在这里插入图片描述
在这里插入图片描述

  1. 打开你的 Gitea 仓库页面,选择仓库设置

在这里插入图片描述

  1. 点击管理 web 钩子,添加 web 钩子,钩子选项选择 Gitea
  2. 目标 URL 按照 Jenkins 的提示输入内容。然后点击添加 web 钩子

在这里插入图片描述
在这里插入图片描述

  1. 点击创建好的 web 钩子,拉到下方,点击测试推送。不出意外,应该能看到推送成功的消息,此时回到 Jenkins 首页,发现已经在构建项目了。

在这里插入图片描述

  1. 由于没有配置 Jenkinsfile 文件,此时构建是不会成功的。所以接下来需要配置一下 Jenkinsfile 文件。将以下代码复制到你 Gitea 项目下的 Jenkinsfile 文件。jenkins 在构建时会自动读取文件的内容执行构建及部署操作。
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {  // window 使用 bat, linux 使用 sh
                bat 'npm i'
                bat 'npm run build'
            }
        }
        stage('Deploy') {
            steps {
                bat 'xcopy .\\build\\* D:\\node-server\\dist\\ /s/e/y' // 这里需要改成你的静态服务器资源目录
            }
        }
    }
}
  1. 每当你的 Gitea 项目执行 push 操作时,Gitea 都会通过 webhook 发送一个 post 请求给 Jenkins,让它执行构建及部署操作。

在这里插入图片描述

小结

如果你的操作系统是 Linux,可以在 Jenkins 打包完成后,使用 ssh 远程登录到阿里云,将打包后的文件复制到阿里云上的静态服务器上,这样就能实现阿里云自动部署了。具体怎么远程登录到阿里云,请看下文中的 《Github Actions 部署到阿里云》 一节。

Github Actions 自动构建前端项目并部署到服务器

如果你的项目是 Github 项目,那么使用 Github Actions 也许是更好的选择。

部署到 Github Page

接下来看一下如何使用 Github Actions 部署到 Github Page。

在你需要部署到 Github Page 的项目下,建立一个 yml 文件,放在 .github/workflow 目录下。你可以命名为 ci.yml,它类似于 Jenkins 的 Jenkinsfile 文件,里面包含的是要自动执行的脚本代码。

这个 yml 文件的内容如下:

name: Build and Deploy
on: # 监听 master 分支上的 push 事件
  push:
    branches:
      - master
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest # 构建环境使用 ubuntu
    steps:
      - name: Checkout
        uses: actions/checkout@v2.3.1  
        with:
          persist-credentials: false

      - name: Install and Build # 下载依赖 打包项目
        run: |
          npm install
          npm run build

      - name: Deploy # 将打包内容发布到 github page
        uses: JamesIves/github-pages-deploy-action@3.5.9 # 使用别人写好的 actions
        with:  # 自定义环境变量
          ACCESS_TOKEN: ${{ secrets.VUE_ADMIN_TEMPLATE }} # VUE_ADMIN_TEMPLATE 是我的 secret 名称,需要替换成你的
          BRANCH: master
          FOLDER: dist
          REPOSITORY_NAME: woai3c/woai3c.github.io # 这是我的 github page 仓库
          TARGET_FOLDER: github-actions-demo # 打包的文件将放到静态服务器 github-actions-demo 目录下

上面有一个 ACCESS_TOKEN 变量需要自己配置。

  1. 打开 Github 网站,点击你右上角的头像,选择 settings

在这里插入图片描述

  1. 点击左下角的 developer settings

在这里插入图片描述

  1. 在左侧边栏中,单击 Personal access tokens(个人访问令牌)

在这里插入图片描述

  1. 单击 Generate new token(生成新令牌)

在这里插入图片描述

  1. 输入名称并勾选 repo

在这里插入图片描述

  1. 拉到最下面,点击 Generate token,并将生成的 token 保存起来。

在这里插入图片描述

  1. 打开你的 Github 项目,点击 settings

在这里插入图片描述
点击 secrets->new secret
在这里插入图片描述
创建一个密钥,名称随便填(中间用下划线隔开),内容填入刚才创建的 token。
在这里插入图片描述

在这里插入图片描述
将上文代码中的 ACCESS_TOKEN: ${{ secrets.VUE_ADMIN_TEMPLATE }} 替换成刚才创建的 secret 名字,替换后代码如下 ACCESS_TOKEN: ${{ secrets.TEST_A_B }}。保存后,提交到 Github。

以后你的项目只要执行 git push,Github Actions 就会自动构建项目并发布到你的 Github Page 上。

Github Actions 的执行详情点击仓库中的 Actions 选项查看。

在这里插入图片描述
在这里插入图片描述
具体详情可以参考一下我的 demo 项目 github-actions-demo

构建成功后,打开 Github Page 网站,可以发现内容已经发布成功。

在这里插入图片描述

Github Actions 部署到阿里云

初始化阿里云服务器

  1. 购买阿里云服务器,选择操作系统,我选的 ubuntu
  2. 在云服务器管理控制台选择实例->更多->密钥->重置实例密码(一会登陆用)
  3. 选择远程连接->VNC,会弹出一个密码,记住它,以后远程连接要用(ctrl + alt + f1~f6 切换终端,例如 ctrl + alt + f1 是第一个终端)
  4. 进入后是一个命令行 输入 root(默认用户名),密码为你刚才重置的实例密码
  5. 登陆成功, 更新安装源 sudo apt-get update && sudo apt-get upgrade -y
  6. 安装 npm sudo apt-get install npm
  7. 安装 npm 管理包 sudo npm install -g n
  8. 安装 node 最新稳定版 sudo n stable

创建一个静态服务器

mkdir node-server // 创建 node-server 文件夹
cd node-server // 进入 node-server 文件夹
npm init -y // 初始化项目
npm i express
touch server.js // 创建 server.js 文件
vim server.js // 编辑 server.js 文件

将以下代码输入进去(用 vim 进入文件后按 i 进行编辑,保存时按 esc 然后输入 :wq,再按 enter),更多使用方法请自行搜索。

const express = require('express')
const app = express()
const port = 3388 // 填入自己的阿里云映射端口,在网络安全组配置。

app.use(express.static('dist'))

app.listen(port, '0.0.0.0', () => {
    console.log(`listening`)
})

执行 node server.js 开始监听,由于暂时没有 dist 目录,先不要着急。

注意,监听 IP 必须为 0.0.0.0 ,详情请看部署Node.js项目注意事项

阿里云入端口要在网络安全组中查看与配置。

在这里插入图片描述

创建阿里云密钥对

请参考创建SSH密钥对绑定SSH密钥对 ,将你的 ECS 服务器实例和密钥绑定,然后将私钥保存到你的电脑(例如保存在 ecs.pem 文件)。

打开你要部署到阿里云的 Github 项目,点击 setting->secrets。

在这里插入图片描述
点击 new secret
在这里插入图片描述
secret 名称为 SERVER_SSH_KEY,并将刚才的阿里云密钥填入内容。

在这里插入图片描述
点击 add secret 完成。

在你项目下建立 .github\workflows\ci.yml 文件,填入以下内容:

name: Build app and deploy to aliyun
on:
  #监听push操作
  push:
    branches:
      # master分支,你也可以改成其他分支
      - master
jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Install Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.16.2'
    - name: Install npm dependencies
      run: npm install
    - name: Run build task
      run: npm run build
    - name: Deploy to Server
      uses: easingthemes/ssh-deploy@v2.1.5
      env:
          SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
          ARGS: '-rltgoDzvO --delete'
          SOURCE: dist # 这是要复制到阿里云静态服务器的文件夹名称
          REMOTE_HOST: '118.190.217.8' # 你的阿里云公网地址
          REMOTE_USER: root # 阿里云登录后默认为 root 用户,并且所在文件夹为 root
          TARGET: /root/node-server # 打包后的 dist 文件夹将放在 /root/node-server

保存,推送到 Github 上。

以后只要你的项目执行 git push 操作,就会自动执行 ci.yml 定义的脚本,将打包文件放到你的阿里云静态服务器上。

这个 Actions 主要做了两件事:

  1. 克隆你的项目,下载依赖,打包。
  2. 用你的阿里云私钥以 SSH 的方式登录到阿里云,把打包的文件上传(使用 rsync)到阿里云指定的文件夹中。

如果还是不懂,建议看一下我的 demo

ci.yml 配置文件讲解

  1. name,表示这个工作流程(workflow)的名称。
  2. on,表示监听的意思,后面可以加上各种事件,例如 push 事件。

下面这段代码表示要监听 master 分支的 push 事件。当 Github Actions 监听到 push 事件发生时,它就会执行下面 jobs 定义的一系列操作。

name: Build app and deploy to aliyun
on:
  #监听push操作
  push:
    branches:
      # master分支,你也可以改成其他分支
      - master
jobs:
...
  1. jobs,看字面意思就是一系列的作业,你可以在 jobs 字段下面定义很多作业,例如 job1job2 等等,并且它们是并行执行的。
jobs:
  job1:
      ...
  job2:
      ...
  job3:
    ...

回头看一下 ci.yml 文件,它只有一个作业,即 build,作业的名称是自己定义的,你叫 good 也可以。

  1. runs-on,表示你这个工作流程要运行在什么操作系统上,ci.yml 文件定义的是最新稳定版的 ubuntu。除了 ubuntu,它还可以选择 Mac 或 Windows。

  1. steps,看字面意思就是一系列的步骤,也就是说这个作业由一系列的步骤完成。例如先执行 step1,再执行 step2...

setps 步骤讲解

setps 其实是一个数组,在 YAML 语法中,以 - 开始就是一个数组项。例如 ['a', 'b', 'c'] 用 YAML 语法表示为:

- a
- b
- c

所以 setps 就是一个步骤数组,从上到下开始执行。从 ci.yml 文件来看,每一个小步骤都有几个相关选项:

  1. name,小步骤的名称。
  2. uses,小步骤使用的 actions 库名称或路径,Github Actions 允许你使用别人写好的 Actions 库。
  3. run,小步骤要执行的 shell 命令。
  4. env,设置与小步骤相关的环境变量。
  5. with,提供参数。

综上所述,ci.yml 文件中的 setps 就很好理解了,下面从头到尾解释一边:

    steps:
    - uses: actions/checkout@v1
    - name: Install Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.16.2'
    - name: Install npm dependencies
      run: npm install
    - name: Run build task
      run: npm run build
    - name: Deploy to Server
      uses: easingthemes/ssh-deploy@v2.1.5
      env:
          SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
          ARGS: '-rltgoDzvO --delete'
          SOURCE: dist # 这是要复制到阿里云静态服务器的文件夹名称
          REMOTE_HOST: '118.190.217.8' # 你的阿里云公网地址
          REMOTE_USER: root # 阿里云登录后默认为 root 用户,并且所在文件夹为 root
          TARGET: /root/node-server # 打包后的 dist 文件夹将放在 /root/node-server
  1. 使用 actions/checkout@v1 库克隆代码到 ubuntu 上。
  2. 使用 actions/setup-node@v1 库安装 nodejs,with 提供了一个参数 node-version 表示要安装的 nodejs 版本。
  3. ubuntushell 上执行 npm install 下载依赖。
  4. 执行 npm run build 打包项目。
  5. 使用 easingthemes/ssh-deploy@v2.1.5 库,这个库的作用就是用 SSH 的方式远程登录到阿里云服务器,将打包好的文件夹复制到阿里云指定的目录上。

env 上可以看到,这个 actions 库要求我们提供几个环境变量:

  1. SSH_PRIVATE_KEY: 阿里云密钥对中的私钥(需要你提前写在 github secrets 上),
  2. ARGS: '-rltgoDzvO --delete',没仔细研究,我猜是复制完文件就删除掉。
  3. SOURCE:打包后的文件夹名称
  4. REMOTE_HOST: 阿里云公网 IP 地址
  5. REMOTE_USER: 阿里云服务器的用户名
  6. TARGET: 你要拷贝到阿里云服务器指定目录的名称

如果你想了解一下其他 actions 库的实现,可以直接复制 actions 库的名称去搜索引擎搜索一下,例如搜索 actions/checkout 的结果为:

都看到这了,给个赞再走吧。

参考资料

更多文章,敬请关注

查看原文

OLong 赞了文章 · 2020-10-27

前端项目自动化部署——超详细教程(Jenkins、Github Actions)

本教程主要讲解了怎么使用 Jenkins 和 Github Actions 部署前端项目。

  1. 第一部分是使用 Gitea 配置局域网 git 服务器,再使用 Jenkins 将 Gitea 下的项目部署到局域网服务器。
  2. 第二部分是使用 Github Actions 将 Github 项目部署到 Github Page 和阿里云。

阅读本教程并不需要你提前了解 Jenkins 和 Github Actions 的知识,只要按照本教程的指引,就能够实现自动化部署项目。

PS:本人所用电脑操作系统为 windows,即以下所有的操作均在 windows 下运行。其他操作系统的配置大同小异,不会有太大差别。

Gitea + Jenkins 自动构建前端项目并部署到服务器

Gitea 用于构建 Git 局域网服务器,Jenkins 是 CI/CD 工具,用于部署前端项目。

配置 Gitea

  1. 下载 Gitea,选择一个喜欢的版本,例如 1.13,选择 gitea-1.13-windows-4.0-amd64.exe 下载。
  2. 下载完后,新建一个目录(例如 gitea),将下载的 Gitea 软件放到该目录下,双击运行。
  3. 打开 localhost:3000 就能看到 Gitea 已经运行在你的电脑上了。
  4. 点击注册,第一次会弹出一个初始配置页面,数据库选择 SQLite3。另外把 localhost 改成你电脑的局域网地址,例如我的电脑 IP 为 192.168.0.118

在这里插入图片描述
在这里插入图片描述

  1. 填完信息后,点击立即安装,等待一会,即可完成配置。
  2. 继续点击注册用户,第一个注册的用户将会成会管理员。
  3. 打开 Gitea 的安装目录,找到 custom\conf\app.ini,在里面加上一行代码 START_SSH_SERVER = true。这时就可以使用 ssh 进行 push 操作了。

在这里插入图片描述

  1. 如果使用 http 的方式无法克隆项目,请取消 git 代理。
git config --global --unset http.proxy
git config --global --unset https.proxy

配置 Jenkins

  1. 需要提前安装 JDK,JDK 安装教程网上很多,请自行搜索。
  2. 打开 Jenkins 下载页面。

在这里插入图片描述

  1. 安装过程中遇到 Logon Type 时,选择第一个。

在这里插入图片描述

  1. 端口默认为 8080,这里我填的是 8000。安装完会自动打开 http://localhost:8000 网站,这时需要等待一会,进行初始化。
  2. 按照提示找到对应的文件(直接复制路径在我的电脑中打开),其中有管理员密码。

在这里插入图片描述

  1. 安装插件,选择第一个。

在这里插入图片描述

  1. 创建管理员用户,点击完成并保存,然后一路下一步。

在这里插入图片描述

  1. 配置完成后自动进入首页,这时点击 Manage Jenkins -> Manage plugins 安装插件。

在这里插入图片描述

  1. 点击 可选插件,输入 nodejs,搜索插件,然后安装。
  2. 安装完成后回到首页,点击 Manage Jenkins -> Global Tool Configuration 配置 nodejs。如果你的电脑是 win7 的话,nodejs 版本最好不要太高,选择 v12 左右的就行。

在这里插入图片描述

创建静态服务器

  1. 建立一个空目录,在里面执行 npm init -y,初始化项目。
  2. 执行 npm i express 下载 express。
  3. 然后建立一个 server.js 文件,代码如下:
const express = require('express')
const app = express()
const port = 8080

app.use(express.static('dist'))

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

它将当前目录下的 dist 文件夹设为静态服务器资源目录,然后执行 node server.js 启动服务器。

由于现在没有 dist 文件夹,所以访问网站是空页面。
在这里插入图片描述
不过不要着急,一会就能看到内容了。

自动构建 + 部署到服务器

  1. 下载 Jenkins 提供的 demo 项目 building-a-multibranch-pipeline-project,然后在你的 Gitea 新建一个仓库,把内容克隆进去,并提交到 Gitea 服务器。

在这里插入图片描述

  1. 打开 Jenkins 首页,点击 新建 Item 创建项目。

在这里插入图片描述

  1. 选择源码管理,输入你的 Gitea 上的仓库地址。

在这里插入图片描述

  1. 你也可以尝试一下定时构建,下面这个代码表示每 5 分钟构建一次。

在这里插入图片描述

  1. 选择你的构建环境,这里选择刚才配置的 nodejs。

在这里插入图片描述

  1. 点击增加构建步骤,windows 要选 execute windows batch command,linux 要选 execute shell

  1. 输入 npm i && npm run build && xcopy .\build\* G:\node-server\dist\ /s/e/y,这行命令的作用是安装依赖,构建项目,并将构建后的静态资源复制到指定目录 G:\node-server\dist\ 。这个目录是静态服务器资源目录。

在这里插入图片描述

  1. 保存后,返回首页。点击项目旁边的小三角,选择 build now

在这里插入图片描述

  1. 开始构建项目,我们可以点击项目查看构建过程。

在这里插入图片描述

  1. 构建成功,打开 http://localhost:8080/ 看一下结果。

在这里插入图片描述
在这里插入图片描述

  1. 由于刚才设置了每 5 分钟构建一次,我们可以改变一下网站的内容,然后什么都不做,等待一会再打开网站看看。

在这里插入图片描述

  1. 把修改的内容提交到 Gitea 服务器,稍等一会。打开网站,发现内容已经发生了变化。

在这里插入图片描述

使用 pipeline 构建项目

使用流水线构建项目可以结合 Gitea 的 webhook 钩子,以便在执行 git push 的时候,自动构建项目。

  1. 点击首页右上角的用户名,选择设置

在这里插入图片描述

  1. 添加 token,记得将 token 保存起来。

在这里插入图片描述

  1. 打开 Jenkins 首页,点击 新建 Item 创建项目。

在这里插入图片描述

  1. 点击构建触发器,选择触发远程构建,填入刚才创建的 token。

在这里插入图片描述

  1. 选择流水线,按照提示输入内容,然后点击保存

在这里插入图片描述

  1. 打开 Jenkins 安装目录下的 jenkins.xml 文件,找到 <arguments> 标签,在里面加上 -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true。它的作用是关闭 CSRF 验证,不关的话,Gitea 的 webhook 会一直报 403 错误,无法使用。加好参数后,在该目录命令行下输入 jenkins.exe restart 重启 Jenkins。

在这里插入图片描述

  1. 回到首页,配置全局安全选项。勾上匿名用户具有可读权限,再保存。

在这里插入图片描述
在这里插入图片描述

  1. 打开你的 Gitea 仓库页面,选择仓库设置

在这里插入图片描述

  1. 点击管理 web 钩子,添加 web 钩子,钩子选项选择 Gitea
  2. 目标 URL 按照 Jenkins 的提示输入内容。然后点击添加 web 钩子

在这里插入图片描述
在这里插入图片描述

  1. 点击创建好的 web 钩子,拉到下方,点击测试推送。不出意外,应该能看到推送成功的消息,此时回到 Jenkins 首页,发现已经在构建项目了。

在这里插入图片描述

  1. 由于没有配置 Jenkinsfile 文件,此时构建是不会成功的。所以接下来需要配置一下 Jenkinsfile 文件。将以下代码复制到你 Gitea 项目下的 Jenkinsfile 文件。jenkins 在构建时会自动读取文件的内容执行构建及部署操作。
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {  // window 使用 bat, linux 使用 sh
                bat 'npm i'
                bat 'npm run build'
            }
        }
        stage('Deploy') {
            steps {
                bat 'xcopy .\\build\\* D:\\node-server\\dist\\ /s/e/y' // 这里需要改成你的静态服务器资源目录
            }
        }
    }
}
  1. 每当你的 Gitea 项目执行 push 操作时,Gitea 都会通过 webhook 发送一个 post 请求给 Jenkins,让它执行构建及部署操作。

在这里插入图片描述

小结

如果你的操作系统是 Linux,可以在 Jenkins 打包完成后,使用 ssh 远程登录到阿里云,将打包后的文件复制到阿里云上的静态服务器上,这样就能实现阿里云自动部署了。具体怎么远程登录到阿里云,请看下文中的 《Github Actions 部署到阿里云》 一节。

Github Actions 自动构建前端项目并部署到服务器

如果你的项目是 Github 项目,那么使用 Github Actions 也许是更好的选择。

部署到 Github Page

接下来看一下如何使用 Github Actions 部署到 Github Page。

在你需要部署到 Github Page 的项目下,建立一个 yml 文件,放在 .github/workflow 目录下。你可以命名为 ci.yml,它类似于 Jenkins 的 Jenkinsfile 文件,里面包含的是要自动执行的脚本代码。

这个 yml 文件的内容如下:

name: Build and Deploy
on: # 监听 master 分支上的 push 事件
  push:
    branches:
      - master
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest # 构建环境使用 ubuntu
    steps:
      - name: Checkout
        uses: actions/checkout@v2.3.1  
        with:
          persist-credentials: false

      - name: Install and Build # 下载依赖 打包项目
        run: |
          npm install
          npm run build

      - name: Deploy # 将打包内容发布到 github page
        uses: JamesIves/github-pages-deploy-action@3.5.9 # 使用别人写好的 actions
        with:  # 自定义环境变量
          ACCESS_TOKEN: ${{ secrets.VUE_ADMIN_TEMPLATE }} # VUE_ADMIN_TEMPLATE 是我的 secret 名称,需要替换成你的
          BRANCH: master
          FOLDER: dist
          REPOSITORY_NAME: woai3c/woai3c.github.io # 这是我的 github page 仓库
          TARGET_FOLDER: github-actions-demo # 打包的文件将放到静态服务器 github-actions-demo 目录下

上面有一个 ACCESS_TOKEN 变量需要自己配置。

  1. 打开 Github 网站,点击你右上角的头像,选择 settings

在这里插入图片描述

  1. 点击左下角的 developer settings

在这里插入图片描述

  1. 在左侧边栏中,单击 Personal access tokens(个人访问令牌)

在这里插入图片描述

  1. 单击 Generate new token(生成新令牌)

在这里插入图片描述

  1. 输入名称并勾选 repo

在这里插入图片描述

  1. 拉到最下面,点击 Generate token,并将生成的 token 保存起来。

在这里插入图片描述

  1. 打开你的 Github 项目,点击 settings

在这里插入图片描述
点击 secrets->new secret
在这里插入图片描述
创建一个密钥,名称随便填(中间用下划线隔开),内容填入刚才创建的 token。
在这里插入图片描述

在这里插入图片描述
将上文代码中的 ACCESS_TOKEN: ${{ secrets.VUE_ADMIN_TEMPLATE }} 替换成刚才创建的 secret 名字,替换后代码如下 ACCESS_TOKEN: ${{ secrets.TEST_A_B }}。保存后,提交到 Github。

以后你的项目只要执行 git push,Github Actions 就会自动构建项目并发布到你的 Github Page 上。

Github Actions 的执行详情点击仓库中的 Actions 选项查看。

在这里插入图片描述
在这里插入图片描述
具体详情可以参考一下我的 demo 项目 github-actions-demo

构建成功后,打开 Github Page 网站,可以发现内容已经发布成功。

在这里插入图片描述

Github Actions 部署到阿里云

初始化阿里云服务器

  1. 购买阿里云服务器,选择操作系统,我选的 ubuntu
  2. 在云服务器管理控制台选择实例->更多->密钥->重置实例密码(一会登陆用)
  3. 选择远程连接->VNC,会弹出一个密码,记住它,以后远程连接要用(ctrl + alt + f1~f6 切换终端,例如 ctrl + alt + f1 是第一个终端)
  4. 进入后是一个命令行 输入 root(默认用户名),密码为你刚才重置的实例密码
  5. 登陆成功, 更新安装源 sudo apt-get update && sudo apt-get upgrade -y
  6. 安装 npm sudo apt-get install npm
  7. 安装 npm 管理包 sudo npm install -g n
  8. 安装 node 最新稳定版 sudo n stable

创建一个静态服务器

mkdir node-server // 创建 node-server 文件夹
cd node-server // 进入 node-server 文件夹
npm init -y // 初始化项目
npm i express
touch server.js // 创建 server.js 文件
vim server.js // 编辑 server.js 文件

将以下代码输入进去(用 vim 进入文件后按 i 进行编辑,保存时按 esc 然后输入 :wq,再按 enter),更多使用方法请自行搜索。

const express = require('express')
const app = express()
const port = 3388 // 填入自己的阿里云映射端口,在网络安全组配置。

app.use(express.static('dist'))

app.listen(port, '0.0.0.0', () => {
    console.log(`listening`)
})

执行 node server.js 开始监听,由于暂时没有 dist 目录,先不要着急。

注意,监听 IP 必须为 0.0.0.0 ,详情请看部署Node.js项目注意事项

阿里云入端口要在网络安全组中查看与配置。

在这里插入图片描述

创建阿里云密钥对

请参考创建SSH密钥对绑定SSH密钥对 ,将你的 ECS 服务器实例和密钥绑定,然后将私钥保存到你的电脑(例如保存在 ecs.pem 文件)。

打开你要部署到阿里云的 Github 项目,点击 setting->secrets。

在这里插入图片描述
点击 new secret
在这里插入图片描述
secret 名称为 SERVER_SSH_KEY,并将刚才的阿里云密钥填入内容。

在这里插入图片描述
点击 add secret 完成。

在你项目下建立 .github\workflows\ci.yml 文件,填入以下内容:

name: Build app and deploy to aliyun
on:
  #监听push操作
  push:
    branches:
      # master分支,你也可以改成其他分支
      - master
jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Install Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.16.2'
    - name: Install npm dependencies
      run: npm install
    - name: Run build task
      run: npm run build
    - name: Deploy to Server
      uses: easingthemes/ssh-deploy@v2.1.5
      env:
          SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
          ARGS: '-rltgoDzvO --delete'
          SOURCE: dist # 这是要复制到阿里云静态服务器的文件夹名称
          REMOTE_HOST: '118.190.217.8' # 你的阿里云公网地址
          REMOTE_USER: root # 阿里云登录后默认为 root 用户,并且所在文件夹为 root
          TARGET: /root/node-server # 打包后的 dist 文件夹将放在 /root/node-server

保存,推送到 Github 上。

以后只要你的项目执行 git push 操作,就会自动执行 ci.yml 定义的脚本,将打包文件放到你的阿里云静态服务器上。

这个 Actions 主要做了两件事:

  1. 克隆你的项目,下载依赖,打包。
  2. 用你的阿里云私钥以 SSH 的方式登录到阿里云,把打包的文件上传(使用 rsync)到阿里云指定的文件夹中。

如果还是不懂,建议看一下我的 demo

ci.yml 配置文件讲解

  1. name,表示这个工作流程(workflow)的名称。
  2. on,表示监听的意思,后面可以加上各种事件,例如 push 事件。

下面这段代码表示要监听 master 分支的 push 事件。当 Github Actions 监听到 push 事件发生时,它就会执行下面 jobs 定义的一系列操作。

name: Build app and deploy to aliyun
on:
  #监听push操作
  push:
    branches:
      # master分支,你也可以改成其他分支
      - master
jobs:
...
  1. jobs,看字面意思就是一系列的作业,你可以在 jobs 字段下面定义很多作业,例如 job1job2 等等,并且它们是并行执行的。
jobs:
  job1:
      ...
  job2:
      ...
  job3:
    ...

回头看一下 ci.yml 文件,它只有一个作业,即 build,作业的名称是自己定义的,你叫 good 也可以。

  1. runs-on,表示你这个工作流程要运行在什么操作系统上,ci.yml 文件定义的是最新稳定版的 ubuntu。除了 ubuntu,它还可以选择 Mac 或 Windows。

  1. steps,看字面意思就是一系列的步骤,也就是说这个作业由一系列的步骤完成。例如先执行 step1,再执行 step2...

setps 步骤讲解

setps 其实是一个数组,在 YAML 语法中,以 - 开始就是一个数组项。例如 ['a', 'b', 'c'] 用 YAML 语法表示为:

- a
- b
- c

所以 setps 就是一个步骤数组,从上到下开始执行。从 ci.yml 文件来看,每一个小步骤都有几个相关选项:

  1. name,小步骤的名称。
  2. uses,小步骤使用的 actions 库名称或路径,Github Actions 允许你使用别人写好的 Actions 库。
  3. run,小步骤要执行的 shell 命令。
  4. env,设置与小步骤相关的环境变量。
  5. with,提供参数。

综上所述,ci.yml 文件中的 setps 就很好理解了,下面从头到尾解释一边:

    steps:
    - uses: actions/checkout@v1
    - name: Install Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.16.2'
    - name: Install npm dependencies
      run: npm install
    - name: Run build task
      run: npm run build
    - name: Deploy to Server
      uses: easingthemes/ssh-deploy@v2.1.5
      env:
          SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
          ARGS: '-rltgoDzvO --delete'
          SOURCE: dist # 这是要复制到阿里云静态服务器的文件夹名称
          REMOTE_HOST: '118.190.217.8' # 你的阿里云公网地址
          REMOTE_USER: root # 阿里云登录后默认为 root 用户,并且所在文件夹为 root
          TARGET: /root/node-server # 打包后的 dist 文件夹将放在 /root/node-server
  1. 使用 actions/checkout@v1 库克隆代码到 ubuntu 上。
  2. 使用 actions/setup-node@v1 库安装 nodejs,with 提供了一个参数 node-version 表示要安装的 nodejs 版本。
  3. ubuntushell 上执行 npm install 下载依赖。
  4. 执行 npm run build 打包项目。
  5. 使用 easingthemes/ssh-deploy@v2.1.5 库,这个库的作用就是用 SSH 的方式远程登录到阿里云服务器,将打包好的文件夹复制到阿里云指定的目录上。

env 上可以看到,这个 actions 库要求我们提供几个环境变量:

  1. SSH_PRIVATE_KEY: 阿里云密钥对中的私钥(需要你提前写在 github secrets 上),
  2. ARGS: '-rltgoDzvO --delete',没仔细研究,我猜是复制完文件就删除掉。
  3. SOURCE:打包后的文件夹名称
  4. REMOTE_HOST: 阿里云公网 IP 地址
  5. REMOTE_USER: 阿里云服务器的用户名
  6. TARGET: 你要拷贝到阿里云服务器指定目录的名称

如果你想了解一下其他 actions 库的实现,可以直接复制 actions 库的名称去搜索引擎搜索一下,例如搜索 actions/checkout 的结果为:

都看到这了,给个赞再走吧。

参考资料

更多文章,敬请关注

查看原文

赞 98 收藏 80 评论 6

OLong 发布了文章 · 2020-10-26

活用async/await,实现一些让Vue更好用的装饰器

Async/await加上装饰器,会产生神奇的效果。

以下所列几个装饰器,都要求被装饰的方法写成async/await,

这样就可以利用async/await本身的特性,从方法外部得知异步方法是否运行完成。

于是便实现了将繁杂和麻烦的逻辑隐藏在装饰器内部,使业务代码更加干净。

以下装饰器除了最后一个都是用在Typescript环境下的class写法的vue里的。

最后一个其实并不是装饰器,而是一个高阶函数,但是众所周知,装饰器本质上就是个高阶函数。

所以所有装饰器都可以很容易的改成高阶函数,然后用在js环境的vue里。

给vue添加一个指示初始化完成的变量。

  1. 使用场景举例:

    搜索页面:搜索中显示loading,结果为空时显示暂无数据。

    第一次打开页面时,在created或者mounted中发出请求,进行初始化的搜索,此时搜索还没完成,显示暂无数据并不合适。
    这个时候就需要一个变量来判断页面是不是第一次打开。

  2. 代码解释:

    通过装饰器添加这个属性(pageIsReady)到组件的类上,

    并包装vue的created, mounted和beforeDestroy方法,监控组件的生命周期。
    当created或者mounted里发出的请求完成后,就把pageIsReady设为true。
    然后在beforeDestroy中重置状态,因为装饰器用了闭包,只会实例化一次。

import { Constructor } from "vue/types/options";
export type WrapReadyProperty<T> = T & {
    pageIsReady?: boolean;
    createdDone?: boolean;
    mountedDone?: boolean
}
/**  
 * 在@compontent 之后使用这个装饰器,
 * 组件就会被注入属性 pageIsReady,
 * 当created和mounted都执行完成时 pageIsReady 变成true,
 * 要求mounted或created是async/await。(取决于在哪个方法中发请求初始化组件)
 * 然后可以在template中直接使用。
 * 在script中使用调用isPageReady.call(this)方法;
    */
export default function PageReadyStatus() {
    return function pageReadyEnhancement<T extends WrapReadyProperty<Constructor>>(target: T) {
        const oldMounted = target.prototype.mounted || function() { }
        const oldCreated = target.prototype.created || function() { }
        const oldBeforeDestroy = target.prototype.beforeDestroy || function() { }
        target.prototype.pageIsReady = false;
        function isCreatedMountedAllDone(this: T) {
            return !!this.createdDone && !!this.mountedDone;
        }
        target.prototype.created = async function(...params: any[]) {
            await oldCreated.apply(this, params);
            this.createdDone = true;
            this.pageIsReady = isCreatedMountedAllDone.call(this)
        }
        target.prototype.mounted = async function(...params: any[]) {
            await oldMounted.apply(this, params);
            this.mountedDone = true
            this.pageIsReady = isCreatedMountedAllDone.call(this)
        }
        target.prototype.beforeDestroy = async function(...params: any[]) {
            await oldBeforeDestroy.apply(this, params);
            this.createdDone = false;
            this.mountedDone = true
            this.pageIsReady = false;
        }
        return target
    };
}

export function isPageReady(this: WrapReadyProperty<Vue>) {
    return this.pageIsReady
}

给事件回调函数和按钮Dom添加防抖与loading样式

  1. 使用场景举例:

    点击一个按钮,触发一个函数,并发出一个请求。此时需要给这个函数防抖,并给按钮增加一个loading的样式

  2. 代码解释

    利用async/await把异步变成同步的特性,在装饰器中发现方法还没执行完成时直接返回。

    并从时间对象中拿到按钮的dom节点,改变按钮的样式。我这里是用了一个cursor:wait;

/*
 * 请保证被包装的方法的参数列表最后一个是点击事件的参数
 */
export default function buttonThrottle() {
    let pending = false;
    return function(target: any, name: string): any {
        const btnClickFunc = target[name];
        const newFunc = async function(this: Vue, ...params: any[]) {
            if (pending) {
                return;
            }
            const event:Event = params[params.length - 1];
            let btn = event.target as HTMLElement
            pending = true;
            const recoverCursor = changeCursor(btn);
            try {
                await btnClickFunc.apply(this, params);
            } catch (error) {
                console.error(error);
            }
            recoverCursor();
            pending = false;
        };
        target[name] = newFunc;
        return target;
    };
}
function changeCursor(btn?: HTMLElement) {
    if (btn == null) {
        return () => {};
    }
    const oldCursor = btn.style.cursor;
    btn.style.cursor = "wait";
    return () => {
        btn.style.cursor = oldCursor;
    };
}
  1. 用法:
    在点击事件函数上使用这个装饰器.
    import { Component, Vue } from "vue-property-decorator";
    import buttonThrottle from "@/ui/view/utils/buttonThrottle";


    type Member = { account_no: string; name: string; warn?: string };
    @Component({ components: {} })
    export default class AddMemberInput extends Vue {
    @buttonThrottle()
    private async confirmAdd() {
        await this.addMembers(this.getVaildMembers());
        }    
    }

注入loading变量

  1. 场景

    发请求时在页面上加一个loading的状态,比如element-ui里就有一个v-loading的指令。

    这个指令需要一个是否在loading中的变量

  2. 代码解释

    往组件上增加一个变量,变量名由参数variableName指定

    该变量会在被包装的方法执行期间为true

    这样就不用自己写this.loading=true this.loading=false了

 export default function FunctionLoadingVariable(variableName: string) {
       return function(target: any, name: string): any {
           target[variableName] = false;
           const btnClickFunc = target[name];
           const newFunc = async function(this: Vue & {
               [key: string]: boolean
           }, ...params: any[]) {
               try {
                   this[variableName] = true
                   await btnClickFunc.apply(this, params);
               } catch (error) {
                   console.error(error);
               }
               this[variableName] = false
           };
           target[name] = newFunc;
           return target;
       };
   }
  

mounted之前显示白屏

  1. 场景

    页面加载的过程很丑,所以可以在mouted之前显示白屏,或者弄一个骨架屏。

    特别是在微信小程序中,因为加载完成之前特别丑,所以几乎所有小程序都会在mounted之前白屏。

  2. 通过async/await获得mounted或者created是否执行完成
    再通过指向vue实力的this拿到组件根节点,然后按需修改它
    以下代码只是将组件隐藏了,实际上可以写更复杂的逻辑,在加载过程中显示其他内容,毕竟拿到了Dom,想干嘛就干嘛。
  function firstPaintControl(vueObj) {
    let oldMounted = vueObj.mounted || function() {};
    vueObj.mounted = async function(...params) {
      this.$el.style.visibility = 'hidden';
      await oldMounted.apply(this, params);
      this.$el.style.visibility = 'visible';
    };
    return vueObj;
  }
查看原文

赞 17 收藏 13 评论 4

认证与成就

  • 获得 93 次点赞
  • 获得 9 枚徽章 获得 0 枚金徽章, 获得 2 枚银徽章, 获得 7 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-07-30
个人主页被 1.8k 人浏览