寒水寺一禅

寒水寺一禅 查看完整档案

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

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

个人动态

寒水寺一禅 发布了文章 · 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 评论 2

寒水寺一禅 收藏了文章 · 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。

查看原文

赞 55 收藏 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

认证与成就

  • 获得 498 次点赞
  • 获得 21 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 18 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2017-05-03
个人主页被 996 人浏览