寒水寺一禅

寒水寺一禅 查看完整档案

西安编辑  |  填写毕业院校暂无  |  前端工程师 编辑 libbgit.github.io/person 编辑
编辑

若确切地知道现在,就能预见未来

个人动态

寒水寺一禅 收藏了文章 · 10月26日

浅谈怎样系统的准备前端面试

image.png

前言

创业梦碎,回归现实,7 月底毅然裸辞,苦战两个月,拿到了美团和字节跳动的 offer,这算是从业以来第一次真正意义的面试,遇到蛮多问题,比如一开始具体的面试过程我都不懂,基本一直是摸着石头过河,所以结合我的经历和前人经验,总结一下我认为还比较系统科学的面试大纲分享给大家,希望大家在系统的准备之后,都能找到自己满意的工作。

一、知识准备

1. 知识体系

知识体系是重中之重,优秀的开发者很多都有维护自身知识体系的习惯,建立知识体系能帮助认知知识全貌及迅速找到知识的关联,就像对碎片化的知识做了索引,无论工作还是面试中碰到的问题,能很快对号入座,举一反三,哪怕是不熟悉的知识点,也可以使用其他同体系的知识进行关联解释,知识体系可以帮助你尽快了解自己,帮助你查漏补缺,让你能够把宝贵的时间聚焦于自己的薄弱项。

如果还没有自己的知识体系,那就赶快行动起来吧,这里列出一些参考资料帮助你快速行动:

2. 时间分配

梳理好知识体系之后,接下来就是制定一个合理的学习计划了,这一步需要你根据自己的个人时间进行安排(我就是时间安排不了一狠心就裸辞了,后面压力巨大),按照知识体系中标记的优先级进行系统的学习,总的时间根据自身情况,建议 1 ~ 3 个月即可,太长时间可能容易遗忘前面学习的知识。

针对不同模块,时间安排也有所不同,我列举一下我自己的安排以供参考:

  • 基础知识 40%
  • 项目与业务 20%
  • 算法与数据结构 20%
  • 设计思想与工程化 10%
  • 框架与原理 10%

3. 整理算法

这里把算法单独拿出来,是因为近年来在大厂的面试中对数据结构和算法的考察越来越重视,不管是前端还是后端,首先我们是工程师,我们日常工作就是写程序的,程序 = 数据结构 + 算法,所以算法和数据结构的学习是很有必要的,虽然对于前端岗位的算法要求可能不会那么高,但是基本的递归、遍历、链表的操作、栈与队列的常见算法还是要会的。每天学习两三题,两个月后,你不会后悔的。

推荐一些社区内很不错的算法学习资料和经验:

喜欢付费课程的话,比较不错的有:

  • 慕课网 bobo 老师的《算法与数据结构体系课》
  • 极客时间 覃超 老师的《算法面试通关40讲》

4. 整理面试题

这一步不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。可以搜集整理近两年来一线公司的面试题,做成笔记,你会发现面试题实际问的大同小异,只是考察的内容和形式有不同的目的性。提前熟悉,上场的时候才不会慌张。

推荐资料:

5. 常见功能的手写实现

这块几乎是必考的,比如:深拷贝、事件总线、es5 继承,以及最近很火的手写 Promise 实现,这些手写功能不仅考察了面试者的编码能力也考察了对原理和规范的掌握程度。

虽然实际面试过程,面试官可能不会问的特别细节,比如让你实现一个完整的 Promise,但是我们自己学习这些手写功能的时候,不能浅尝辄止,需要考虑使用场景、错误处理、规范等细节的问题,千万不要背代码,不然手写代码一时爽,深挖细节火葬场。

笔者自己粗略的总结了一些前端面试常见的手写功能,供大家参考;

6. 项目实战

这部分是社招必考点,对自己负责或参与的项目,一定要深挖,要提炼出「难点」「痛点」「亮点」以及「解决方案」,更要体现出自己的「思考」和做出的「努力」,对应于 「问题 - 思考 - 解决 - 成果」这样的一个过程,是大厂很看重的能力,希望大家对于自己的参与的项目都能参考这个流程进行思考总结。

如果没有很丰富的项目经验,也可以多研究社区内技术大佬们的「项目经验」来获得,但一定要研究透彻,看过不等于会,不然面试问到只会坑了自己。

7. 执行学习计划

按照梳理的「知识体系」、「整理算法」、以及「整理面试题」,结合「时间分配」、给自己制定一个合适的学习计划,然后坚定认真的去执行它。

二、简历准备

1. 参考目录

  • 【基本信息】不写无用的个人信息,比如:照片、籍贯、性别、地址、身高等;
  • 【技术技能】对「了解、熟练掌握、精通」这类词有概念,不要随便用精通;
  • 【项目经历】不写对求职无用项目经历、做的最好的项目 2 ~ 3 个即可,有数据支撑;
  • 【工作经历】简略概述名称、在职时间、职位以及主要负责业务,也可以和项目经历结合起来写;
  • 【教育背景】名称、时间等简要信息,普通院校建议放在底部即可,名校可以放在顶部;

    参考简历模板:链接: https://pan.baidu.com/s/1I-9U... 提取码: gkxw

2. 项目经历

简历中最难写的应该就是「项目经历」了,这块也是最重要的,是面试官考察你的依据,也是你用来引导面试官提问的工具,项目经历的总结,要有数据思维,不能泛泛而谈,一般按照 STAR 法则进行描述,按照:情境(situation)、目标(target)、行动(action)、结果(result)四项对工作做一个精简描述,例如:

  • 项目简介以及在 xx 项目中担任前端负责人
  • 负责了 xxx 工作,实现什么目标
  • 通过 xxx 方案解决了 xxx 问题;使 xxx 提升了 50%
  • 总结了 xxx 解决方案

3. 注意事项

  • 【突出亮点】如开源项目、大厂背景、社区影响力、知名项目、个人博客、技术亮点等;
  • 【对症下药】针对不同公司职位,可以针对性的调整简历内容,准备多份简历;
  • 【格式排版】PDF 格式,最好一页,最多不超过两页,像对待毕业论文一样去检查排版、错别字、标点符号、措辞;
  • 【文件命名】姓名_职位_手机号.pdf(学历有优势的可以加上最高学历院校);

4. 投递简历

  • 【筛选公司】相关因素:平台大小、发展前景、公司距离、个人喜好等;
  • 【了解公司】通过网络、社区、认识的内部员工去了解面试的具体流程、周期、注意事项等;
  • 【投递顺序】面试周期短的可以推迟,面试周期长的可以先面试,保证 offer 发放之间的时间跨度不会太长,便于集中对比选择;最想去的公司可以最后面试,这时已充分热身,甚至拿了 offer,心态方面也会更加从容;
  • 【内推优先】优先找人内推,社区内有很多小伙伴愿意帮忙的;

三、面试准备

1. 自我介绍

面试官对你的基本信息都已知晓,所以这一步最好结合应聘职位直奔亮点进行简要概述,做了哪些亮点项目遇到了什么难点如何解决的项目有什么收获给团队或公司带来了哪些成果,按照这个方式去吸引面试官,同时这也是我们掌握主动权的方法,面试官喜欢根据我们表述的内容进行展开,这样由一段精心设计的自我介绍开始,进而引导面试官和你交流,这会让面试官的工作开展的很舒服。

注意自我介绍不必涉及过多的技术细节阐述,一是这些技术细节可能面试官不一定涉猎,导致面试官只能从其他方面寻找切入点让你陷入被动,二是占用过多时间,所以简要概述要点即可,随后面试官会根据这些点和你展开沟通的,这时再详细阐述不迟。

2. 面试过程

大厂的面试多为四轮,整个过程因人因公司而异,下面介绍一些常见的面试过程与注意事项:

一面

一般是你应聘职位的平级的骨干同事,是入职后和你一起并肩作战的伙伴,这一面一般也是最难的,会从多个方面考察你能不能胜任这份工作,侧重于学习能力、沟通能力、基础知识掌握程度、总结与思考、编码能力等;

这一面要特别注意编程题,如果遇到原题,不要太激动,面试官会从其他方面再进一步考察你,所以多思考一点,这也是上文说的,一定不要背题,不然一问就露馅;

遇到不会的知识,也不要太紧张,先尝试暴力解,然后逐步优化,也可以请面试官给予提示,如果能在面试中解决一个不会的问题,那一定会让面试官给你加分的;

二面

一般是团队骨干或直属 leader,这一面是对一面的延伸,除了基础知识之外,面试官还会从技术选型、架构、解决方案等方面提问,考察你对技术细节、项目优化、整体方案等方面的思考;

三面

三面一般是所属团队的 leader,这一面的技术细节考察你的不会太多,更多的是你对工作中涉及到的业务、产品、技术的思考,职业的规划与个人发展,以及一些职场软技能,常见问题举例:

  • 项目中的角色、承担了哪些任务、遇到了哪些难点?怎么克服的?
  • 和其他技术选型或者产品项目的对比有什么优劣?
  • 团队怎么协作与分工的?
  • 给自己的技术能力做一个评价
  • 做了哪些提升团队的工作?
  • 公司产品这样的?是否有竞争力?怎么盈利的?
  • 你的个人职业规划?

四面

四面一般是 HR 面,这一面,尽力别说太多题外话,因为言多必失,保持积极乐观、礼貌友好的态度,当面试官问你为什么离职时,哪怕你上家公司老板和你打过架,也不要抱怨说出来。常见问题举例:

  • 为什么从上家公司离职?(注意积极向上)
  • 希望找一个怎样的工作,职业规划呢?(重发展,少谈钱)
  • 谈谈自己最大的优点?(不要编,结合实际说就好,大家都有的,比如:专注、团队精神、技术热情与钻研精神、沟通能力、深度思考等)
  • 谈谈自己最大的缺点?(和工作相关,又可以通过努力改变的点,比如:过于局限技术细节而忽视产品业务的重要性和理解,导致开发过程受阻,现在会积极参与产品业务的早起阶段,加强对业务的理解)
  • 方便透露手上都有哪些 offer 了吗?(按实际情况说即可,好的 offer 可以突出一下,不好的,可以不说)
  • 在 B 公司和我们之间,你怎么考虑的呢?(肯定选你啦)

3. 面试官:“你有什么想问我的吗?”

这个问题一般每一面都会遇到的,提问是面试中我们能够主动“索取”的环节,所以一定不要浪费这个机会,一些 leader 的回答还会带给你很多技术之外的思考与经验,让你受益良多,一定注意,不要问和待遇相关的问题,最后谈 offer 的时候再去问。

下面给出一些提问示例供参考:

  • 一面:面试官一般是你的平级同事,可以多去了解实际的工作内容,便于后续对比 offer,例如:团队业务、日常工作、技术栈、协作、技术分析等
  • 二面:面试官一般是团队骨干或直属 leader,可以多去了解业务和产品的规划、技术建设、对应聘职位的定位与期待等;
  • 三面:面试官一般是部门 leader,这一步可以多了解技术之外的知识,比如面试官自己的成长经验、技术之外的能力、职位发展路线等;
  • Hr 面:这一步可以多去了解公司本身相关的事,比如:你在公司工作的最大的感受是什么?晋升机制是怎样的?等等

4. 面试复盘

面试也是一个特别好的学习过程,能利用这个机会和其他团队的优秀的人沟通技术、交流心得、检验能力、了解优秀团队业务和产品,无论最后结果怎样,都值得好好总结下来。

  • 【记录】每轮面试结束后,尽量详细记录整个过程,最好录音,方便分析自己的表现
  • 【分析】按照自己的掌握程度对面试问题进行分类统计,分析沟通过程以及自己的表现
  • 【补强】一知半解的问题优先复习掌握,不会的问题要去大致了解一下,如果没有时间掌握,可以暂时忽略
  • 【总结】分析补强之后,可以总结成文,也可以分享给社区的小伙伴

五、Offer

当面试通过以后,你就要着手开始准备最后的 offer 沟通了,这一步,你要结合新公司的薪资构成,职位的薪资范围,自己估算涨幅后的年薪总包、社区了解的信息、公司发展前景、个人心里预期等去设定一个自己的薪资底线。

1. 年薪总包,是你在上家公司的税前年度总收入:『月薪 * 12 + 奖金 + 其他』,会要求银行流水进行证明,新公司会参考进行定薪,特殊情况可以主动说明,上一家公司的薪资知识参考,但也不是决定因素的。

2. 薪资谈判,这一步可以说是最考验沟通能力的环节了,这里提供一些信息:

个人实力 / 公司水平优秀公司普通公司
个人实力优秀保持底线、冲击高薪没有底线、必须高薪
个人实力普通降低底线、学习为重保持底线、冲击高薪
  • 薪资一般会在之前总包的基础上提高 30% ~ 50%;
  • 实力优秀且入职优秀公司,翻倍不是不可能;
  • 有些公司超过 50% 涨幅需要走特批,要求你承诺入职才会给你申请,这个说明一是公司对你认可,二是公司希望你尽快入职,所以如果公司不错,可以好好考虑一下;
  • HR 询问薪资预期时,可以基于心里底线和职位薪资范围向上多要一些,大大方方的沟通即可,没有知乎上说的那么多戏,与其说 HR 压价,倒不如说 HR 是防止候选人狮子大开口,只要薪资的提升在一个合理的范围,谈薪还是比较简单的。
  • HR 询问薪资时,一般还会问你都拿到了哪些 offer 了,如果你手上有比较不错的 offer 可以说一下,可以帮助 HR 更加确定你是一个优秀的候选人,薪资说不定还可以获得一个提升,但是一定不要为了提价胡编乱造 offer,诚信是本;

3. 何时入职,这一步,HR 都会问你何时能入职,这个结合你的当前工作和后续的面试计划,可以推迟入职日期,但是不宜太久,后续如果不能入职,一定要尽早通知 HR,要尊重别人的工作与付出,礼貌说明原因即可,别让人家等太久;

4. offer 对比,简单来说:有目标向前看,没目标向钱看,薪资很重要,但是技术人的职业发展更重要,而且大的平台在薪资上也不会让你吃亏;

六、注意事项

  • 不要裸辞,不要裸辞,不要裸辞;
  • 尽量 15 号之后办理离职,下个月的 15 号之前入职,这样能保证你的五险一金不断缴,平滑过度
  • 上家公司签的离职证明日期,不要和新公司的入职日期有重叠,所以拿到 offer 后,要留出时间先把当前工作的离职手续办完;
  • 注意社交礼仪,IT 行业虽然没那么多繁文缛节,但是基本的礼节不能丢,着装得体整洁、不要迟到、进门敲门、出门关门、等;
  • 有 offer,心不慌,可以先把还不错的 offer 留着,再去冲击大厂;
  • 面试是七分实力三分运气,不同的面试侧重点也会不同,所以不要因为某一两次面试受挫就丢失信心,及时总结;
  • 乐观积极、保持诚信、杜绝欺骗、避免负面情绪;
  • 不抱怨同事、不抱怨上家公司;

七、扯点别的

感谢一下 @ssh_晨曦时梦见兮 给我内推,给我看简历,给我建议,一句:“我觉得你的简历还不错”,给了我很大信心,和晨曦开玩笑说:“自从遇到你好像所有的面试都顺利多了,争取做你同事”,最后虽然不在一个部门,也算是得偿所愿成了同事,就等面基吃饭啦。

感谢一下 @狼叔 * 阿里巴巴,和狼叔都有着一段困难的创业公司经历,在我辞职之后一直走不出内心对未来迷茫以及对过去痛心的情况下,我主动联系了狼叔,对于我的现状和规划,狼叔谈了自己的看法,给了建议,鼓励我:“有目标向前看,没目标向钱看,现在都还不晚,加油吧”。

最后手握 offer 后,甚至有点做梦的感觉,一路走来,一直感觉迷茫与无助,直到最后严重怀疑自己,但离职的这段时间,有不少朋友经常鼓励我:“自信点,你还不错,加油!”,也一直帮我找内推,我觉得没有这些朋友,我心态可能没那么快恢复过来,真的非常感谢他们。

稳定之后,我现在除了做好工作以外,还想做的一件事就是也试着去帮助一些我能帮助的人,也希望有机会鼓励他们:“自信点,你很棒,加油!”

八、说在最后

文章主要对面试的核心流程与准备工作做了一个大纲性的概述,重点在于对面试的一个整体的审视以及各个环节的重点,所以肯定有很多细节没有顾及到,如有疑问或者建议也欢迎留言一起交流讨论,也欢迎联系我,找内推、聊简历、聊技术、侃大山。

邮箱:weboying@gmail.com
公众号:iboying

image.png

查看原文

寒水寺一禅 收藏了文章 · 10月18日

vue.js进入了vue3 RC阶段,正确姿势霸气迎接

👑 👑 👑 👑 👑 👑 👑 👑

稿定设计导出-20200720-120017.png

image.png

进入了rc版本阶段:

3.0.0-rc.2 (2020-07-20)
3.0.0-rc.1 (2020-07-17)

-- Alpha(α):预览版,或者叫内部测试版;一般不向外部发布,会有很多Bug;一般只有测试人员使用。
-- Beta(β):测试版,或者叫公开测试版;这个阶段的版本会一直加入新的功能;在 Alpha版之后推出。
-- RC(Release Candidate):最终测试版本;可能成为最终产品的候选版本,如果未出现问题则可发布成为正式版本。

多数开源软件会推出两个RC版本,最后的 RC2 则成为正式版本。

Here we go ~~

五步走天下去思考,步步渐进:

  • 我们怎么入手?
  • 有哪些新填API?和vue2不一样的地方?
  • 快在哪里,我们如何得知?
  • 大部分基于vue2的第三方组件库面临着升级?
  • 源码和周边知识点哪些值得学习的?

v3.vuejs.org

image.png

vue3一些核心,浪里个浪

更小更快
支持自定义渲染器
静态ID绑定标志
响应式修改为基于Proxy的侦测
深度结合typescript
基于treeshaking优化
Cache Handlers(事件侦听器的缓存)
...

setup()
ref()
watchEffect()
effect() 和 reactive()
...

与 2.x 版本生命周期相对应的组合式 API

beforeCreate → 使用 setup()
created → 使用 setup()
beforeMount → onBeforeMount
mounted → onMounted
beforeUpdate → onBeforeUpdate
updated → onUpdated
beforeDestroy → onBeforeUnmount
destroyed → onUnmounted
errorCaptured → onErrorCaptured

如何使用vue-next-template-explorer玩一玩?
https://vue-next-template-exp...

import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("span", null, "static"),
    _createVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)//1 patchflag flag是编译时生成的一个配置,只有带patchflag的Node(节点)会被追踪,比较text的文字变动
      
  ]))
}
<div>
  <span>static</span>
  <span>
    {{msg}}
  </span> 
</div>

vite简介
vite 是一个基于 Vue3 单文件组件的非打包开发服务器,它做到了本地快速开发启动:

1、快速的冷启动,不需要等待打包操作;
2、即时的热模块更新,替换性能和模块数量的解耦让更新飞起;
3、真正的按需编译,不再等待整个应用编译完成,这是一个巨大的改变。

特征就是使用了ES Module,代码以模块的形式引入到文件,同时实现了按需加载。
其最大的特点是在浏览器端使用 export import 的方式导入和导出模块,在 script 标签里设置 type="module" ,然后使用 ES module。

看看github这个项目:
《前端会客厅第一期代码》和尤大聊vue3的 提升: https://github.com/shengxinji...

三种体验vue3的方式

vue-cli

  • Vue create vue3-demo-cli
  • Vue add vue-next
  • 代码文件 vue3-demo-cli

webpack

  • 代码文件 vue-demo-webpack
  • 代码仓库

新工具vite

  • create-vite-app
  • 代码文件 vue3-demo-vite

而且使用了wrk来测压:

// vue2 12个进程,300个并发,压19秒
➜  ~ wrk -t12 -c300 -d19s http://localhost:3000/
Requests/sec:    130.58
Transfer/sec:     17.19MB
// vue3 12个进程,300个并发,压19秒
➜  ~ wrk -t12 -c300 -d19s http://localhost:3000/
Requests/sec:    288.21
Transfer/sec:     40.69MB

入手vue3,浪里个浪

两步得天下:

git clone https://github.com/vuejs/vue-next-webpack-preview.git
cd vue-next-webpack-preview
npm install

https://github.com/vuejs/vue-...

1、检查vue-cli脚手架版本(vue -V),低版本的要更新(npm install @vue/cli -g)
2、创建项目(vue create vue3test )
3、进入项目文件夹,更新vue版本(vue add vue-next)
4、运行项目(npm run serve)

Tips: 不是一帆风顺的,过程中估计的修修改改,项目才能跑起来,O(∩_∩)O哈哈~_

入手vue3 demo,浪里个浪

https://vue3.github.io/vue3-N...

几个vue3 demo,给你强势入门vue3时代。

  • win10 datepanel
  • todolist
  • art 马里奥
  • 2019-ncov-vue3-version

等等...

image.png

其实官网也一些基础案例:

image.png

https://github.com/vuejs/vue-...

vue3源码集合,浪里个浪

【这是入口】你要找的 vue 源码 全宇宙的都在这!
https://github.com/vue3/vue3-...

vue3安装下来的是打包压缩:
image.png

核心代码在这里:
image.png

https://github.com/vuejs/vue-...

【这是入口】你要找的 vue 源码 全宇宙的都在这!
https://github.com/vue3/vue3-...

查看更多,必须浪里个浪

Vue3+ & Vue-CLI3+ 开发生态圈资讯

该推荐文章列表的最新资讯会第一时间发布到Github上,欢迎Star:
Find the latest breaking √vue3 & vue-cli 3 News

🚀欢迎Star,后续会不断更新。
🇨🇳 最后更新日期:2️⃣0️⃣2️⃣0️⃣/0️⃣7️⃣/1️⃣7️⃣

【2020】 ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡------------------------ 【2021】

除了单独Vue3资讯,欢迎查看更多vue.js资讯:【【🔥Vue.js资讯📚】目前web前端开发非常火爆的框架;定时更新,欢迎 Star 一下。

image.png

查看原文

寒水寺一禅 发布了文章 · 8月24日

解决chrome的input莫名其妙被填充问题

曾经有个问题,困惑了很久很久....

问题如下,当我点击role下拉框时,居然给我弹出了 用户名的自动填充
image

这他妈真恶心,我点的仅仅是个 select,并非用户名区域

image

然后网上找了很多方法,不外乎什么修改 autocomplete为off,什么display:none,然后再显示等等等,其中大量的帖子都是复制,粘贴别人的东西。没有一句自己的东西。

后来我发现,当我给一个input="text"设置 placeholder为邮箱emaile-mail这三个关键字时,点击input,也会出现自动填充

image

如果里面没有包含这三个关键字,则不会出现自动填充

image

事实上,这个特性是浏览器的,它是通过判断placeholder中的关键字去找的。但是找的不是我们网页中的用户名和密码。而是浏览器的地址和其他信息中的邮箱

image

如果没有添加地址和邮箱,那么即使设置 placeholder为"email"也不会出现填充

image

除非新增个地址

image

来了

image

那么和我们平时看到的用户名密码的填充和邮箱填充有什么区别呢?

用户名密码的填充是在“密码区域”
image

并且在当前“ip和端口”下已经有之前保存过的用户名和密码,才会出现自动填充,
image

浏览器找密码区域很容易,只需要知道哪个input的type是password即可,那么它怎么知道谁是用户名呢?

原来浏览默认会去找 离type=“password”最近的上方的那个域为“用户名”,进行填充,即使那个不是一个input,而是个select,只要一获取焦点,就出现 "用户名填充区域"。

那么问题来了,我不想让点击select被填充(因为这真的很恶心),该怎么做呢?

在我看来,有几下几个方法:
1、调整顺序,把真正的用户名放到password的上方(可以跟产品聊聊,如果顺序无所谓的话)

2、禁用掉浏览的自动填充功能

image

但这个只能依赖于用户,用户不禁用,你也没办法

3、将password拆分到另外一个 form 中,这样,一个form放普通的input,另一个form放password,两个form中的域互不干涉,点击input就不会自动填充了

4、在password上方再新增一个空的input type="text",并将其隐藏掉

查看原文

赞 10 收藏 6 评论 3

寒水寺一禅 收藏了文章 · 8月5日

如果想成为一名顶尖的前端,这份书单你一定要收藏!

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

本文由腾讯IVWEB团队 发表于云+社区专栏

作者:link

2014年一月以来,自己接触web前端开发已经两年多了,记录一下自己前端学习路上看过的,以及道听途说的一些书,基本上按照由浅入深来介绍。

JavaScript

入门

《JavaScript权威指南(第六版)》 ★★★★★

img

淘宝前端团队翻译的,看译者列表都是一堆大神。这本书又叫犀牛书,号称javascript开发者的圣经,网上对此书评价很多,大概意思都是说这本书是一本JavaScript文档手册,没有完整看过一遍此书的都不能算是一名合格的前端工程师。

我也是从这本书开始接触前端开发的,当时还是华章出版社的校园大使,免费申请到了这本书,可惜的是两年来我一直把它作为一本cookbook来查阅,一直没有好好通读一遍。个人感觉这本书还是写得枯燥了些,不过内容绝对是五颗星,无可挑剔!

《JavaScript高级程序设计》 ★★★★★

img

又称红宝书,雅虎首席前端架构师,YUI的作者Zakas出品。虽然书名带了“高级”二字,但是讲得也很基础,而且行文风格很流畅,每一小节就像是一篇博客,读起来并不枯燥,个人感觉比上面那本犀牛书可读性更强。说到这里,也推荐大家多多关注作者的博客: http://www.nczonline.net/ ,上面也有许多高质量的博文。感觉这本书就像是作者平时的博文按照前端知识体系组织成了一本技术书。

《JavaScript DOM编程艺术》

img

作为初学者如果觉得上面两本书作为入门书来说太厚了,也可以看看这本,不厚,评价也很高,但是由于本人没看过,就不作过多评价了。

《JavaScript编程精解》 ★★★★

img

用上下班时间看完的第三本书。看起来比较吃力,第五章函数式编程和第六章的面向对象编程很多都没看懂。全书游戏式的编程教程还是很有意思的。译者tom大叔名头很大,翻译的质量也只是中规中矩吧。不过,还是get到很多技巧!这本书的推荐语说这本书用来入门很好,但是个人认为初学者并不合适看这本书入门,作者在代码示例中不自觉得使用了一些高级用法,初学者看容易晕菜。听说最近出了第二版,加入了NodeJS的内容,这本书是开源的:http://eloquentjavascript.net/

《JQuery权威指南》 ★★★

img

当时在北京实习时,在每天下班回家的地铁上把这本书看完了。错误很多啊,不过其中的语法+示例的形式,确实很适合初学者。但是错误实在太多了,而且有些语句还不通顺,看着很累啊,只能说写得好代码的人,书不一定写得好。

《ECMAScript6入门》 ★★★★

img

前端工程师当然要关注ECMAScript的发展。阮老师的这本科普小书!短小精悍,通俗易懂。这本书也是开源的:http://es6.ruanyifeng.com/

进阶

《编写可维护的JavaScript》 ★★★★

img

又一本Zakas的书,还没读完,基本上是zakas那本红宝书的子集,重点是javascript代码风格、规范以及最佳实践。

《JavaScript异步编程》 ★★★★

img

掌握异步编程,显然是一位JS开发者必备的技能,用多看的畅读优惠看完了这本介绍js异步编程的科普小书,书中介绍了js异步编程的概念、场景和工具,不过更重要的是把这些工具给用起来。

《JavaScript设计模式》 ★★★

img

作者似乎很偏爱JQuery的源码,不过这本书tom大叔翻译的很烂,代码也很多没有缩进。。。 不推荐。

《Effective JavaScript》 ★★★★

img

这本书我当时看到最后一章“并发”的部分就很吃力了,显然这是一本进阶的js书籍,还是先把那本权威指南啃完吧!听说这本书上的技巧对于IE6有很好的优化效果,不过显然书上提到的这些技巧肯定已经大量的运用到JQuery、Underscore这样流行的JS库中,这些第三方库已经帮我们把这些优化细节封装得很好了。

《JAVASCRIPT语言精髓与编程实践》

img

一本讲JavaScript的硬书,以JavaScript这门语言为栗子,讲述编程语言的特性(动态语言、函数式编程、面向对象编程等等)。作者周爱民老师是前支付宝架构师,现豌豆荚架构师。

《高性能JavaScript》

img

Zakas大神的又一本神书,高工推荐的。

最近开始看《You dont know JS》了,看了个开头,感觉也很不错!

CSS

入门

《Head First HTML与CSS、XHTML(中文版)》

img

进阶

《CSS权威指南(第三版)》

img

虽然是一本老书,但是CSS 2.1是基础

《精通CSS(第2版)》

img

好吧!以上三本书,我都没看过。。。

网络协议 & 架构

《HTTP权威指南》 ★★★★★

img

涉及web开发的前端、后台、运维的同学都可以看看。web应用架构师必看。其中对其中“缓存”、“负载均衡“等章节印象很深,标准的教科书啊,肯定比看枯燥的HTTP规范好多了。

《Web性能权威指南》

img

Google工程师教你优化web性能,刚看了个开头,高工推荐,听说讲得比较深。

《大型网站技术架构》 ★★★★

img

网站架构入门科普。刚刚看完,写得挺好的,通俗易懂。开篇明义:“大型网站是演化出来的,而不是设计出来的。”,书中阐述了缓存为王,分层,解耦,模块化等网站架构中应该遵循的原则。其中负载均衡那一节,基本上是参考的《HTTP权威指南》负载均衡的内容。总结来说,纵向和横向分层以及可线性伸缩的能力是大型网站面对复杂业务和海量访问的制胜法宝!

NodeJS

入门

《了不起的Node.js》 ★★★

img

作为NodeJS入门挺好的一本书,可惜讲得太浅了,基本上就是介绍开发一个简单的NodeJS应用所要用到的一些技术和工具,对里面的原理以及NodeJS本身没有做太多的介绍,停留在介绍第三方库及其API的阶段。

《Node.js开发指南》

img

读了一半,就是看这本书理解了NodeJS的事件循环。作者是大神啊。

进阶

《深入浅出Node.js》

img

很出名的一本书,对NodeJS的一些原理做了深入介绍,挺不错的,还没看完。

用户体验 & 产品

《点石成金》 ★★★★

img

恰好读过第二版和第三版,第三版中添加了mobile web的内容,并且更新和添加了一些新例子,总得来说,我更喜欢第二版的精简。ponyma曾经推荐过的好书。

《结网@改变世界的互联网产品经理》 ★★★★

img

这本书读了挺久。用产品开发过程中的实际案例介绍了产品经理的工作内容以及如何开展工作。并从创建产品和个人修炼两个方面描述了需求分析,产品设计,项目管理,产品运营,产品经理的沟通能力以及个人和团队的创新能力等等,附录的推荐书目和工具质量也很高!作者是前腾讯产品经理,糗事百科的创始人,不过好像在知乎上因为创始人股权纠纷的问题,被黑臭了。。。

《参与感》 ★★

img

很出名的一本书,但其实营销部分讲得一般,老生常谈,不如我的朋友何老湿讲的好啊,不过可能对传统企业转型互联网有一定参考价值。设计那一块说的还挺有意思的,不过肯定还是不如我的另外两位设计师朋友开花和佐叔咯。哈哈!

《创京东》 ★★★

img

一本骗钱的书。看完之后的感受是,京东的核心部门是采销,仓储和物流,排名分先后。

问答
BDD框架的前端如何搭建?
相关阅读
全面进阶 H5 直播(上)
NodeJs内存管理
WebGL 纹理颜色原理
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

此文已由作者授权腾讯云+社区发布,更多原文请点击

搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

海量技术实践经验,尽在云加社区

查看原文

寒水寺一禅 收藏了文章 · 8月5日

前端工程师成长之多读好书

1 引言

乱七八糟的书看了很多,有一本讲JavaScript的印象特别深开篇说的是"JavaScript是Java的脚本语言",但还是看完了,最后忘了书名。

下面列的这些都是看过后至少记得起书名的,也有部分是经常看的书,一起列出来,推荐给爱学习的同学。

2 前端技术

2.1 综合

  • 《现代前端技术解析》
  • 《Web前端开发最佳实践》
  • 《Web前端工程师修炼之道》
  • 《编写高质量代码-Web前端开发修炼之道》
  • 《响应式Web设计 HTML5和CSS3实战》 第二版
  • 《响应式设计、改造与优化》

2.2 基础

2.2.1 HTML && HTML5

  • 《HTML与CSS基础教程》第八版
  • 《HTML与XHTML权威指南》第六版
  • 《HTML5与CSS3实战指南》
  • 《HTML5和CSS3权威指南》
  • 《HTML5与CSS3设计模式》

2.2.2 CSS && CSS3

  • 《CSS世界》
  • 《CSS核心技术详解》
  • 《CSS权威指南》 第三版
  • 《CSS设计指南》第三版
  • 《精通CSS-高级Web标准解决方案》第二版
  • 《图解CSS3-核心技术与案例实战》

2.2.3 JavaScript && ES6+

  • 《看透JavaScript:原理、方法与实践》
  • 《实战ES2015:深入现代JavaScript 应用开发》
  • 《学习JavaScript数据结构与算法》 第二版
  • 《ES6标准入门》第三版
  • 《JavaScript忍者秘籍》第二版
  • 《JavaScript学习指南》第三版
  • 《You Don't Know JS》《你不知道的JS》
  • 《JavaScript权威指南》第六版
  • 《JavaScript高级程序设计》 第三版
  • 《JavaScript核心概念及实践》
  • 《JavaScript面向对象编程指南》第二版
  • 《JavaScript DOM编程艺术》第二版
  • 《JavaScript语言精粹》
  • 《动态函数式编程语言精髓与编程实践》

2.3 性能优化

  • 《Web性能权威指南》
  • 《高性能JavaScript》
  • 《JavaScript性能优化:度量、监控与可视化》
  • 《高性能网站建设指南》
  • 《高性能网站建设进阶指南》
  • 《大型网站性能监测、分析与优化》
  • 《网站性能监测与优化》
  • 《高效前端-Web高效编程与优化实践》
  • 《速度与激情-以网站性能提升用户体验》

2.4 安全

  • 《Web前端黑客技术揭秘》
  • 《白帽子讲Web安全》
  • 《黑客攻防技术宝典 Web实战篇》第二版
  • 《Web应用安全威胁与防治 基于OWASP Top 10与ESAPI》
  • 《Web之困-现代Web应用安全指南》
  • 《Web安全开发指南》
  • 《Web应用安全权威指南》
  • 《黑客攻防技术宝典 浏览器实战篇》
  • 《XSS跨站脚本攻击剖析与防御》

2.5 工程化 && 自动化

  • 《深入浅出Webpack》
  • 《深入PostCSS Web设计》
  • 《前端工程化体系设计与实践》
  • 《Web前端测试与集成- Jasmine/Selenium/Protractor/Jenkins的最佳实践》
  • 《Web前端自动化构建-Gulp、Bower和Yeoman开发指南》

2.6 协议

  • 《Web性能权威指南》
  • 《图解HTTP》
  • 《HTTP权威指南》
  • 《HTTPS权威指南》
  • 《图解TCP-IP》

2.7 浏览器

  • 《浏览器工作原理》 文章
  • 《Webkit技术内幕》

2.8 架构

  • 《JavaScript框架设计》第二版
  • 《前端架构设计》
  • 《JavaScript开发框架权威指南》
  • 《大型JavaScript应用实践最佳指南》
  • 《JavaScript框架高级编程》
  • 《JavaScript设计模式与开发实践》
  • 《JavaScript设计模式》
  • 《JavaScript模式》

3 学点其他的

3.1 所谓的全栈

  • Web开发者技能路线图
  • 教你成为全栈工程师
  • 《全栈增长工程师指南》 《全栈应用开发-精益实践》
  • 《Web全栈工程师的自我修养》
  • 《Web开发权威指南》
  • 《JavaScript快速全栈开发》
  • 《单页Web应用-JavaScript从前端到后端》
  • 《全栈开发之道-MongoDB+Express+AngularJS+Node.js》
  • 《全端Web开发-使用JavaScript和Java》

3.2 程序设计

  • 《代码大全》第二版
  • 《修改代码的艺术》
  • 《重构-改善既有代码的设计》
  • 《代码整洁之道》

3.3 计算机基础

  • 《深入理解计算机系统》第三版
  • 《计算机是怎样跑起来的》
  • 《程序是怎样跑起来的》
  • 《网络是怎样连接的》
查看原文

寒水寺一禅 赞了文章 · 7月30日

初学者应该看的 Webpack 完整指南(2020)

作者:Valentino Gagliardi
译者:前端小智
来源:valentinog
点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHubhttps://github.com/qq44924588... 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

我们应该学习 webpack 吗 ?

如今,CLI工具(如create-react-appVue -cli)已经为我们抽象了大部分配置,并提供了合理的默认设置。

即使那样,了解幕后工作原理还是有好处的,因为我们迟早需要对默认值进行一些调整。

在本文中中,我们会知道 webpack可以做什么,以及如何配置它以满足我们的日常需求。

什么是 webpack?

作为前端开发人员,我们应该熟悉 module 概念。 你可能听说过 AMD模块UMDCommon JS还有ES模块

webpack是一个模块绑定器,它对模块有一个更广泛的定义,对于webpack来说,模块是:

  • Common JS modules
  • AMD modules
  • CSS import
  • Images url
  • ES modules

webpack 还可以从这些模块中获取依赖关系

webpack 的最终目标是将所有这些不同的源和模块类型统一起来,从而将所有内容导入JavaScript代码,并最生成可以运行的代码。

entry

Webpackentry(入口点)是收集前端项目的所有依赖项的起点。 实际上,这是一个简单的 JavaScript 文件。

这些依赖关系形成一个依赖关系图

Webpack 的默认入口点(从版本4开始)是src/index.js,它是可配置的。 webpack 可以有多个入口点。

Output

output是生成的JavaScript和静态文件的地方。

Loaders

Loaders 是第三方扩展程序,可帮助webpack处理各种文件扩展名。 例如,CSS,图像或txt文件。

Loaders的目标是在模块中转换文件(JavaScript以外的文件)。 文件成为模块后,webpack可以将其用作项目中的依赖项。

Plugins

插件是第三方扩展,可以更改webpack的工作方式。 例如,有一些用于提取HTML,CSS或设置环境变量的插件。

Mode

webpack 有两种操作模式:开发(development)生产(production)。 它们之间的主要区别是生产模式自动生成一些优化后的代码。

Code splitting

代码拆分延迟加载是一种避免生成较大包的优化技术。

通过代码拆分,开发人员可以决定仅在响应某些用户交互时加载整个JavaScript块,比如单击或路由更改(或其他条件)。

被拆分的一段代码称为 chunk

Webpack入门

开始使用webpack时,先创建一个新文件夹,然后进入该文件中,初始化一个NPM项目,如下所示:

mkdir webpack-tutorial && cd $_

npm init -y

接着安装 webpackwebpack-cliwebpack-dev-server

npm i webpack webpack-cli webpack-dev-server --save-dev

要运行 webpack,只需要在 package.json 配置如下命令即可:

  "scripts": {
    "dev": "webpack --mode development"
  },

通过这个脚本,我们指导webpack在开发模式下工作,方便在本地工作。

Webpack 的第一步

在开发模式下运行 webpack:

npm run dev

运行完后会看到如下错误:

ERROR in Entry module not found: Error: Can't resolve './src'

webpack 在这里寻找默认入口点src/index.js,所以我们需要手动创建一下,并输入一些内容:

mkdir src

echo 'console.log("Hello webpack!")' > src/index.js

现在再次运行npm run dev,错误就没有了。 运行的结果生成了一个名为dist/的新文件夹,其中包含一个名为main.js的 JS 文件:

dist
└── main.js

这是我们的第一个webpack包,也称为output

配置 Webpack

对于简单的任务,webpack无需配置即可工作,但是很快我们就会遇到问题,一些文件如果没有指定的 loader 是没法打包的。所以,我们需要对 webpack进行配置,对于 webpack 的配置是在 webpack.config.js 进行的,所以我们需要创建该文件:

touch webpack.config.js

Webpack 用 JavaScript 编写,并在无头 JS 环境(例如Node.js)上运行。 在此文件中,至少需要一个module.exports,这是的 Common JS 导出方式:

module.exports = {
  //
};

webpack.config.js中,我们可以通过添加或修改来改变webpack的行为方式

  • entry point
  • output
  • loaders
  • plugins
  • code splitting

例如,要更改入口路径,我们可以这样做

const path = require("path");

module.exports = {
  entry: { index: path.resolve(__dirname, "source", "index.js") }
};

现在,webpack 将在source/index.js中查找要加载的第一个文件。 要更改包的输出路径,我们可以这样做:

const path = require("path");

module.exports = {
  output: {
    path: path.resolve(__dirname, "build")
  }
}

这样,webpack将把最终生成包放在build中,而不是dist.(为了简单起见,在本文中,我们使用默认配置)。

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

打包 HTML

没有HTML页面的Web应用程序几乎没有用。 要在webpack中使用 HTML,我们需要安装一个插件html-webpack-plugin

npm i html-webpack-plugin --save-dev

一旦插件安装好,我们就可以对其进行配置:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

这里的意思是让 webpack,从 src/index.html 加载 HTML 模板。

html-webpack-plugin的最终目标有两个:

  • 加载 html 文件
  • 它将bundle注入到同一个文件中

接着,我们需要在 src/index.html 中创建一个简单的 HTML 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Webpack tutorial</title>
</head>
<body>

</body>
</html>

稍后,我们会运行这个程序。

webpack development server

在本文第一部分中,我们安装了webpack-dev-server。如果你忘记安装了,现在可以运行下面命令安装一下:

npm i webpack-dev-server --save-dev

webpack-dev-server 可以让开发更方便,不需要改动了文件就去手动刷新文件。 配置完成后,我们可以启动本地服务器来提供文件。

要配置webpack-dev-server,请打开package.json并添加一个 “start” 命令:

"scripts": {
  "dev": "webpack --mode development",
  "start": "webpack-dev-server --mode development --open",
},

有了 start 命令,我们来跑一下:

npm start

运行后,默认浏览器应打开。 在浏览器的控制台中,还应该看到一个 script 标签,引入的是我们的 main.js

clipboard.png

使用 webpack loader

Loader是第三方扩展程序,可帮助webpack处理各种文件扩展名。 例如,有用于 CSS,图像或 txt 文件的加载程序。

下面是一些 loader 配置介绍:

module.exports = {
  module: {
    rules: [
      {
        test: /\.filename$/,
        use: ["loader-b", "loader-a"]
      }
    ]
  },
  //
};

相关配置以module 关键字开始。 在module内,我们在rules内配置每个加载程序组或单个加载程序。

对于我们想要作为模块处理的每个文件,我们用testuse配置一个对象

{
    test: /\.filename$/,
    use: ["loader-b", "loader-a"]
}

test 告诉 webpack “嘿,将此文件名视为一个模块”。 use 定义将哪些 loaders 应用于些打包的文件。

打包 CSS

要 在webpack 中打包CSS,我们需要至少安装两个 loader。Loader 对于帮助 webpack 了解如何处理.css文件是必不可少的。

要在 webpack 中测试 CSS,我们需要在 src 下创建一个style.css文件:

h1 {
    color: orange;
}

另外在 src/index.html 添加 h1 标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Webpack tutorial</title>
</head>
<body>
<h1>Hello webpack!</h1>
</body>
</html>

最后,在src/index.js 中加载 CSS:

在测试之前,我们需要安装两个 loader:

  • css-loader: 解析 css 代码中的 url、@import语法像importrequire一样去处理css里面引入的模块
  • style-loader:帮我们直接将css-loader解析后的内容挂载到html页面当中

安装 loader:

npm i css-loader style-loader --save-dev

然后在webpack.config.js中配置它们

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

现在,如果你运行npm start,会看到样式表加载在HTML的头部:

clipboard.png

一旦CSS Loader 就位,我们还可以使用MiniCssExtractPlugin提取CSS文件

Webpack Loader 顺序很重要!

在webpack中,Loader 在配置中出现的顺序非常重要。以下配置无效:

//

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["css-loader", "style-loader"]
      }
    ]
  },
  //
};

此处,“style-loader”出现在 “css-loader” 之前。 但是style-loader用于在页面中注入样式,而不是用于加载实际的CSS文件。

相反,以下配置有效:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      }
    ]
  },
  //
};

webpack loaders 是从右到左执行的。

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

打包 sass

要在 webpack 中测试sass,同样,我们需要在 src 目录下创建一个 style.scss 文件:

@import url("https://fonts.googleapis.com/css?family=Karla:weight@400;700&display=swap");

$font: "Karla", sans-serif;
$primary-color: #3e6f9e;

body {
  font-family: $font;
  color: $primary-color;
}

另外,在src/index.html中添加一些 Dom 元素:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Webpack tutorial</title>
</head>
<body>
  <h1>Hello webpack!</h1>
  <p>Hello sass!</p>
</body>
</html>

最后,将 sass 文件加载到src/index.js中:

import "./style.scss";
console.log("Hello webpack!");

在测试之前,我们需要安装几个 loader:

  • sass-loader:加载 SASS / SCSS 文件并将其编译为 CSS
  • css-loader: 解析 css 代码中的 url、@import语法像importrequire一样去处理css里面引入的模块
  • style-loader:帮我们直接将css-loader解析后的内容挂载到html页面当中

安装 loader:

npm i css-loader style-loader sass-loader sass --save-dev

然后在webpack.config.js中配置它们:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

注意loader的出现顺序:首先是sass-loader,然后是css-loader,最后是style-loader

现在,运行npm start,你应该会在HTML的头部看到加载的样式表:

clipboard.png

打包现代 JavaScrip

webpack 本身并不知道如何转换JavaScript代码。 该任务已外包给babel的第三方 loader,特别是babel-loader

babel是一个JavaScript编译器和“编译器”。 babel 可以将现代JS(es6, es7...)转换为可以在(几乎)任何浏览器中运行的兼容代码。

同样,要使用它,我们需要安装一些 Loader:

  • babel-core :把 js 代码分析成 ast ,方便各个插件分析语法进行相应的处理
  • babel-preset-env:将现代 JS 编译为ES5
  • babel-loader :用于 webpack

引入依赖关系

npm i @babel/core babel-loader @babel/preset-env --save-dev

接着,创建一个新文件babel.config.json配置babel,内容如下:

{
  "presets": [
    "@babel/preset-env"
  ]
}

最后在配置一下 webpack :

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

要测试转换,可以在 src/index.js中编写一些现代语法:

import "./style.scss";
console.log("Hello webpack!");

const fancyFunc = () => {
  return [1, 2];
};

const [a, b] = fancyFunc();

现在运行npm run dev来查看dist中转换后的代码。 打开 dist/main.js并搜索“fancyFunc”:

\n\nvar fancyFunc = function fancyFunc() {\n  return [1, 2];\n};\n\nvar _fancyFunc = fancyFunc(),\n    _fancyFunc2 = _slicedToArray(_fancyFunc, 2),\n    a = _fancyFunc2[0],\n    b = _fancyFunc2[1];\n\n//# sourceURL=webpack:///./src/index.js?"

没有babel,代码将不会被转译:

\n\nconsole.log(\"Hello webpack!\");\n\nconst fancyFunc = () => {\n  return [1, 2];\n};\n\nconst [a, b] = fancyFunc();\n\n\n//# sourceURL=webpack:///./src/index.js?"); 

注意:即使没有babel,webpack也可以正常工作。 仅在执行 ES5 代码时才需要进行代码转换过程。

在 Webpack 中使用 JS 的模块

webpack 将整个文件视为模块。 但是,请不要忘记它的主要目的:加载ES模块

ECMAScript模块(简称ES模块)是一种JavaScript代码重用的机制,于2015年推出,一经推出就受到前端开发者的喜爱。在2015之年,JavaScript 还没有一个代码重用的标准机制。多年来,人们对这方面的规范进行了很多尝试,导致现在有多种模块化的方式。

你可能听说过AMD模块,UMD,或CommonJS,这些没有孰优孰劣。最后,在ECMAScript 2015中,ES 模块出现了。

我们现在有了一个“正式的”模块系统。

要在 webpack 使用 ES module ,首先创建 src/common/usersAPI.js 文件:

const ENDPOINT = "https://jsonplaceholder.typicode.com/users/";

export function getUsers() {
  return fetch(ENDPOINT)
    .then(response => {
      if (!response.ok) throw Error(response.statusText);
      return response.json();
    })
    .then(json => json);
}

src/index.js中,引入上面的模块:

import { getUsers } from "./common/usersAPI";
import "./style.scss";
console.log("Hello webpack!");

getUsers().then(json => console.log(json));

生产方式

如前所述,webpack有两种操作模式:开发(development )和(production)。 到目前为止,我们仅在开发模式下工作。

在开发模式中,为了便于代码调试方便我们快速定位错误,不会压缩混淆源代码。相反,在生产模式下,webpac k进行了许多优化:

  • 使用 TerserWebpackPlugin 进行缩小以减小 bundle 的大小
  • 使用ModuleConcatenationPlugin提升作用域

在生产模式下配 置webpack,请打开 package.json 并添加一个“ build” 命令:

现在运行 npm run build,webpack 会生成一个压缩的包。

Code splitting

代码拆分(Code splitting)是指针对以下方面的优化技术:

  • 避免出现一个很大的 bundle
  • 避免重复的依赖关系

webpack 社区考虑到应用程序的初始 bundle 的最大大小有一个限制:200KB

在 webpack 中有三种激活 code splitting 的主要方法:

  • 有多个入口点
  • 使用 optimization.splitChunks 选项
  • 动态导入

第一种基于多个入口点的技术适用于较小的项目,但是从长远来看它是不可扩展的。这里我们只关注第二和第三种方式。

Code splitting 与 optimization.splitChunks

考虑一个使用Moment.js 的 JS 应用程序,Moment.js是流行的时间和日期JS库。

在项目文件夹中安装该库:

npm i moment

现在清除src/index.js的内容,并引入 moment 库:

import moment from "moment";

运行 npm run build 并查看控制的输出内容:

 main.js    350 KiB       0  [emitted]  [big]  main

整个 moment 库都绑定到了 main.js 中这样是不好的。借助optimization.splitChunks,我们可以从主包中移出moment.js

要使用它,需要在 webpack.config.js 添加 optimization 选项:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  module: {
  // ...
  },
  optimization: {
    splitChunks: { chunks: "all" }
  },
  // ...
};

运行npm run build 并查看运行结果:

        main.js   5.05 KiB       0  [emitted]         main
vendors~main.js    346 KiB       1  [emitted]  [big]  vendors~main

现在,我们有了一个带有moment.js 的vendors〜main.js,而主入口点的大小更合理。

注意:即使进行代码拆分,moment.js仍然是一个体积较大的库。 有更好的选择,如使用luxondate-fns

Code splitting 与 动态导入

Code splitting的一种更强大的技术使用动态导入来有条件地加载代码。 在ECMAScript 2020中提供此功能之前,webpack 提供了动态导入。

这种方法在 Vue 和 React 之类的现代前端库中得到了广泛使用(React有其自己的方式,但是概念是相同的)。

Code splitting 可用于:

  • 模块级别
  • 路由级别

例如,你可以有条件地加载一些 JavaScript 模块,以响应用户的交互(例如单击或鼠标移动)。 或者,可以在响应路由更改时加载代码的相关部分。

要使用动态导入,我们先清除src/index.html,并写入下面的内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dynamic imports</title>
</head>
<body>
<button id="btn">Load!</button>
</body>
</html>

src/common/usersAPI.js中:

const ENDPOINT = "https://jsonplaceholder.typicode.com/users/";

export function getUsers() {
  return fetch(ENDPOINT)
    .then(response => {
      if (!response.ok) throw Error(response.statusText);
      return response.json();
    })
    .then(json => json);
}

src/index.js

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  //
});

如果运行npm run start查看并单击界面中的按钮,什么也不会发生。

现在想象一下,我们想在某人单击按钮后加载用户列表。 “原生”的方法可以使用静态导入从src/common /usersAPI.js加载函数:

import { getUsers } from "./common/usersAPI";

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  getUsers().then(json => console.log(json));
});

问题在于ES模块是静态的,这意味着我们无法在运行时更改导入的内容。

通过动态导入,我们可以选择何时加载代码

const getUserModule = () => import("./common/usersAPI");

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  getUserModule().then(({ getUsers }) => {
    getUsers().then(json => console.log(json));
  });
});

这里我们创建一个函数来动态加载模块

const getUserModule = () => import("./common/usersAPI");

现在,当你第一次使用npm run start加载页面时,会看到控制台中已加载 js 包:

clipboard.png

现在,仅在单击按钮时才加载/common/usersAPI

clipboard.png

对应的 chunk 是 0.js

通过在导入路径前面加上魔法注释/ * webpackChunkName:“ name_here” * /,可以更改块名称:

const getUserModule = () =>
  import(/* webpackChunkName: "usersAPI" */ "./common/usersAPI");

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  getUserModule().then(({ getUsers }) => {
    getUsers().then(json => console.log(json));
  });
});

clipboard.png

人才们的 【三连】 就是小智不断分享的最大动力,如果本篇博客有任何错误和建议,欢迎人才们留言,最后,谢谢大家的观看。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://www.sitepoint.com/web...

交流

文章每周持续更新,可以微信搜索 【大迁世界 】 第一时间阅读,回复 【福利】 有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

查看原文

赞 56 收藏 39 评论 0

寒水寺一禅 分享了头条 · 7月7日

其中很多知识,平时很少用到,但实际却非常好用。正好借此机会,整理下,给大家补全盲区

赞 0 收藏 51 评论 0

寒水寺一禅 发布了文章 · 7月7日

那些不常见,但却非常实用的js知识(整理不易)

一、window

window 对象表示一个包含 DOM 文档的窗口,其 document 属性指向窗口中载入的 DOM 文档 。

1、window 属性和方法

在有标签页功能的浏览器中,每个标签都拥有自己的 window 对象;也就是说,同一个窗口的标签页之间不会共享一个 window 对象。

1.1、几个浏览器的高度

window.screen.height==window.screen.availHeight
表示手机的屏幕高度,在一部手机中是固定的。不同浏览器打开,都不会变。

window.innerHeight==document.documentElement.clientHeight
表示浏览器中,除去顶部地址栏,下部工具栏之外,暴露给用户,可以看的见的中间区域。也就是实际的网页浏览高度,不同浏览器不同。

document.body.clientHeight
body 元素的高度。
如果设置 body 的 height:30px; 那么这个属性就是 30。

下面是示意图,在 pc 端同理
image

1.2、window.performance

Web Performance API 允许网页访问某些函数来测量网页和 Web 应用程序的性能,包括 Navigation Timing API 和高分辨率时间数据。

performance.now()

该方法返回一个 DOMHighResTimeStamp 对象,该对象表示从某一时刻(译者注:某一时刻通常是 navigationStart 事件发生时刻)到调用该方法时刻的毫秒数。

image

1.3、devicePixelRatio

返回当前显示设备的物理像素分辨率与 CSS 像素分辨率之比。

物理像素分辨率表示,你的电脑的硬件部分,在出场时,已经确定。

而 css 像素分辨率,则可以动态调整。
当电脑显示设置为 100%时,物理像素分辨率和 css 像素分辨率是相等的。即 devicePixelRatio 为 1

window.devicePixelRatio   //1

image

而如果你将电脑设置为 150%;或者在电脑设置 100%时,同时将浏览器分辨率调成 150%,那么 devicePixelRatio 都为 1.5
image

image

window.devicePixelRatio   //1.5

你可以将 devicePixelRatio 为 1.5 理解为,1px 的 css 样式,占用了电脑硬件屏幕分辨路的 1.5 个 dpi,所以肉眼看起来电脑上的文字更大些。

这种放大的效果在某些情况下,会导致 html 中的元素失真,典型的便是 canvas 变得模糊。

下面是矫正代码

//size为原本的大小
let scale = window.devicePixelRatio;
canvas.width = Math.floor(size * scale);
canvas.height = Math.floor(size * scale);

image

1.4、base64 编码/解码
window.btoa() 编码为 base64

window.atob() 解码

let encodedData = window.btoa("Hello, world"); // 编码
let decodedData = window.atob(encodedData);    // 解码

image

1.5、requestAnimationFrame / cancelAnimationFrame()

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

回调函数执行次数通常是每秒 60 次,但在大多数遵循 W3C 建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。但是却和 setInterval(),不同,因为 setInterval 设置的秒,并不一定准确在对应秒后执行,而是需要看是否有其他资源在执行,如果有,则等待。实际可能大于等于设置的秒数,而 requestAnimationFrame 会准确的按照浏览器渲染的频率想匹配

//兼容性处理
var requestAnimationFrame =
  window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.msRequestAnimationFrame;

var cancelAnimationFrame =
  window.cancelAnimationFrame || window.mozCancelAnimationFrame;

var start = window.mozAnimationStartTime; // 只有Firefox支持mozAnimationStartTime属性,其他浏览器可以使用Date.now()来替代.

var myReq;
function step(timestamp) {
  var progress = timestamp - start;
  d.style.left = Math.min(progress / 10, 200) + "px";
  if (progress < 2000) {
    myReq = requestAnimationFrame(step); //必须再调用一次,这样就形成了递归
  }
}
myReq = requestAnimationFrame(step);

//当不需要是取消动画,比如 在vue destoryed中
window.cancelAnimationFrame(myReq);

image

image

1.6、getSelection()

此方法不必传入具体的 dom,选中哪个区域或者光标在哪个输入框, 此方法会获取到那个 dom。 返回一个selection对象

window.getSelection();

image

1.7、scroll() / scrollBy() / scrollTo()

scroll()滚动至文档中的绝对位置(类似于 css 中的 display:absolute), scrollBy()滚动指定的距离(类似于 css 中的 display:relative)

scrollTo 和 scroll 一致。

window.scroll({
  top: 100,
  left: 100,
  behavior: 'smooth'  //表示是否平滑的过渡还是即可调到指定位置,同css属性scroll-behavior
});
window.scrollBy({
  top: 100,
  left: 100,
  behavior: "smooth"
});

scroll() scrollBy() scrollTo()合称为 scrollOptions API
image

2、window 事件

通常在定义 window 中的事件时,有两种方式:

  • window.onXXX = function(){};
  • window.addEventListener("XXX", ()=>{}, {capture:true, once:true, passive:true});

那么这两种方式有区别吗? 有区别,但也没区别。

因为虽然定义的方式不同,可最终都会走到事件中。

但是又有区别,尤其在多个组件中,同时定义相同的事件,那么 window.onXXX 会后面定义的把前面定义的相同事件覆盖掉。最终只会执行最后定义的那个。而 window.addEventListener 不同,定义几个,执行几次,而且还可以再 options 中设置 once,capture,passive 等选项。

以 passive 为例,它可以忽略事件得默认行为,不会阻止它。当你在 js 操作时,html 中会立马响应到。最典型得可以使得触摸事件和 scroll 事件不再卡顿,非常流畅。

通常有 XXX 方式,那么对应也会有 onXXX

2.1、onbeforeunload

当窗口即将被卸载(关闭)时,会触发该事件.此时页面文档依然可见,且该事件的默认动作可以被取消.

需要注意的是,点击浏览器标签页的 x 号前,如果没有对页面进行过任何“操作”,则不会弹框直接关闭,如果进行过操作,则会弹出确认框。

这里所指的“操作”包括,但不限于,input 输入,打开 console,复制页面的一段文字等等。

window.onbeforeunload = () => {
    let isIE = xxxxxxxx; //忽略通过user-agent判断ie浏览器的方法
    if (isIE) {
      return "The system may be not save your changes.";
    } else {
      return false; //其他浏览器会弹出自己的文字,如上图。是中文
    }
};

image

2.2、onhashchange

当 一个窗口的 hash (URL 中 # 后面的部分)改变时就会触发 hashchange 事件(参见 location.hash)。

window.onhashchange = (newURL, oldURL)=>{
    //newURL 当前页面新的URL
    //oldURL 当前页面旧的URL
};

image

2.3、onload / DOMContentLoaded

DOMContentLoaded 指 html 页面加载完毕就会触发,至于一些异步资源的比如 img,video 等等,它不关心。

而 onload 表示除了 html 加载完,img,video 等也加载完,才执行

window.addEventListener("load", function () {

});

window.addEventListener("DOMContentLoaded", function () {

});

image

image

看到没: JavaScript event that fires when the DOM is loaded, but before all page assets are loaded (CSS, images, etc.). 说的再清楚不过了

2.4、onmouseover、onmouseout / onmouseenter、onmouseleave

onmouseover、onmouseout:鼠标移动到自身时候会触发事件,同时移动到其子元素身上也会触发事件 onmouseenter、onmouseleave:鼠标移动到自身是会触发事件,但是移动到其子元素身上不会触发事件

onmouseover 和 onmouseout 支持性一致
image

onmouseenter 和 onmouseleave 支持性一致
image

2.5、onscroll / onwheel

onwheel 事件在鼠标滚轮在元素上下滚动时触发,必须滚轮要转,至于页面滚不滚动,它不关心。

onscroll 事件在元素滚动条在滚动时触发,必须滚动条存在且上下运动。
触发方式有:滚轮滚动,鼠标按住滚动条拖动,键盘上下键滚动,js 脚本去滚动如 scrollTo,scrollBy,scrollByLines, scrollByPages 等。

在这里有个特殊,在手机端,虽然没有鼠标,但是手指触摸上下滚动,也是触发 onscroll 的。

image

image
什么? 支持率这么一点点? 大大出乎我的意料

2.6、copy 事件/cut 事件/ paste 事件

window 的复制/剪切, 粘贴事件。

window.addEventListener("copy", function (e) {
    //将复制的数据,存入到剪切板中
    e.clipboardData.setData("abc", "Hello, world!");
    e.preventDefault();
});

window.addEventListener("paste", function (e) {
    //再从剪切板中取出数据
    let data = e.clipboardData.getData("abc");
    e.preventDefault();
});

这三个事件支持性一致

image

2.7、error 事件

当资源加载失败或无法使用时,会在 Window 对象触发 error 事件。例如:script 执行时报错。

window.addEventListener('error', (event) => {

});

image

2.8、orientationchange 事件

orientationchange 事件在设备的纵横方向改变时触发。

window.addEventListener("orientationchange", function() {

});

image
pc 上几乎都不支持,这也能理解,毕竟 pc 上是使用 resize 的,只有手机才会使用 横竖屏。

2.9、rejectionhandled 事件 / unhandledrejection 事

当 Promise 被 rejected 且有 rejection 处理器时会在全局触发 rejectionhandled。

当 Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件;

window.addEventListener("rejectionhandled", event => {

}, false);

window.addEventListener("unhandledrejection", event => {

});


function getName() {
    return Promise.reject("error");
}

let p = getName();   //触发unhandledrejection
setTimeout(() => {
    p.catch((err) => {});  //触发rejectionhandled
}, 1000);

image

image

2.10、storage 事件

当 localStorage 被修改时,将触发 storage 事件。

注意:

  • 只有在同域名的不同文件之间,才能够监听到,
  • 同一个文件中,是监听不到的(合理,同一个文件直接拿就行了,用 storage 监听多此一举)
  • 通过 iframe 引入的另一个站点,也可以监听到

image

2.11、online 事件 / offline 事件

online 当网络连接时,触发,
offline 当网络断开时触发

online 和 offline 支持性一致
image

二、element(DOM 对象)

1、element 属性和方法

1.1、clientHeight / clientWidth 属性
  • clientHeight:元素内部的高度,包含内边距,但不包括水平滚动条、边框和外边距。
  • clientWidth:元素内部的宽度,包含内边距,但不包括垂直滚动条、边框和外边距。

此属性会将获取的值四舍五入取整数。

document.querySelector("span").clientWidth

clientHeight 和 clientWidth 支持性一致
image

1.2、scrollHeight / scrollWidth 属性

类似于上方的 clientHeight / clientWidth,不同在于 clientHeight / clientWidth 在元素设置 overflow 后,不包含隐藏不可见的高度部分。而 scrollHeight / scrollWidth 却包含隐藏的那部分高度。

我觉得利用这个特性来判断是否超长,如果 scrollWidth 大于 clientWidth,则表示超长,此时可以对于那些超长后显示...的元素在浮上去后展示一个自定义的 toolip.

scrollHeight 和 scrollWidth 支持性一致
image

1.3、getBoundingClientRect()方法

返回元素的大小及其相对于视口的位置(眼睛看的见的文档区域)。

这个方法超级好用。不管你的元素在什么位置,它都会计算出来当前元素 相当于 视口的边缘的位置,和滚动条无关。

image

返回值为

{
    bottom: xx,  //元素底部离视口顶部的距离
    height: xx,   //元素高度,和元素的clientHeight属性一致,但比它精确,会保留小数
    left: xx,  //元素左边离视口左侧的距离
    right: xx,  //元素右边离视口左侧的距离
    top: xx,   //元素上部离视口顶部的距离
    width: xx,   //元素宽度,和元素的clientWidth属性一致,但比它精确,会保留小数
}

image
这个方法的支持性为 100%, 良心啊,为什么我才知道这个方法?

1.4、scrollIntoView()方法

如果父元素定义了 overflow,并产生了滚动条,里面有个子元素,在滚动条滑动后,看不到了。那么可以让这个子元素执行这个方法,让元素滚动到父元素可视区域内。

可以定义滚动条可视区域的顶部,底部,还是左边,右边。
也可以定义平滑的滚动过来,还是一瞬间滚动过来。

这个方法的好处是自动计算里面子元素距离可见区域多少,不需要给数值进行人为干涉,而 scroll()或 scrollTo()方法,必须人为计算滚动条的距离,然后给个数值,才能滚动到某个位置。

首先看个例子,
image

div1 超过屏幕的区域有个 div2,超过 div2 的区域有个 span1,此时我们可以通过调用 span1 元素的 scrollIntoView 方法,让 span1,滚动到 div2 的可见区域,也就是向左边滚动,但是有个坏处,就是 div1 也会向上滚动,直到 div2 能被用户看到。
而 scroll()或 scrollTo()方法在 span1 滚动到 div2 的可见区域时,div1 不动。不会产生其他附加作用,直到你慢慢滑屏,才会看到 span1,已经停留在 div2 的可视范围了。

image

1.5、scroll() / scrollTo() / scrollBy() 方法

scrollTo 方法可以使界面滚动到给定元素的指定坐标位置。

以产生滚动条的那个父元素为基准,

scroll() scrollBy() scrollTo()合称为 scrollOptions API
image

2、element 事件

2.1、contextmenu 事件

contextmenu 事件会在用户尝试打开上下文菜单时被触发。该事件通常在鼠标点击右键或者按下键盘上的菜单键时被触

<p id="noContextMenu">这个段落右键菜单已被禁用。</p>



noContext = document.getElementById('noContextMenu');

noContext.addEventListener('contextmenu', e => {
  e.preventDefault();
});

单击右键,不会出现标准的右键菜单项目

image

2.2、copy 事件/cut 事件/ paste 事件

dom 的复制/剪切, 粘贴事件。

<div class="source">
  Try copying text from this box...
</div>
<div class="target" contenteditable="true">
  ...and pasting it into this one
</div>
let sourceDom = document.querySelector(".source");
sourceDom.addEventListener("copy", function (e) {
  //将数据存入剪切板
  e.clipboardData.setData("abc", "Hello, world!");
  e.preventDefault();
});

let targetDom = document.querySelector(".target");
targetDom.addEventListener("paste", function (e) {
  //从剪切板取出来
  let data = e.clipboardData.getData("abc");

  //自定义转化数据
  data = data.toUpperCase();

  //获取光标位置
  const selection = window.getSelection();
  if (!selection.rangeCount) return false;
  selection.deleteFromDocument();
  //将转换后的数据插入到光标位置
  selection.getRangeAt(0).insertNode(document.createTextNode(data));

  e.preventDefault();
});

这三个事件支持性一致

image

2.3、focusin 事件 / focusout 事件

当元素获得焦点时,focusin 事件被触发。
focusin 事件和 focus 事件之间的主要区别在于 focus 不会冒泡。

当元素即将失去焦点时,focusout 事件被触发。
focusout 事件和 blur 事件之间的主要区别在于 blur 不会冒泡。

image

2.4、onscroll / onwheel

类似于 window 的 onscroll 和 onwheel。只不过绑定对象为 element

let sourceDom = document.querySelector(".source");
sourceDom.addEventListener("scroll", function (e) {
    console.log("111");
});

sourceDom.addEventListener("wheel", function (e) {
    console.log("111");
});

三、document(文档对象)

1、document 属性和方法

1.1、characterSet

返回当前文档的字符编码,但有相当一部分浏览器未实现,可使用原始的 charset 代替

document.characterSet || document.charset
1.2、compatMode

表明当前文档的渲染模式是怪异模式/混杂模式还是标准模式。

document.compatMode  //  BackCompat怪异模式, CSS1Compat标准模式

image

1.3、defaultView

返回当前 document 对象所关联的 window 对象,如果没有,会返回 null。

document.defaultView   //返回还是window,我为什么不直接 使用window呢?

上面的代码很平淡,不足为奇,可是下面的就不一定了

<div class="source" style="height: 200px; overflow: auto;">
    <object type="text/html" style="width: 100%; height: 100%;"> </object>
</div>
let doc = document.querySelector("object").contentDocument; //得到一个document对象

doc.defaultView; //接着得到一个window

得到这个 window 后,有什么用呢?

我们可以想象一个场景,当我们缩放 window 窗口时,会触发 window 的 onresize 事件,但是缩放 div,却不会触发 onresize 事件,因为 dom 没有 onresize,那么如何监听一个 div 的 resize 呢?

就是上述的方式,在 div 中套一个 object。我不监听 div,我监听 div 中的 object,一旦 div 变了,object 不也就变了吗?

然后通过 object 返回的一个 window 对象,就自然可以绑定 onresize 事件了

document.querySelector("object").contentDocument.defaultView .addEventListener("resize", () => {
    //只要div尺寸变化,object尺寸就变化,resize就能监听到。不管何种原因导致的尺寸变化。都会监听到。
});

image

除此之外,我有一遍专门介绍如何彻底解决 div 尺寸变化问题的文章,有兴趣的伙伴可以阅读

1.4、designMode

控制整个文档是否可编辑。有效值为 "on" 和 "off" 。

默认值为 "off" 。如果设置为"on",则好比给 html 所有的元素都添加了 contenteditable 属性。

image

1.5、documentElement

会返回文档对象(document)的根元素。

可以通过 document.documentElement.clientHeight 来获取浏览器的可用高度,这个高度和 html 或者 body 的 style 上的 height 无关,只与浏览器的上方地址栏,下方工具栏等有关,和 window.innerHeight 相等。

image

2、document 事件

2.1、onscroll / onwheel

类似于 window 的 onscroll 和 onwheel。只不过绑定对象为 document

document.addEventListener("scroll", function (e) {
    console.log("111");
});

document.addEventListener("wheel", function (e) {
    console.log("111");
});
查看原文

赞 61 收藏 51 评论 4

寒水寺一禅 赞了回答 · 6月24日

网页如何调用微信打开指定的链接啊?

第三方浏览器打开微信的接口,微信只给部分合作平台开放了接口权限,任何第三方想调用只能是通过一些技术手段来请求接口,获取秘钥(ticket)。

网上搜出来的,都是各种卖接口的

=============================

貌似已经被屏蔽了,网上搜,都是各种广告

官方文档:https://open.weixin.qq.com/cg...

关注 24 回答 2

寒水寺一禅 发布了文章 · 6月5日

那些不常见,但却非常实用的css属性(整理不易)

1、-webkit-line-clamp

可以把 块容器 中的内容限制为指定的行数。并且在超过行数后,在最后一行显示"..."

这是正常的展示

image

display: -webkit-box; /*值必须为-webkit-box或者-webkit-inline-box*/
-webkit-box-orient: vertical; /*值必须为vertical*/
-webkit-line-clamp: 2; /*值为数字,表示一共显示几行*/
overflow: hidden;

这是加了 line-clamp 后的展示

image

https://developer.mozilla.org/zh-CN/docs/Web/CSS/-webkit-line-clamp

2、all

将除却 unicode-bidi 与 direction 之外的所有属性重设至其初始值,或继承值。

all: unset; /*initial | inherit | unset*/
initial 改变该元素所有属性的值至初始值。

inherit 改变该元素的值 至 从父元素继承的值

unset 如果该元素的属性的值是可继承的,重置为父元素的继承的值,反之则改变为初始值。

3、box-decoration-break

https://developer.mozilla.org/zh-CN/docs/Web/CSS/box-decoration-break

4、caret-color

用来定义插入光标(caret)的颜色,这里说的插入光标,就是那个在网页的可编辑器区域内,用来指示用户的输入具体会插入到哪里的那个一闪一闪的形似竖杠 | 的东西。

caret-color: red;

image

5、clip-path / shape-outside

clip-path 属性使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。类似的裁剪还有 svg 的 clipPath。

clip-path 的取值有以下几种图形

inset(xxx): 裁剪为长方形

circle(xx): 裁剪为原型

ellipse(xxx): 裁剪为椭圆

polygon(xx): 裁剪为多边形

none: 不裁剪

例子前的准备

<div
  style="width: 500px; height: 500px;text-align: left;background-color:gray;color:white"
>
  <img
    class="clip-mode"
    style="float: left; margin:20px"
    data-original="https://interactive-examples.mdn.mozilla.net/media/examples/balloon-small.jpg"
    width="150"
  />
  We had agreed, my companion and I, that I should call for him at his house,
  after dinner, not later than eleven o’clock. This athletic young Frenchman
  belongs to a small set of Parisian sportsmen, who have taken up “ballooning”
  as a pastime. After having exhausted all the sensations that are to be found
  in ordinary sports, even those of “automobiling” at a breakneck speed, the
  members of the “Aéro Club” now seek in the air, where they indulge in all
  kinds of daring feats, the nerve-racking excitement that they have ceased to
  find on earth.
</div>

不裁剪

clip-path: none;

image

圆形裁剪

clip-path: circle(40%);  //半径为40%,圆心默认为中心

image

椭圆裁剪

clip-path: ellipse(130px 140px at 10% 20%);

image

多边形裁剪

clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

image

我们可以看到上面图形如何裁剪,外面的看不见的框始终是矩形,也就是说文字始终是按矩形的样式在周围环绕。

那么有办法让文字紧紧的贴在裁剪的图形周围呢?
有的,使用 shape-outside 属性

shape-outside 定义了一个可以是 非矩形的形状,相邻的内联内容应围绕该形状进行包裹。默认情况下,内联内容包围其矩形边距;

默认矩形环绕

clip-path: none;
shape-outside: none

image

圆形环绕

clip-path: circle(40%);
shape-outside: circle(40%);

image

椭圆环绕

clip-path: ellipse(130px 140px at 10% 20%);
shape-outside: ellipse(130px 140px at 20% 20%);

image

多变性环绕

clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
shape-outside: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

image

当然你不一定在圆形裁剪上,使用圆形环绕,你可以在圆形裁剪上使用多边形环绕,在多边形裁剪上,使用菱形环绕。总之这两个之间没关系,不是两两匹配的。都随你便,自己定义

6、object-fit / object-position

object-fit 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。

object-position 属性来指定被替换元素的内容对象在元素框内的对齐方式。

注: 其中可替换元素有 iframe,video,embed,img,还有一些在特性情况也是可替换元素,option,audio,canvas,object

例子前的准备

<div style="width: 300px; height: 300px; background-color:gray;">
    <img class="clip-mode" style="height: 100%; width: 100%;" data-original="https://interactive-examples.mdn.mozilla.net/media/examples/plumeria.jpg">
</div>

图片一定能要设置为宽高 100%,即不能超过父容器,才可以设置 object-fit,否则没意义。

fill 填满 图片会拉变形,宽度和高度都被拉到父容器的 100%,以适应父容器

object-fit: fill;

image

contain 包容 图片不会变形,图片会按照自身比例进行缩放,整个图片放入父容器中,较短的边会出现自动填充的空白。

object-fit: contain;

image

cover 覆盖 图片不会变形,图片会按照自身比例进行缩放,整个图片放入父容器中,按照图片最短的边,纳入父容器为基准。较长的边会溢出

object-fit: cover;

image

none 和父容器的宽高没关系。展示其图片最原始的宽高比,以自身图片的“中心”为基点,放置到父容器的“中心”位置。

object-fit: none;

image

scale-down 内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。

object-fit: scale-down;

如果图片比父容器尺寸大,那么按照 contain 的效果,如果图片比父容器小,那么按照 none 的效果。

在上面 object-fit 的展示中,我们发现可替换元素的对齐方式都是自动的。

比如 object-fit: fill; 的左上角和父容器的左上角对齐。

object-fit: none;的中心和父容器的中心对齐等等。

但是我们想手动更改对齐方式呢??

可以使用 object-position 属性, 规定了可替换元素的内容,在其内容框中的位置。

object-position: 10px 10px; 可以设置 px,第一个值代表距离父容器左边的距离,第二个值代表距离父容器顶部的距离。只有一个数值则只代表距离父容器左侧的距离。也可以设置%数值,但此时只有某一边有空白才会起作用,如果没有空白,刚好铺满父元素,则不起作用。设置 px 就没有这样的问题,任何之后都会起作用。

object-position: right top;可以设置关键字,第一个值关键字可设置(left|center|right),第二个关键字可设置(top|center|bottom),此时不表示距离左侧或者顶部的距离,而表示放置在父元素的什么位置。

object-fit: fill;
object-position: 50px 50px;   //距离左侧10px,距离顶部10%

加 object-position 前后对比图:
image

object-fit: contain;
object-position: right top;  //停留子 右上方

加 object-position 前后对比图:
image

7、font-stretch

为字体定义一个正常或经过伸缩变形的字体外观,它仅仅意味着当有多种字体可供选择时,会为字体选择最适合的大小。

normal 默认字体

semi-condensed, condensed, extra-condensed, ultra-condensed 小于默认字体

semi-expanded, expanded, extra-expanded, ultra-expanded 大于默认字体

image

8、font-variant-caps

可以控制大写字母特殊字符的使用。

  • normal 关闭一切特殊字符变体的使用。
  • small-caps 允许小型大写字母的使用(OpenType 特性:smcp)。小型大写字母指使用大写形式,但尺寸与对应小写字母相同的字母。
  • all-small-caps 将大小写字母全部转化为小型大写字母。(OpenType 特性: c2sc, smcp)。
  • petite-caps 允许特小型大写字母的使用(OpenType 特性: pcap)。
  • all-petite-caps 将大小写字母全部转化为小型大写字母。(OpenType 特性: c2pc, pcap)。
  • unicase 允许将大写字母转化为小型大写字母与普通小写字母的混用 (OpenType 特性: unic)。
  • titling-caps 允许首字母大写(OpenType 特性: titl)。大写字母变体字符通常被设计成与用于小写字母。在标题序列中,如果均使用大写字母,可能会带来过于强烈的视觉效果。首字母大写即用来应对这种情况。

image

9、font-variant-east-asian

控制对东亚字符(如日语和汉语,韩语等)使用替代符号。

值有一下几种:
normal; ruby; jis78; jis83; jis90; jis04; simplified; traditional; full-width; proportional-width
image

10、max-content / min-content / fill-available / fit-content

这几个值都可用在 width, height, min-width, min-height, max-width 和 max-height 属性上。

display 必须为 inline-block 或者 block,否则上面的值不起作用。

fill-available

元素撑满可用空间。参考的基准为父元素有多宽多高。

类似子元素的 div 撑满父元素的宽,fill-available 不仅可以撑满宽还能撑满高。

例子前的代码

<div style="width: 300px; height: 100px; background-color:gray;">
  <span style="display:inline-block;background-color: burlywood;"
    >这是子元素的内容</span
  >
</div>

给 span 上设置 fill-available 时的不同表现
image

假如里面的有个元素,是 img 呢?它也是 inline-block,应该也满足情况。
image
我们可以看到 img 和 span 的不同在于,设置 width 或者 height 其中一个时,整个 image 会按照自身比例缩放。

max-content

它的宽度或者高度,会自动调整为,刚刚好容纳下子元素中那个长度最长(按照文字不换行时计算)的元素即可。
参考的基准为子元素有多宽多高。

<div class="parent">
  <div class="current" style="width: 200px; height: 300px; background-color:gray;">
    <p>这是普通的p元素行,内容为文字</p>
    <img data-original="https://interactive-examples.mdn.mozilla.net/media/examples/balloon-small.jpg"/>
  </div>
</div>

给 current div 设置 max-content 时得不同表现。
image

min-content

它的宽度或者高度,会自动调整为,刚刚好容纳下子元素中那个“最小宽度值”最大的元素即可,剩余超长的要么换行,要么溢出
参考的基准为子元素“最小宽度值”有多宽多高。

什么是“最小宽度值”?
比如图片,最小宽度值,就是图片原始的宽高;如果是一串中文,则最小宽度值为单个汉字的宽高;如果是一串英文,则最小宽度值为里面单词最长的那个。

image

fit-content

表示元素自动伸缩到内容的宽度,和 max-content 的区别为,都是刚刚好容纳下子元素中那个长度最长的元素即可。

不同的是 max-content 在计算时按照文字不换行时计算,如果超过父元素,则不换行,直接产生滚动条; 而 fit-content 在超过父元素后,换行,不产生滚动条。

image

11、fit-content()

这个不同于上面的 fit-content 值,它是函数,用在 grid 布局当中。

(略)

具体查看 grid 布局。

12、resize

比较简单,可以查看

官方文档

13、scroll-behavior

当用户通过 API 触发滚动操作时,CSS 属性 scroll-behavior 为一个滚动框指定滚动行为, 平滑到达还是立即到达

可以查看
官方文档

14、max() / min()

max 在两者这件取最大;min 函数在两者之间取最小。

max,min 可以用在任何可以设置 <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> 等值的地方

width: max(50vw, 300px);
width: min(50vw, 300px);

15、clamp()

clamp 函数会在定义的 三个值之间,取中间的那个值,是大小在中间,不是位置在中间,

clamp(MIN, VAL, MAX)

和 max,min 函数一样,可以用在任何可以设置 <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> 等值的地方

font-size: clamp(1px, 3px, 2px);    //中间值为2px
font-size: clamp(1px, 3px, 5px);    //中间值为3px
font-size: clamp(4px, 3px, 5px);    //中间值为4px
width: clamp(200rem, 25vw, 150px);  //在这三个之间取中间值

16、conic-gradient()

在渐变中我们知道,有:

  • 线性渐变,linear-gradient,从一个方向,沿着另一个方向,颜色线性过渡。

image

  • 径向基渐变,radial-gradient,从某一个点,沿圆环向外慢慢辐射。

image

除此之外,还有一种渐变,叫"锥形渐变"。它是围绕中心点按照扇形方向进行旋转的渐变(而不是从中心点辐射)

这是锥形和径向渐变的区别图
image

background: conic-gradient(red, orange, black, green, blue);

默认从时钟 12 点,按照顺时针旋转

image

18、:out-of-range / :in-range

比较简单,可以查看官方文档

:out-of-range

:in-range

19、writing-mode

定义了文本水平或垂直排布以及在块级元素中文本的书写方向

horizontal-tb 表示水平书写,从上(top)到下(bottom)书写

vertical-rl 表示垂直书写,从右(right)向左(left)(古人书法就这么写的)

vertical-lr 表示垂直书写,从左向右

注意没有 horizontal-bt,不要杜撰

image

20、inline-size

和元素的 width,height 效果一样,都会改变盒子的大小。但是会覆盖 width,height 值。

不同在于,width 是绝对的水平方向,height 是绝对的竖直方向;

而 inline-size 是相对的水平方向,可通过 writing-mode 模式,改变方向

image

21、block-size

类似于 inline-size,只不过和 inline-size 刚好相反,block-size 默认设置的是 height 方向的值。

image

查看原文

赞 65 收藏 50 评论 10

寒水寺一禅 发布了文章 · 5月29日

ES2015(ES6)之后特性的合集(很详细)

一、ES 2016

1、Array.prototype.includes 和 String.prototype.includes

在之前我们比较一个数组中是否包含某个元素的常用做法是:

if (arr.indexOf(el) !== -1) {
    ...
}

或者

if (~arr.indexOf(el)) {
    ...
}
//此处~ 为取反,即-1取反结果为0,0取反为-1,1取反会-2,2取反为-3

indexOf 结果返回是个数字,我们必须要和其他数字进行比较,才能见到得到是否"存在",即-1 表示不存在,大于-1 表示存在。

由于 indexOf 在查找元素的比对过程中,使用的是严格相等"===",比如

[1,2,3].indexOf('1')   //就会找不到。因为1和'1'并不相等。

同样在当数组中含有 NaN 是,也找不到,即

[NaN].indexOf(NaN)   //找不到,因为NaN===NaN为false。

由此可见 indexOf 并不能完美的找出是否包含某个元素值。

所以我们便有了下面的方式

arr.includes(el);

includes 结果直接返回 boolean,true 表示存在,false 表示不存在,非常直观。includes 是通过,类型和值是否“一致”,而不是“严格相等”

[1,2,3].includes('1')   //false
[1,2,3].includes(1)   //true
[1,2,NaN].includes(NaN)   //true

所以再以后的使用中,
indexOf 应倾向于寻找 元素的位置,可能后续还要通过这个位置进行其他计算的场景,而 includes 应倾向于寻找 元素是否存在,只需要知道存在或者不存在,其他不必知道

既然数组有 indexOf,字符串也有 indexOf,那么同样
数组有 includes,字符串也有 includes

"1234567".includes("12")   //true
2、指数运算符

在以前,js 要求取 m 的 n 次方,得这么写

Math.pow(m,n)

比如 2 的 3 次方

Math.pow(2,3)  //8

而现在只需要 指数操作符"**",即两个星号即可

2 ** 3  //表示2的3次方
3 ** 2  //表示3的2次方

由于- + _ /,都有 -=,+=, _=, /=

同样 也有 "="

let a = 2;
a **= 2; //  a = a ** 2

二、ES 2017

1、Object.values / Object.keys() / Object.entries

将 object 的 key 或者 value 转成一个可以遍历的数组。

Object.values({id:1,name:2});    // [1,2]
Object.keys({id:1,name:2});    // ["id", "name"]
Object.entries({id:1,name:2});    // [["id", 1], ["name", 2]]
2、字符串“填充”
  • String.prototype.padStart(); 使用给定的字符串,填充原字符串头部,整体达到一定的长度
  • String.prototype.padEnd();使用给定的字符串,填充原字符串尾部,整体达到一定的长度
  • String.prototype.trimRight();移除尾部的空白(和 trimEnd 一样,为了兼容其他浏览器)
  • String.prototype.trimLeft();移除首部的空白(和 trimStart 一样,为了兼容其他浏览器)
  • String.prototype.trimEnd(); 移除尾部的空白
  • String.prototype.trimStart();移除首部的空白
  • String.prototype.trim(); 移除两端的空白
//padStart
"abc".padStart(10); // "       abc"  在原字符串"abc"的头部填充空白,以使整个字符串的长度变为10
"abc".padStart(10, "foo"); // "foofoofabc"  在原字符串"abc"的头部填充"foo",以使整个字符串的长度变为10
"abc".padStart(6, "123465"); // "123abc"   在原字符串"abc"的头部填充"123465",以使整个字符串的长度变为10,如果中途够了,就不进行填充了
"abc".padStart(8, "0"); // "00000abc"
"abc".padStart(1); // "abc"
//padEnd
"abc".padEnd(10); // "abc       "   同padStart,只不过填充到末尾
"abc".padEnd(10, "foo"); // "abcfoofoof"   同padStart,只不过填充到末尾
"abc".padEnd(6, "123456"); // "abc123"       同padStart,只不过填充到末尾
"abc".padEnd(1); // "abc"          同padStart,只不过填充到末尾
//trimStart
"   abc   ".trimStart(); // "abc   "
"   abc   ".trimEnd(); //  "   abc"
"   abc   ".trim(); // "abc"
3、Object.getOwnPropertyDescriptors

获取对象的所有自身属性的描述符。包括 configurable(可配置),enumerable(可枚举),writable(可写)

Object.getOwnPropertyDescriptors({ id: 1, name: 2 });

/*
{
  "id": {
    "value": 1,
    "writable": true,
    "enumerable": true,
    "configurable": true
  },
  "name": {
    "value": 2,
    "writable": true,
    "enumerable": true,
    "configurable": true
  }
}
*/
4、在函数末尾参数后增加逗号

在之前的函数是这样的

function clownPuppiesEverywhere(param1, param2) {}

//或者这样
function clownPuppiesEverywhere(param1, param2) {}

param2 后面如果加逗号会报错,而现在不会报错,它是被允许的

function clownPuppiesEverywhere(param1, param2) {}

//或者这样
function clownPuppiesEverywhere(param1, param2) {}

这样如果我们有新参数,只需要往后加就行了,不必往上一行末尾加逗号(真懒,加个逗号又不费事,鸡肋特性)

5、async / await

将异步变为同步神器。再也不需要像 promise 那样回调了

async function getList(){ //用async指明当前方法中有异步,但是当做同步执行

    await getId();  //如果getId是个promise,则只有状态为resolve时,才进入下一行。如果是普通函数,则默认是resolved


    let result = await getName(); //还可以有返回值。其值为resolved(xx)中的参数

}

await 的并行处理

//因为多个await都是依次往后台发送。如果这几个请求之前没有先后关联顺序,则完全没必要。可以做成并行发送
async getName() {
  let str = "";
  await Promise.all([this.getPromise(),this.getPromise(),this.getPromise()]);
  return str;
}
6、共享内存和原子

太复杂,我也没看懂

如果你想查看,这是详细
文档

三、ES 2018

1、正则表达式 点匹配符 s

在正则表达式中,“.” 点,代表 匹配除换行符之外的任何单个字符。
如下:

/.n/.test('an');   //. 匹配到了a
/.n/.test('1n');   //. 匹配到了1
/.n/.test('nn');   //. 匹配到了n
/.n/.test('\nn');   //.不会匹配 \n 返回false

假如有个需求,需要匹配任何字符。那怎么办.....

有个骚操作。

/foo[^]bar/.test('foo\nbar');  //返回true

用 [^] 替换掉. 它表示匹配包含n 在内的任意字符。

可这也太秀了,正常人都想不到这么写。这么写出来,别人也看不懂。

所以便有了下面的写法:

/foo.bar/s.test('foo\nbar');    //返回true

正则的后面加个 s 标志,你可以将 s 理解为 stop,终止的意思,即表示除了其他的,还能匹配终止符 n,换句话说现在这个. 啥都能匹配到

我们可以总结下,到此为止,正则表达式标志符有:

g      全局搜索。
i      不区分大小写搜索。
m      多行搜索。
s      允许 . 匹配换行符。
u      使用unicode码的模式进行匹配。
y      执行“粘性”搜索,匹配从目标字符串的当前位置开始,可以使用y标志。
2、扩展运算符
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }



let n = { x, y, ...z };
n; // { x: 1, y: 2, a: 3, b: 4 }

或者

let [x,y,...z] = [ 1,2,3,4 ];
x; // 1
y; // 2
z; // [3, 4]



let n = [ x, y, ...z ];
n; // [1, 2, 3, 4]

...x 始终代表这是个展开式,而 x 代表原式(对象,或者数组),

类似于高数中的泰勒展开式, ...x 就是那个展开式,x 就是那个原式。

比如:

function getName({a,b,...others}){
    console.log(others)
}

getName({a:1,b:2,c:3,d:4})

由于...others 是展开式 c:3,d:4,那么 others 自然就是原式{c: 3, d: 4}

3、Promise.prototype.finally

在 promise 结束时,无论结果是 resovled 或者是 rejected,finally 都会执行指定的回调函数。

这避免了同样的语句需要在 then()和 catch()中各写一次的情况。

所以 finally 中最适合需要进行"清空"的操作。比如 request 请求完成或失败后,都要将 loading 设置为 false。或者关闭打开的文件流对象,或者进行日志记录等。

finally()方法和 then()一样,执行后,也返回一个 Promise。

所以一般流程是

new Promise((resolved, rejected)=>{
    //...
    //return  resolved(res); 如果执行成功
    //return  rejected(); 如果执行失败
    //...
}).then(res=>{
    //resolved的回调, res的值为resolved传入的参数
}).catch(err=>{
    //rejected的回调。err为rejected传入的失败的原因
}).finally(()=>{
    //由于不关注resolved还是rejected。所以没有参数。

})
4、for-await-of

我们经常会通过 for....of 进行迭代,如下:

let arr = [1,2,3];
for(let num of arr) {
   console.log(num);
}

输出 1,2,3

我们可以想象下,加入 arr 中的每一项不是普通类型的对象,而是 promise 呢?

//分别创建三个promise对象
let p1 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(1)
    },1000)
});
let p2 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(2)
    },1000)
});
let p3 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(3)
    },1000)
});

let arr = [p1,p2,p3];
for(let num of arr) {
   console.log(num);
}

那执行结果会怎么样呢?

你将会在控制台直接看到下面三个结果。

> Promise {<pending>}
> Promise {<pending>}
> Promise {<pending>}

也就是说 arr 在迭代时,分别将 p1,p2,p3 输出控制台了,而 p1,p2,p3 是谁,当然是 promise 啊,只不过还没执行 resolved 而已,处于 pending 状态。

如果我们想在 arr 迭代时,依次输出 p1,p2,p3 的 resolved 或者 rejected 结果呢?

我们可以使用下面的方式

//分别创建三个promise对象
let p1 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(1)
    },1000)
});
let p2 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(2)
    },1000)
});
let p3 = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
       resolved(3)
    },1000)
});

let arr = [p1,p2,p3];
for await(let num of arr) {
   console.log(num);
}

在 for 后面,左圆括号前面,加个 await。

这样在每次 arr 迭代时,等待 num 的结果为 resolved 或者 rejected 时,才进入 for 的语句块。

结果输出为: 1 2 3

我们可以想想在没有 for-await-of 之前,是怎么用的?

let num = null;
let arr = [p1,p2,p3];

num = await arr[0];
console.log(num);

let num = await arr[1];
console.log(num);

let num = await arr[2];
console.log(num);

是不是?但是如果 arr 中几个这么写还行,可如果多了呢,显然不如 for await of 方便。

四、ES 2019

1、可选的 catch 参数
try {
  throw new Error("出错了")
} catch (err) {
  console.log(err.message);
}

我们通常会在 catch 中通过 err 来获取或者打印错误信息。

但是有些场景下我们不需要 catch 中的 err,信息,只是捕获错误,然后做些其他的事。此时 err 参数被闲置,unused,未被使用。

针对这种情况,es 规范允许你省略 err 参数。

try {
  throw new Error("出错了")
} catch () {
  console.log('321');
}

==Uncaught SyntaxError: Unexpected token ')'==

报错了,纳尼?

注意不是上面这种省略,而应该是下面的省略。

try {
  throw new Error("出错了")
} catch{
  console.log('321');
}

catch 后面直接跟{即可。

坑我给你们填上了,别在掉进去了。

2、json 超集

由于 json 可以支持 "u2028"(行分隔符)和 "u2029"(段落分隔符)两个特殊字符。

我们可以看看这两个字符长什么样
image
方方正正的,一个写着 LSEP,一个写着 PSEP.

创建个 json,包含 u2028.

image

没问题,可以解析。

但是这两个字符之前在 js 中是不能写的。所以 ECMA 在标准中实现了他们,以便在 js 中也能正常使用。

image

3、Symbol.prototype.description

symbol 是一种基本数据类型。 每个从 Symbol()返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。

我们可以通过下面方式获取 symbol 的描述。

Symbol('desc').description    //desc
4、Function.prototype.toString 的修订

以前由于 function 继承了从 object 来的 toString 方法;所以 toString 为"[object Object]"

function getName(){
    return "hello";
};
getName.toString()    // "[object Object]"

而修订后的 function toString 覆盖了从 object 继承来的 toString 方法。返回一个包含定义函数的源文本段。

image

5、Object.fromEntries
let obj = {
  id: 1,
  name: "hello",
};
let entries = Object.entries(obj); //   [["id",1],["name","hello"]]

同样我们可以使用 fromEntries 还原 obj

let obj = Object.fromEntries([
  ["id", 1],
  ["name", "hello"],
]); // {id: 1, name: "hello"}
6、Array.prototype.flat / Array.prototype.flatMap

具体可参考 mdn 链接

flat 文档

flatMap 文档

五、ES 2020

1、String.prototype.matchAll
let regexp = /te/;
let str = 'test1test2';

str.match(regexp)   // ['te']  匹配到第一个位置就停止,并返回匹配到的字符串

加个 g 标志

let regexp = /te/g;
let str = 'test1test2';

str.match(regexp)   //["te", "te"]   返回所有匹配到的字符串

matchAll 会返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。且正则表达式必须含有标志 g,否则报错

let regexp = /te/g;
let str = 'test1test2';

str.matchAll(regexp)   //  RegExpStringIterator{}  但会迭代器。

可以通过解构方式取出迭代器。

let regexp = /te/g;
let str = 'test1test2';

let arr = [...str.matchAll(regexp) ]   //
arr[0]  //  {0: "te", groups: undefined, index: 0, input: "test1test2", length: 1}

arr[1]  //  {0: "te", groups: undefined, index: 5, input: "test1test2", length: 1}

这样我们不仅能获取到 匹配的字符串,还是通过 index 知道匹配的位置。

2、import()

在 js 中,引入模块的方式通常是:

import _ from "lodash"

在代码运行之前,在编译阶段,就已经绑定引入本地作用域。

但是如果我们想在运行阶段动态的引入呢?

答案是没有办法。

如果你使用的是 webpack,则可以使用 webpack 的 require("xxx") 动态的将模块引入。

所以 ECMA 直接在 js 核心库中,实现了这个 api。即使不适用 webpack,也能直接在浏览器上运行 import().

在 chrome 控制台我们可以直接使用。

image

同时发现,import()返回的是个 promise 对象,

所以我们可以这么用

import("/static/js/app.js").then(res=>{
    //xxx
})

或者
await import("/static/js/app.js");
//后续代码
3、BigInt

在 javascript 中,interget 的最大数为 2^53

Math.pow(2,53)  // 9007199254740992

如果加 1,发现没变。

Math.pow(2,53)+1  // 9007199254740992

假如要表示 比 Math.pow(2,53) 还要大的数值怎么办?

可以使用 BigInt 类型来表示

const theBiggestInt = 9007199254740991n;   //后面追加 n,表示这是个bigInt类型

const alsoHuge = BigInt(9007199254740991);  //直接通过构造器创建。

在 bigInt 中,最小的 1,用 1n 来表示,如下面的运算

1n+1n==2n
2n-1n == 1n
2n * 2n == 4n
4n / 2n == 2n

9007199254740992n +1n==9007199254740993n   //  //2^53加1  结果为

特殊情况

1n+1n==2  //true
0n == 0   //true

//但是下面为false
1n+1n==2    //false
0n === 0    //false

特别的

1n+1    会直接报错

Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
3、Promise.allSettled

在 promise 中的组合器有下面几种:

  • Promise.all 参数中的所有 promise 完成,才执行回调。
  • Promise.race 只要有一个完成,或者一个失败,就马上执行回调。
  • Promise.all 只要有个完成,或者所有的失败,才执行回调。
  • Promise.allSettled 永远不会中途结束,会全部完成,返回所有给定的 promise 已被完成或失败后的数组。
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, "1oo");
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 1000, "foo");
});
const promises = [promise1, promise2];

Promise.allSettled(promises).then((results) => {
  //results  [{"status":"fulfilled","value":"1oo"},{"status":"rejected","reason":"foo"}]
});
3、globalThis

在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。在 Web 中,可以通过 window、self 或者 frames 取到全局对象,但是在 Web Workers 中,只有 self 可以。在 Node.js 中,它们都无法获取,必须使用 global。

globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)

这样在浏览器中, globalThis 就是 window 或者 self,
在 Web Workers 中, globalThis 就是 self,
在 nodejs 中,globalThis 就是 global。

快去把你项目中的 window,self,global 等替换成 globalThis 吧

4、for-in

for...in 语句以任意顺序遍历一个对象的除 Symbol 以外的可枚举属性。

在对象中使用 for....in 并没有什么问题

for(let item in {id:1,name:'123'}){
   console.log(item)  //依次输出 id, name
}

不建议 for....in 和数组搭配一起使用。为什么呢,请看下面的例子:

for(let item in ['a','b','c']){
   console.log("-===",item) //依次输出 '0' '1' '2',

   //注意  '0' '1' '2'并非下标,而是枚举位置
}

我们再给数组添对象添加个可枚举属性

let arr = [1,2,3];
Object.defineProperty(arr, "getName", {
    value: "hello",
    enumerable: true
});

//等同于

let arr = [1,2,3];
Array.prototype.getName = "hello";


//紧接着我们执行下面
for(let item in arr){
   console.log(item)  //依次输出 '0' '1'  '2'  'getName'
}

发现没?? 是不出错了,如果我们项目中,在 util 的模块中,给 Array.prototype 上增加了一些 polyfill,那么我们使用 for....in 遍历数组,就必然出错。

当然我们可以通过其他方式避免。
比如

for(let i=0;i<arr.length;i++){
    //
}

//或者
arr.forEach((value,index)=>{
  //
})
5、可选链操作符 '?.'

在以前我们进行条件判断时:

let obj = { "circle": { "x": 0, "y": 0 }, "radius": 50 };

if(obj && obj.circle && obj.circle.x){

    //然后才敢拿着  obj.circle.x 进行操作。否则假如obj为null,obj.circle 就会直接报错。

}

而现在不用这么麻烦

let obj = { "radius": 50 };

if(obj?.circle?.x){
    // obj.circle.x 进行操作
}

?.表示是否有这个属性,如果没有(undifined),或者有,但值为 null。则直接短路不会再继续向下。从而保护了代码不被出错。

let obj = { "circle": { "y": 0 }, "radius": 50 };

if(obj?.circle?.x){

}else{
    //不会报错。在执行到 ?.circle时得到undefiend,直接短路。返回undefiend, 进入 else
}

同样,数组也可以

let arr = ['a','b'];
arr?.[1]  //  'b'

最后注意,可选链不能用于赋值操作

let arr = ['a','b'];
arr?.[1]  = 'c'  //报错   Uncaught SyntaxError: Invalid left-hand side in assignment
6、空值合并操作符 '??'

它是个逻辑操作符,类似于 ||

|| 操作符,只有当左侧为假值(0, '', NaN, false, null,undefined)是才返回右侧的值.

0 || 'A' //A
'' || 'A' //A
NaN || 'A' //A
false || 'A' //A
null || 'A' //A
undefined || 'A' //A

而 ??只有左侧为空值(只有 null 和 undefined)时才

0 ?? 'A';     // 0
'' ?? 'A'      // ''
NaN ?? 'A'     //NaN
false ?? 'A'    //false
null ?? 'A'     //A
undefined ?? 'A' //A
6、import.meta

具体查看
文档

参考 ECMA 规范:
https://github.com/tc39/proposals/blob/master/finished-proposals.md

查看原文

赞 0 收藏 0 评论 0

寒水寺一禅 收藏了文章 · 5月27日

12个优秀GUI Git客户端,程序员必备!

尽管许多用户可以从命令行轻松地使用Git,但有多种GUI客户端可以大大加快你的工作流程,尤其是在你不熟悉平台的情况下。

如果你正在寻找理想的客户端来管理你的Mac上的仓库,本文列出了适用于Mac OS X或Windows系统的最佳GUI Git客户端。

1. GitHub Desktop

https://desktop.github.com/

GitHub Desktop是由GitHub开发的完全免费且开源的可自定义的基于Electron的Git客户端应用程序,它允许你与GitHub和其他Git平台(包括Bitbucket和GitLab)进行交互。

它的特点包括漂亮的分区方法,可以轻松地检查带有pull请求的分支,你可以检查图片和代码区块之间的差异,甚至可以使用拖拽的方式从应用程序中添加项目进行管理。

2.Fork

https://git-fork.com/

Fork是Mac和Windows的免费高级GUI git客户端,专注于速度,用户友好性和效率。它的功能包括带有快速操作按钮的主题布局,内置的合并冲突帮助器和解析器,仓库管理器,GitHub通知等。

在免费的Git客户端中,我喜欢Fork的大部分功能。我知道的功能包括漂亮UI中的交互式rebase、Git流、Git LFS、精选、恢复、子模块等。

3. Tower

https://www.git-tower.com/

Tower是适用于macOS和Windows的付费GUI Git客户端。目前,它是专业git工具中领先的客户端应用程序之一。它使你能够以可视化的方式执行所有的Git操作,让你对版本控制有了更多的了解。它包括合并冲突排序和项目协作。

您可以免费享受30天的免费试用期,然后分别为Basic或Pro订阅支付每位用户69美元或每位用户99美元。

4. Sourcetree

https://www.sourcetreeapp.com/

Sourcetree是适用于macOS和Windows的免费GUI Git客户端。它简化了版本控制过程,让你可以专注于重要的事情——编码。

它拥有专业的UI,可以通过直接访问Git流、子模块、远程repo管理器、本地提交搜索、支持Git大文件等可视化管理版本库,来执行Git任务和访问Git流。

Sourcetree由Atlassian为Bitbucket开发,但不限于此。它可以与其他Git平台结合使用,并具有对Mercurial存储库的内置支持。

5. SmartGit

https://www.syntevo.com/smart...

SmartGit是适用于Mac,Linux和Windows的功能丰富的Git客户端,支持SVN,GitHub和Bitbucket的Pull Request。它的功能包括用于Git的CLI,图形合并和提交历史记录,SSH客户端,Git-Flow,文件合并,冲突解决程序等。

SmartGit可以免费用于非商业项目。许可证的费用从每年99美元到终身费用229美元不等。根据你选择的支持期限,费用可能会有所不同。

6. Sublime Merge

https://www.sublimemerge.com/

Sublime Merge是一款适用于Mac、Windows和Linux的Git客户端,由同一开发者继流行的Sublime Text源代码编辑器之后创建。

它包含了Sublime Text用户满意的所有品质,包括快速的性能、集成的合并工具、强大的搜索工具、高级差异检查器等。它是免费的,但是像Sublime Text一样,你需要支付99美元的扩展许可。

7. GitKraken

https://www.gitkraken.com/

GitKraken是一个免费的跨平台GUI Git客户端,可用于版本控制系统(包括GitHub,Bitbucket,GitLab等)。它旨在通过为你提供直观的UI,任务跟踪,内置代码编辑器,合并冲突编辑器以及对与其他平台集成的支持,使你成为富有生产力的Git用户。

出于商业目的和Pro版本中包含的其他特性(如合并冲突编辑器、多个配置文件和自托管存储库),GitKraken的成本为每月4.08美元,而企业版本的成本更高。

8. GitUp

https://gitup.co/

GitUp是面向Mac用户的免费开源Git客户端,重点在于速度,简单性,效率和易用性。它绕过Git二进制工具并直接与仓库数据库进行交互,这使其比其他Git客户端快得多。例如,它在一秒钟内加载并呈现40,000个GitUp仓库提交的内容。

GitUp具有所有Git功能的GUI替代方案,并且可以直观地实现输入命令和实时更改。

9. Ungit

https://github.com/FredrikNor...

尽管市场上有许多不同版本的GUI,但是开发人员可能会寻找一种非常简单的使用git的方法。是的,如果你很难选择哪种GUI更好,Ungit将解决你的选择问题。

Ungit在不牺牲git多功能性的情况下为git带来了用户友好性,并且它在所有平台上均可运行。

10. Aurees Git customers

https://aurees.com/

Aurees Git Client是Mac,Windows和Linux上面向Git用户的免费应用程序,旨在为你提供一个简单而强大的应用程序来使用GUI管理所有Git项目,从而加快工作流程。

它为你提供了直观操作Git仓库的便利。这些功能包括出色的合并与预览、冲突解决、内置编辑器的差异检查、直观的高亮显示等。

11. GitaHead

https://gitahead.github.io/gi...

GitAhead是适用于所有不同操作系统的图形化Git客户端。它具有快速的原生界面,旨在帮助你了解和管理源代码历史记录。

GitAhead由Understand™的制造商SciTools™设计。它具有吗希望从商业质量的客户获得的所有功能,现在完全免费和开源。

12. GitBlade

https://gitblade.com/

GitBlade是一款Mac、Windows、Linux平台上的精美的Git客户端。它为用户提供了操作Git项目所需的日常功能,包括合并工具、显示链接分支和提交的可视化图形,以及联合差异检查来查看多个添加文件之间的差异,这是一个可视化文件历史记录的责任/注释工具。

GitBlade可以免费使用所有基本的Git功能14天专业版功能。专业版的价格为每用户每年19.99美元,它包含了最多可以在3台电脑上使用的许可,存储库标签、非常规工具、合并工具等。

尽管所有这些应用程序都为Git项目提供了类似的功能,但它们具有独特的功能,使其在其他领域脱颖而出。

查看原文

寒水寺一禅 赞了文章 · 5月27日

12个优秀GUI Git客户端,程序员必备!

尽管许多用户可以从命令行轻松地使用Git,但有多种GUI客户端可以大大加快你的工作流程,尤其是在你不熟悉平台的情况下。

如果你正在寻找理想的客户端来管理你的Mac上的仓库,本文列出了适用于Mac OS X或Windows系统的最佳GUI Git客户端。

1. GitHub Desktop

https://desktop.github.com/

GitHub Desktop是由GitHub开发的完全免费且开源的可自定义的基于Electron的Git客户端应用程序,它允许你与GitHub和其他Git平台(包括Bitbucket和GitLab)进行交互。

它的特点包括漂亮的分区方法,可以轻松地检查带有pull请求的分支,你可以检查图片和代码区块之间的差异,甚至可以使用拖拽的方式从应用程序中添加项目进行管理。

2.Fork

https://git-fork.com/

Fork是Mac和Windows的免费高级GUI git客户端,专注于速度,用户友好性和效率。它的功能包括带有快速操作按钮的主题布局,内置的合并冲突帮助器和解析器,仓库管理器,GitHub通知等。

在免费的Git客户端中,我喜欢Fork的大部分功能。我知道的功能包括漂亮UI中的交互式rebase、Git流、Git LFS、精选、恢复、子模块等。

3. Tower

https://www.git-tower.com/

Tower是适用于macOS和Windows的付费GUI Git客户端。目前,它是专业git工具中领先的客户端应用程序之一。它使你能够以可视化的方式执行所有的Git操作,让你对版本控制有了更多的了解。它包括合并冲突排序和项目协作。

您可以免费享受30天的免费试用期,然后分别为Basic或Pro订阅支付每位用户69美元或每位用户99美元。

4. Sourcetree

https://www.sourcetreeapp.com/

Sourcetree是适用于macOS和Windows的免费GUI Git客户端。它简化了版本控制过程,让你可以专注于重要的事情——编码。

它拥有专业的UI,可以通过直接访问Git流、子模块、远程repo管理器、本地提交搜索、支持Git大文件等可视化管理版本库,来执行Git任务和访问Git流。

Sourcetree由Atlassian为Bitbucket开发,但不限于此。它可以与其他Git平台结合使用,并具有对Mercurial存储库的内置支持。

5. SmartGit

https://www.syntevo.com/smart...

SmartGit是适用于Mac,Linux和Windows的功能丰富的Git客户端,支持SVN,GitHub和Bitbucket的Pull Request。它的功能包括用于Git的CLI,图形合并和提交历史记录,SSH客户端,Git-Flow,文件合并,冲突解决程序等。

SmartGit可以免费用于非商业项目。许可证的费用从每年99美元到终身费用229美元不等。根据你选择的支持期限,费用可能会有所不同。

6. Sublime Merge

https://www.sublimemerge.com/

Sublime Merge是一款适用于Mac、Windows和Linux的Git客户端,由同一开发者继流行的Sublime Text源代码编辑器之后创建。

它包含了Sublime Text用户满意的所有品质,包括快速的性能、集成的合并工具、强大的搜索工具、高级差异检查器等。它是免费的,但是像Sublime Text一样,你需要支付99美元的扩展许可。

7. GitKraken

https://www.gitkraken.com/

GitKraken是一个免费的跨平台GUI Git客户端,可用于版本控制系统(包括GitHub,Bitbucket,GitLab等)。它旨在通过为你提供直观的UI,任务跟踪,内置代码编辑器,合并冲突编辑器以及对与其他平台集成的支持,使你成为富有生产力的Git用户。

出于商业目的和Pro版本中包含的其他特性(如合并冲突编辑器、多个配置文件和自托管存储库),GitKraken的成本为每月4.08美元,而企业版本的成本更高。

8. GitUp

https://gitup.co/

GitUp是面向Mac用户的免费开源Git客户端,重点在于速度,简单性,效率和易用性。它绕过Git二进制工具并直接与仓库数据库进行交互,这使其比其他Git客户端快得多。例如,它在一秒钟内加载并呈现40,000个GitUp仓库提交的内容。

GitUp具有所有Git功能的GUI替代方案,并且可以直观地实现输入命令和实时更改。

9. Ungit

https://github.com/FredrikNor...

尽管市场上有许多不同版本的GUI,但是开发人员可能会寻找一种非常简单的使用git的方法。是的,如果你很难选择哪种GUI更好,Ungit将解决你的选择问题。

Ungit在不牺牲git多功能性的情况下为git带来了用户友好性,并且它在所有平台上均可运行。

10. Aurees Git customers

https://aurees.com/

Aurees Git Client是Mac,Windows和Linux上面向Git用户的免费应用程序,旨在为你提供一个简单而强大的应用程序来使用GUI管理所有Git项目,从而加快工作流程。

它为你提供了直观操作Git仓库的便利。这些功能包括出色的合并与预览、冲突解决、内置编辑器的差异检查、直观的高亮显示等。

11. GitaHead

https://gitahead.github.io/gi...

GitAhead是适用于所有不同操作系统的图形化Git客户端。它具有快速的原生界面,旨在帮助你了解和管理源代码历史记录。

GitAhead由Understand™的制造商SciTools™设计。它具有吗希望从商业质量的客户获得的所有功能,现在完全免费和开源。

12. GitBlade

https://gitblade.com/

GitBlade是一款Mac、Windows、Linux平台上的精美的Git客户端。它为用户提供了操作Git项目所需的日常功能,包括合并工具、显示链接分支和提交的可视化图形,以及联合差异检查来查看多个添加文件之间的差异,这是一个可视化文件历史记录的责任/注释工具。

GitBlade可以免费使用所有基本的Git功能14天专业版功能。专业版的价格为每用户每年19.99美元,它包含了最多可以在3台电脑上使用的许可,存储库标签、非常规工具、合并工具等。

尽管所有这些应用程序都为Git项目提供了类似的功能,但它们具有独特的功能,使其在其他领域脱颖而出。

查看原文

赞 13 收藏 8 评论 1

寒水寺一禅 回答了问题 · 4月29日

解决vue transition 只有一半的效果

你好,我已经解决,亲测有效。
只需要讲 .v-leave-to,.v-leave设置如下即可:

.v-leave-to,.v-leave {
  position: absolute;
  z-index:-10;
}

如果仅仅设置.v-leave-to,那么在过渡时,不会出现半边,但是过渡之初,会闪一瞬间,也可以看到半边,所以再加上.v-leave

关注 3 回答 2

寒水寺一禅 回答了问题 · 3月29日

解决Echarts是如何实现饼图自动提示的

建议看echart文档吧,一看你就没看过。文档中有个属性toolip,在toolip中有个formatter方法,可以自定义你在鼠标浮上去时,所现在的内容

关注 4 回答 3

寒水寺一禅 回答了问题 · 3月29日

vuex中state改变但是没有进行渲染

只要shopper的引用不变,它就不会渲染,而mapGetter我猜它应该是进行了深度监听,除了引用,也监听属性值,这个要去看mapgetter源码

关注 2 回答 1

寒水寺一禅 报名了系列讲座 · 3月9日

如何快速开发一款小程序

【课程说明】 微信小程序自 2017 年上线以来,小程序的数量和小程序的开发者持续增长,它以一种极度轻量化、无处不在、用完即走的方式全面连接人与服务,在给用户带来更好的体验的同时,大幅降低开发门槛和成本。 本期 Open Talk ,又拍云邀请无码科技、有赞、大搜车、二维火等知名企业的微信小程序开发者,为广大开发者带来一场了解小程序开发生态、学习小程序开发经验、探索小程序的更多应用可能的技术分享。 Open Talk 是由又拍云发起的系列主题分享沙龙,秉承又拍云帮助企业提升发展速度的初衷,从 2015 年开启以来,Open Talk 至今已成功举办 50 余期,辐射线上线下近十万技术人群,分别在北京、上海、广州、深圳、杭州、武汉等 12 座城市举办,覆盖腾讯、华为、网易、京东、唯品会、斗鱼、哔哩哔哩、美团点评等诸多知名企业。不管是从某个“主题”出发横向拓展技术干货分享,还是以某个“品牌企业”为主纵深丰富演讲内容,活动都场场爆满。 【课程福利】 又拍云推出开发者帮助计划,为开发者提供专业、免费、稳定的 CDN 及云存储服务,加速个人网站及 APP 等项目。即日起加入又拍云联盟,每月独享 10GB 免费存储空间和 15GB 免费 CDN 流量,更多详情请前往又拍云官网查询。

寒水寺一禅 发布了文章 · 1月14日

vue中style scope深度访问新方式(::v-deep)

1、>>>

如果vue的style使用的是css,那么则

<style lang="css" scoped>
.a >>> .b { 
   /* ... */ 
}
</style>

但是像scss等预处理器却无法解析>>>,所以我们使用下面的方式.

2、/deep/

<style lang="scss" scoped>
.a{
   /deep/ .b { 
      /* ... */ 
   }
} 
</style>

但是有些开发者反应,在vue-cli3编译时,deep的方式会报错或者警告。
此时我们可以使用第三种方式

3、::v-deep

切记必须是双冒号

<style lang="scss" scoped>
.a{
   ::v-deep .b { 
      /* ... */ 
   }
} 
</style>

下面贴上node_modules中的一段解析scope的源码
image.png

参见下面的链接
https://github.com/vuejs/component-compiler-utils/commit/8b2c646
https://vue-loader.vuejs.org/guide/scoped-css.html

查看原文

赞 5 收藏 3 评论 9