localhost与127.0.0.1的区别:
localhost:也叫local ,正确的解释是:本地服务器 127.0.0.1:在windows等系统的正确解释是:本机地址(本机服务器)
localhost:是不经网卡传输的,它不受网络防火墙和网卡相关的的限制。 127.0.0.1:是通过网卡传输的,它依赖网卡,并受到网络防火墙和网卡相关的限制。
JS复制文字到剪切板
execCommand方法
复制一段文字内容实现的方法是 document.execCommand
,兼容性好,但是执行有限制,有性能隐患。需要文字选中才有效,通常做法是创建一个隐藏的输入框,赋值,选中,然后复制。虽然已经被弃用但目前仍可以生效。
// 创建输入框
const textarea = document.createElement('textarea');
document.body.appendChild(textarea);
// 隐藏此输入框
textarea.style.position = 'absolute';
textarea.style.clip = 'rect(0 0 0 0)';
// 赋值
textarea.value = '复制的文本内容...';
// 选中
textarea.select();
// 复制
document.execCommand('copy', true);
Clipboard API
无需浏览器权限申请,文字内容直接进入剪切板,代码简单,使用方便简单,同时是异步,不用担心阻塞。然而,兼容性不足有点遗憾。
if (navigator.clipboard) {
navigator.clipboard.writeText(text);
}
使用 Git Bisect 快速找到第一個有問題的 Commit
开始搜寻并标记好与坏的 Commit
git bisect start <坏的 Commit> <好的 Commit>
开始后将自动 Checkout 到要检查的 Commit。
请执行以下指令标记正常或错误
git bisect good
git bisect bad
看到以下文字,代表找到第一个有问题的 Commit。
0675162a1b00bf8d2cdd535d4fc80e3a31196a8e is the first bad commit
css3 性能优化之 will-change 属性
will-change:
顾名思义“我要变形了“,它的作用是“提高浏览器的页面渲染性能”
属性:
auto:默认值,实行标准浏览器优化。
scroll-position:表示开发者希望在不久后改变滚动条的位置或者使之产生动画。
contents:表示开发者希望在不久后改变元素内容中的某些东西,或者使它们产生动画。
<custom-ident>
:表示开发者希望在不久后改变指定的属性名或者使之产生动画,比如transform 或 opacity
例子
下面告诉浏览器期望元素的变换属性发生变化,以便提前进行适当的优化。
.el {
will-change: transform;
}
target="_blank"隐患
应用场景
通常使用于注重相关用户体验,在用户点击一个链接的时候在新窗口中打开。
<a href="https://www.baidu.com/" target="_blank">baidu</a>
安全隐患
使用该属性来打开新标签或者新窗口时,站点会通过window.opener API给了新页面对原有窗口的访问入口,并授予一些权限,其中window.location是没有被跨域限制拦截的。这可能就存在一个钓鱼的安全隐患。
解决方法
尽量不使用 target="_blank"
,如果一定要用,需要加上 rel="noopener"
或者 rel="noreferrer"
。这样新窗口的 window.openner
就是 null
了,而且会让新窗口运行在独立的进程里,不会拖累原来页面的进程。
<a href="https://www.baidu.com/" target="_blank" rel="noopener">baidu</a>
或者使用以下可能触发弹出窗口阻止程序的 JavaScript 解决方法:
var otherWindow = window.open();
otherWindow.opener = null;
otherWindow.location = url;
有些浏览器对性能做了优化,即使不加这个属性,新窗口也会在独立进程打开。
https://mathiasbynens.github.io/rel-noopener/
专注于开发代码的语言学习模型,比肩chatpt,服务开发人员的瑞士军刀。
What does Bito’s AI Assistant help with? Ask any technical question
- Generate Code: Examples: “code in java to convert a number from one base to another”, “code to implement a simple REST API in GO”
- Command Syntax: “how to set git config variables”, “create an encrypted s3 bucket using the AWS cli”
- Test Cases: “Generate test cases for this code < insert your code here >"
- Explain code: “explain this code < insert your code here >”
- Comment Method: “Explain this code and explain the parameters < insert your code here >”
- Improve Performance: “how can I improve performance of this code? < insert your code here >”
- Check Security: “Is this code secure? < insert your code here > ”
- Explain concepts : "explain B+ trees, give an example with code", “explain banker’s algorithm”
( 可惜只有英文版
https://chrome.google.com/webstore/detail/bito-ai-assistant/afchmofckbnlkpnjkdikdkgnjelhlbkg/related?hl=en
Motion轻松成为前端动画师
https://chrome.google.com/webstore/detail/motion-devtools/mnbliiaiiflhmnndmoidhddombbmgcdk
CSS attr() 函数
CSS 表达式 attr()
用来获取DOM某一属性值,并用于其样式中。
语法:attr( attribute-name )
示例:
浏览器支持:
chrome 106版本之后,支持对某个容器的媒体查询:
.a {
container-type: inline-size;
}
.b {
color: yellow;
}
@container (min-width: 400px) {
.b {
color: blue;
}
}
git worktree
git worktree 可以为同一项目创建多个工作目录,方便分支对比、修bug和插单需求介入,不需要 stash 暂存改动。
常见场景:
git worktree
开启新的bugfix 工作目录,当 commit 后自动回到业务迭代。除了通过eval函数还有另一种方式可以将字符串当初js代码运行
new Function('data',
'return data')(data) `
签名第一个是传参,后面的字符串是代码
https://vitejs.dev/blog/announcing-vite4.html
前端缓存
「http缓存流程图👇🏻」
http缓存又分为两种两种缓存,强制缓存 和 协商缓存
强制缓存:浏览器判断请求的目标资源有效命中强缓存,如果命中,则可以直接从内存中读取目标资源,无需与服务器做任何通讯。
基于 Cache-control
的强制缓存:在资源的响应头上写上需要缓存的时间即可,单位是秒,如下:
协商缓存:通过服务器来判断缓存是否可用
Last-Modified:表示这个响应资源的最后修改时间,web服务器在响应请求时,告诉浏览器资源的最后修改时间
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识。
If-None-Match:需要配合Cache-Control使用,当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304
判断字符是否为emoji表情的方法
1.UTF-8 字节流
UTF-8 的编码中,英文是1个字节,中文是3个字节,emoji一般是4个字节。
TextEncoder 接受码位流作为输入,并提供 UTF-8 字节流作为输出。
TextEncoder.encode()接受一个字符串作为输入,返回一个包含 UTF-8 编码的文本的 Uint8Array。
const textEncoder = new
TextEncoder()textEncoder.encode('🤔').length //4
2.emoji-regex导入
emoji-regex提供了一个正则表达式来匹配所有表情符号和序列(包括表情符号的文本表示)符合 Unicode 标准,基于emoji-test-regex-pattern。
获取完整的首字母字符
使用slice(0,1)无法完整切割emoji表情,使用Array.from()将其转换为数组则可以获取完成emoji表情
const str = '🤔1哦哦'
str.slice(0,1) //'\uD83E'
str.slice(0,2) //'🤔'
const arr = Array.from(str) //['🤔', '1', '哦', '哦']
textEncoder.encode(arr[0]).length //4
监听元素大小、位置变化的方法
1.ResizeObserver,可以监听Element或SVG边界尺寸的变化
const resizeOb = new ResizeObserver(entries => {
for (const entry of entries){
console.log(entry?.target?.clientWidth)
}
})
resizeOb.observe(document.getElementById('test'))
实例化一个监听器,调用observe方法传入一个要执行监听的DOM元素或SVG元素,每次resizes事件触发时都会执行实例化时传入的回调函数。回调函数第一个参数是被监听元素数组,数组内元素按被监听的顺序排列。
2.MutationObserver,监听范围更广,会将DOM变化记录为一个MutationRecord对象
🌲下一代CSS
<svg viewBox>
属性,在元素的内容上进行缩放或平移喜闻乐见之Node18亲自操刀
https://nodejs.org/en/blog/release/v18.11.0/
okki-galio-cli 快速生成galio项目子应用
https://www.npmjs.com/package/okki-galio-cli
安装
npm install -g okki-galio-cli
or
yarn global add okki-galio-cli
命令
galio --version
galio --help
galio init <project-name>
webpack5 资源模块
webpack5新增了资源模块(asset module),允许使用资源文件(字体,图标等)而无需配置额外 loader。资源模块定义了四种类型,用以代替之前的 file-loader
,url-loader
和 raw-loader
。
asset/resource
代替 file-loader
实现。asset/inline
代替 url-loader
实现。asset/source
代替 raw-loader
实现。asset
在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader
,并且配置资源体积限制实现。原先 loader 中的选项配置可以使用资源模块相应的配置项代替
// before
{
test: /\.url\.(png|jpe?g|gif|webp)(\?.*)?$/,
use: [
/* config.module.rule('images').use('url-loader') */
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'static/img/[name].[contenthash:8].[ext]',
publicPath: 'https://cfile.xiaoman.cn/${CDN_ENV}/'
}
}
}
}
]
}
// after
{
test: /\.url\.(png|jpe?g|gif|webp)(\?.*)?$/,
type: 'asset',
generator: {
filename: 'static/img/[name].[hash:8][ext]'
publicPath: 'https://cfile.xiaoman.cn/${CDN_ENV}/'
},
parser: {
dataUrlCondition: {
maxSize: 4096
}
}
}
CSS clamp()
函数
clamp()
函数的作用是把一个值限制在上限和下限之间
基本语法:clamp(MIN, VAL, MAX)
该函数接收三个用逗号分隔的表达式作为参数,按最小值、首选值、最大值排列;当首选值比最小值要小时,则使用最小值,当首选值比最大值要大时,则使用最大值,首选值介于二者之间时,则使用首选值
有时候,页面的某个区域高度需要根据视口的大小而变化,但是在较大视口上高度不能过高,在较小视口上高度不能过低,这种场景下,使用 clamp()
函数是很好的选择
举个简单的例子:
width: 100%;
height: clamp(250px, 50vw, 400px)
OkkiTable
组件 空数据时,自定义empty方式
<OkkiConfigProvider>
<template
renderEmpty>
<img src=""/>
<OkkiButton type="primary">
重新加载
</OkkiButton>
</template>
<OkkiTable>
// ...
</OkkiTable>
</OkkiConfigProvider>
TS内置类型Partial
,用于把一个类型的成员属性设为可选模式,其源码定义如下
type Partial<T> = {
[P in keyof T]?: T[P]
}
当使用一个空对象准备接收上传的文件时,会报如下错误
可以选择使用内置的Partial
类型解决这个问题
不过Partial无法将更深层的成员属性变为可选模式,可以自定义一个DeepPartial实现深度Partial
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Object ? DeepPartial<T[P]> : T[P]
}
npm包 patch-package
让开发者可以立即对 npm 依赖项进行修复,而不用通过升级npm 版本或clone npm包等其他操作处理。
操作步骤:
1.安装 patch-package
npm install patch-package --save-dev
2.package.json新增
scripts: {
"postinstall": "patch-package"
}
3.手动修改 node_modules 依赖包中的源码
4.创建补丁文件
npx patch-package package-name
Object.fromEntries() 方法接收一个键值对的列表参数,并返回一个带有这些键值对的新对象。这个迭代参数应该是一个能够实现@iterator方法的的对象,返回一个迭代器对象。它生成一个具有两个元素的类数组的对象,第一个元素是将用作属性键的值,第二个元素是与该属性键关联的值。
常用场景:将数组对象转化为Object,比如以下,将person转化为以name属性值为key,数组对象为value的Object
浏览器打开新标签安全问题
如果在项目中需要 打开新标签 进行跳转一般会有两种方式:
window.open
<a href="..." target="_blank">new tab</a>
这两种方式看起来没什么问题,但是存在漏洞
通过这两种方式打开的页面可以使用 window.opener 来访问源页面的 window 对象,场景:
在自己的系统内通过 <a target="_blank"
标签或 window.open
打开第三方网站,第三方网站可以通过 window.opener.location.replace("https://test.evil.com")
(跨域仍然有效)将原来的页面替换成钓鱼网站。
如何防止?
劫持window.open:
const openPage = (url) => {
var newTab = window.open()
newTab.opener = null
newTab.location = url
}
<!--
noopener:将 window.opener置空
noreferrer:兼容老浏览器/火狐。禁用HTTP头部Referer属性(后端方式)
-->
<a target="_blank" href="" rel="noopener noreferrer nofollow">a标签跳转url</a>
proposal-extractors
proposal-extractors 是一个关于解构能力增强的提案,支持在直接解构时执行自定义逻辑。
当我们需要对结构的数据进行赋值时加工,就会退化成非解构版本
const [first: firstTemp, second: secondTemp] = arr
const {name: nameTemp, age: ageTemp} = obj
const first = someLogic(firstTemp)
const second = someLogic(secondTemp)
const name = someLogic(nameTemp)
const age = someLogic(ageTemp)
proposal-extractors 提案就是用来解决这个问题,希望保持解构语法优雅的同时,加一些额外逻辑:
const SomeLogic(first, second) = arr // 解构数组
const SomeLogic{name, age} = obj // 解构对象
SomeLogic 定义:
const SomeLogic = {
[Symbol.matcher]: (value) => {
return { matched: true, value: value.toString() + "特殊处理" };
},
};
一图看懂 Typescript 4.9bate 新操作符 satisfies
OKKI UI upload 组件踩坑记录
因为OKKI UI是基于 ant design vue 二次封装的,所以OkkiUploader会有与之相同的问题,即使用 FileReader 的readAsBinaryString()、erAsDataUrl()等方法会报错
报错信息如下:readFailed to execute 'readAsBinaryString' on 'FileReader': parameter 1 is not of type 'Blob'.
解决方法:使用组件返回的file对象中的originFileObj,因为ant design在上传的原始file对象外面包裹了一层,originFileObj 是原始的文件对象,FileReader可读取其内容
Via
是一个通用首部,是由代理服务器添加的,适用于正向和反向代理,在请求和响应首部中均可出现。这个消息首部可以用来追踪消息转发情况,常用于查看CDN资源经过了哪些节点,例如:
TC39新提案:Array.fromAsync
作用与 Array.from 类似,Array.fromAsync 可以将异步迭代转换为 promise,并将解析为新数组。在 promise 解析之前,它将从输入值中创建一个异步迭代器,进行惰性的迭代,并将每个产生的值添加到新数组中。
与其他基于 Promise 的 API 一样,Array.fromAsync 总是会立即返回一个 promise。当 Array.fromAsync 的输入在创建其异步或同步迭代器时引发错误时,则此 promise 状态将被置为 rejected。
示例:
async function * asyncGen (n) {
for (let i = 0; i < n; i++)
yield i * 2;
}
// arr 将变为 [0, 2, 4, 6]
const arr = [];
for await (const v of asyncGen(4)) {
arr.push(v);
}
// 与上述方式等价
const arr = await Array.fromAsync(asyncGen(4))
for...in 和 for...of 的区别
零宽字符
零宽字符是一系列不显示内容也不占用宽度的不可打印的字符
如 零宽空格(zero-width space, ZWSP)Unicode: \u200B Urlencode: %E2%80%8B
若前端发送的请求参数重包含了零宽空格,虽然看起来一切正常,后端会因为数据库中无法查询到数据导致无法返回预期的结果
当事件捕获和事件冒泡一起存在的情况,事件又是如何触发呢。 这里记被点击的DOM节点为target节点
JavaScript 的 undefined
是一个变量,并非是一个关键字,这是 JavaScript 语言的设计失误。在开发中为了避免被无意篡改,建议使用 void 0
来获取 undefined
值
vscode server——拯救你的散热器
巨硬在 2019年发布了 Visual Studio Code Remote Development 远程开发插件,能在 vscode 像编辑本地文件一样去编辑远程机器上的代码,并且能将远程机器的终端命令行和监听端口映射到本地。让散热器的寿命 +1s。
之后巨硬更进一步,发布了 vscode server,支持在远程机器上私有化部署一个 vscode 的 web 服务。得益于 vscode 本身良好的跨平台支持,能让开发者在浏览器里访问自己部署的 vscode 编辑器。
让开发者随时随地有一个浏览器就可以写代码,能腾出更多时间来喝酒打屁,这波利好茅台。
MouseEvent metaKey 属性
在MAC键盘上,表示 Command 键(⌘),在Windows键盘上,表示 Windows 键(⊞)
AbortController 是一个用于终止行为的控制器(实验性功能)。
function fetchVideo() {
controller = new AbortController() // 新建一个 controller
const signal = controller.signal
fetch(url, { signal }) // 在 fetch 方法传入 signal
.then(function (response) {
console.log('Download complete', response)
})
.catch(function (e) {
console.log('Download error: ' + e.message)
})
}
abortBtn.addEventListener('click', function () {
if (controller) controller.abort() // 调用 controller.abort 取消 fetch
console.log('Download aborted')
})
const controller = new AbortController();
downloadBtn.addEventListener('click', fetchVideo);
abortBtn.addEventListener('click', function() {
controller.abort();
console.log('Download aborted');
});
chromium 历史版本全家桶
https://vikyd.github.io/download-chromium-history-version/ /
一个忽略的点
svg
文件不能以文件路径的形式放置在 img
标签的src里面,这样是不会显示出来的
因为svg的真正链接路径应该是svg里面的 xlink:href
的路径,通常是以data:..., base64....开头的地址
Referrer Policy 指令值
npm run xxx 的原理
unix 系默认的可执行文件,必须输入完整文件名
vue-cli-service
windows cmd 中默认的可执行文件,当我们不添加后缀名时,自动根据 pathext 查找文件
vue-cli-service.cmd
Windows PowerShell 中可执行文件,可以跨平台
vue-cli-service.ps1
Promise.allSettled 的参数接受一个 Promise 的数组,返回一个新的 Promise。执行完之后不会失败,也就是说当 Promise.allSettled 全部处理完成后,我们可以拿到每个 Promise 的状态,而不管其是否处理成功。
可以看到,Promise.allSettled 最后返回的是一个数组,记录传进来的参数中每个 Promise 的返回值,这就是和 all 方法不太一样的地方。
适用场景:
Promise.allSettled: 适用于需要执行多个不依赖于彼此成功完成的异步任务,或者当你总是想知道每个承诺的结果时;
Promise.all: 适用于任务相互依赖/想在其中任何一个拒绝时立即拒绝。
Google 推动的 File System Access API,在得到用户授权后,能与用户本地设备上的文件进行交互,可以让 PWA 技术读写本地文件系统。
Performance insights 网站性能的可行性深度分析
https://developer.chrome.com/zh/blog/new-in-devtools-102/ perf
TypeScript 的 Enums 会生成大量代码,因为在默认情况下,枚举会创建反向映射。通过 const 在 TypeScript 中与 Enums 一起引入关键字,可以减轻大量生成的代码。
enum Sizes {
Small,
Medium,
Large,
}
// 编译后代码
var Sizes;
(function (Sizes) {
Sizes[Sizes["Small"] = 0] = "Small";
Sizes[Sizes["Medium"] = 1] = "Medium";
Sizes[Sizes["Large"] = 2] = "Large";
})(Sizes || (Sizes = {}));
var size = Sizes.Small;
/**** 使用 const 声明枚举类型 ****/
const enum Sizes {
Small,
Medium,
Large,
}
const size = Sizes.Small;
// 编译后代码
var size = 0 /* Small */;
lodash 中判断是不是对象是用 isPlainObject
而不是用 isObject
isObject底层用的typeof,数组这种也对被判定为对象
如何用一行 CSS 实现 10 种现代布局
超级居中:place-items: center
解构煎饼式布局:flex: <grow>
<shrink>
<baseWidth>
侧边栏布局:grid-template-columns: minmax(<min>
, <max>
) …)
煎饼堆栈布局:grid-template-rows: auto 1fr auto
经典圣杯布局:grid-template: auto 1fr auto / auto 1fr auto
12 跨网格:grid-template-columns: repeat(12, 1fr)
RAM (Repeat, Auto, MinMax): grid-template-columns(auto-fit, minmax(<base>
, 1fr))
排列布局:justify-content: space-between
保持我的风格:clamp(<min>
, <actual>
, <max>
)
10.保持宽高比:aspect-ratio: <width>
/ <height>
UI 组件化是前端的主流开发模式,由 Google 推动的浏览器原生组件,即 Web Components,支持跨技术栈调用。
Web Components 主要技术部分是:
你可以不用 但是不能不知道系列
近期社区再次火起来的Svelte
Rollup之父对Vue、React降维打击
https://github.com/sveltejs/svelte
user-select属性详解
user-select: none | text | all | element
none: 文本不能被选择
text: 可以选择文本
all: 当所有内容作为一个整体时可以被选择。如果双击或者在 上下文上点击子元素,那么被选择的部分将是以该子元素 向上回溯的最高祖先元素。
Element: 可以选择文本,但选择范围受元素边界的约束
git revert是用一次新的commit来回滚之前的commit;
git reset是直接删除指定的commit。
在回滚这一操作上看,效果差不多。但是在以后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此之后合并老的branch时,导致这部分改变不会再次出现,但是git reset是直接把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
复制 git 暂存区中的文件到临时目录的脚本
可用于辅助处理技术栈升级代码同步的工作
mkdir temp
// 复制被修改的文件
git status | grep modified | awk '{print $2}' | xargs -I % dirname % > temp.txt
cat temp.txt | xargs -I % mkdir -p ./temp/%
git status | grep modified | awk '{print $2}' | xargs -I % cp % ./temp/%
// 复制新增的文件
git status | grep 'new file' | awk '{print $3}' | xargs -I % dirname % > temp.txt
cat temp.txt | xargs -I % mkdir -p ./temp/%
git status | grep 'new file' | awk '{print $3}' | xargs -I % cp % ./temp/%
Web端直传文件到OSS
为什么
Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传的OSS,跟数据直传相比,缺点如下:
①上传慢:OSS采用BGP带宽,能保证各地各运营商之间的传输速度
②扩展性差:用户数量多时,应用服务器会成为瓶颈
③费用高:需要多台应用服务器,与其同时OSS上行流量免费
技术方案
①利用OSS Browser.js SDK将文件上传到OSS:网络不好时可以断点续传上传大文件。在个别浏览器上有兼容性问题。
②利用OSS提供的PostObject接口,通过表单上传的方式将文件上传到OSS。兼容大部分浏览器,但网络不好时,如果单个文件上传失败,只能重试上传。——我们目前用的也是这种。
③通过小程序上传到OSS。
gitboy 这一步一定要设置!
在最新版的 Git 2.37.0 中,开启如下配置项后就能直接 git push 新分支,不再需要 --set-upstream origin: git config --global --add --bool push.autoSetupRemote true
from: 卡颂
要想搬砖稳准狠,利其器是关键
vscode6月版体验,亮眼功能 合并编辑器
更多查看:https://code.visualstudio.com/updates/v1_69
sass编译器简单介绍
第一代ruby sass,由于ruby是解释型语言,前端要编译sass需要安装ruby,2019年不再维护。
第二代node-sass,由c++实现的LibSass和node集成,成为node-sass,开发者可以在Node.js里通过api来编译sass代码。
但因为node-sass是一个c++模块,所以安装时需要与node版本对应,否则会编译报错。
2020年node-sass不再支持新特性,并标记为过时。
第三代dart-sass,官方推荐的sass编译器。dart可以编译为js,所以不需要适配node版本。
type TypeKeys<T extends Record<string, any>, Type> = keyof { [Key in keyof T as T[Key] extends Type ? Key : never]: any }
使用案例:点我在线看
type MyPlugin = {
name: string
onFetch: (res: any, payload: Record<string, any>) => void
onSelect: (selected: any[]) => void
}
// 批量触发 plugin 中的函数 hook
const runNotify = (key: keyof MyPlugin) => {
//...
}
runNotify('name') // 开发时没有错误提示
// 改进版
const runNotifyPlus = (key: TypeKeys<MyPlugin, Function>) => {
//...
}
runNotifyPlus('name') // 报错:Argument of type '"name"' is not assignable to parameter of type '"onFetch" | "onSelect"'.(2345)
size-adjust
属性用在 @font-face
中,可以自定义字体的时候指定字号大小,仅支持百分比值。
unicode-range
可以指定哪些字符应用这个自定义字体,支持任意数量的字符,也支持字符范围。任意字符转换成HTML识别格式工具页面
@font-face {
font-family: smallYuan;
src: local('PingFang SC'),
local("Microsoft Yahei");
size-adjust: 50%;
unicode-range: U+5143;
}
size-adjust
是支持 0%
,此时字符会隐藏不可见。这种隐藏会更巧妙,爬虫是不可识别的。
snippets 是片段的意思,VSCode 支持自定义 snippets,写代码的时候可以基于它快速完成一段代码的编写。
不只是 VSCode,基本所有的主流编辑器都支持 snipeets。
{ "alpha": { "prefix": ["a", "z"], "body": [ "abcdefghijklmnopqrstuvwxyz" ], "description": "字母", "scope": "javascript" } }
算是一种 DSL 了,支持很多语法,比如指定光标位置、多光标编辑、placeholder、多选值、变量、对变量做转换等语法。
scrollbar-gutter
可以让滚动条出现的时候内容不晃动。
scrollbar-gutter: auto | stable | both-edges
auto就是默认的表现。没有滚动条的时候,内容尽可能占据宽度,有了滚动条,可用宽度减小。
stable如果 overflow
属性计算值不是 visible
,则提前预留好空白区域,这样滚动条出现的时候,整个结构和布局都是稳定的。
both-edges这个是让左右两侧同时预留好空白区域,目的是让局部绝对居中对称。
随着 Vue3 一大堆新特性的发布,并且源头上支持了 TS,而 Vetur 备受诟病的 性能、TS 支持已经跟不上 Vue 了,于是基于 @vue/reactivity ,实现一切按需计算,提供原生 TypeScript 语言服务级别的性能对 Volar 这一高性能的 Vue 语言插件孕育而生。
使用方式也很简单,正常通过 vite 创建 Vue 项目即可。
除了支持 Vue3 基本的语法高亮、和代码提示, Volar 还具备:
.vue
文件解析<template>
上。<style>
里面的 class
引用lang
语法提示<template>
语法转换让人意外的是,Volar 还支持了 vue2,只需要在 ts.config.json
加上个配置即可。
(文档上说还需安装
@vue/runtime-dom
和删除.d.ts
,但是效果并不好)
{
//...
"vueCompilerOptions": {
"target": 2,
},
}
此外, Volar 还提供了一些开箱即用的插件,有兴趣的可以了解一下
浏览器提供了原生的 API,可以轻松实现浏览器滚动后不记住滚动位置每次刷新都回到顶部的能力!使用很简单,在页面的任意位置执行下面几行 JS 代码就可以了
if (history.scrollRestoration) {
history.scrollRestoration = 'manual';
}
Source 面板 = VSCode
使用 command + p 可以快捷打开指定文件,在有sourcemap 环境下与源码文件对应,可以快捷打断点:
众所周知,NaN !== NaN。
const x = NaN;
x !== x // true
这是因为 NaN
代表的是一个范围,而不是一个具体的数值。在早期的 isNaN()
函数中,即使传入字符串,也会返回 true
,这个问题已经在 es6 中修复。
isNaN('abc'); // true
Number.isNaN('abc') // false
所以如果想兼容旧浏览器,可以用 x !== x 来判断是不是NaN
vue3 console.log 一个ref等响应值,看到的数据是一层又一层的proxy嵌套,有时候找某个属性很困难,很低效
教你一个小方法
打开Chrome 控制台的设置页面,找到console里面的
enable custom fomatters
打开即可看到console.log的值就很精简了
npm 包有错误需要本地 hack 修复, patch-package 最佳实践
// 官方推荐同时安装 postinstall-postinstall
yarn add patch-package postinstall-postinstall
"scripts": {
+ "postinstall": "patch-package"
}
yarn patch-package package-name
https://www.npmjs.com/package/patch-package
锁定唯一版本!
^1.0.0
version
字段是唯一的版本号,如 1.0.0
"@xiaoman/element-ui@^1.4.9": version "1.4.9" resolved "http://npm.xiaoman.cn/@xiaoman...." integrity sha512-oJ...... dependencies: async-validator "~1.8.1" babel-helper-vue-jsx-merge-props "^2.0.0" deepmerge "^1.2.0" throttle-debounce "^1.0.1"
各个字段代表的意思?
version
是实际安装的版本
resolved
的是一个链接,是下载这个包的地址
integrity
是对 resolved
下载下来的文件进行完整性校验
dependencies
是这个包自己的依赖
scrollbar-color
可以定义滚动条的颜色,语法如下:
scrollbar-color: auto | 滑杆颜色 轨道颜色;
scrollbar-width
可以设置滚动条的宽度,不过这个宽度不能随意指定,是有约束的,语法如下所示:
scrollbar-width: auto | thin | none;
auto
就是默认的尺寸,在 Windows 系统下是 17px;thin
是窄滚动条,在 Windows 系统下是 8px;none
没有滚动条,宽度为0,但是内容依然可以滚动。有这么一种情况,我们需要拿某个数组arr的最后一个元素,很平常的做法 => arr[arr.length -1]
如果arr这个变量名过长那样显得很冗杂
巧了,es2020新出规范,数组新增一个at方法, 想要拿数组最后一个元素,很简单 => arr.at(-1)
命令式编程需要明确指出计算机需要完成目标的具体步骤,重点在于如何做。
声明式(函数式)编程就是将现实的事物抽象为程序运算,不关心具体的实现。
例如:从数组中获取所有偶数
const arr = [1, 2, 3, 4, 5, 6];
// 命令式编程
const result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 === 0) {
result.push(arr[i]);
}
}
// 声明式编程
const result = arr.filter(item => item % 2 === 0);
设置了content-visibility: auto 的内容在可视区外将不被渲染,它相比于visibility属性,提升了首次渲染的速度,相比于display属性它又不会影响全局的搜索功能,使用它能提升长列表、长文本页面的渲染性能;
通过**Resource Timing API
**可以获取和分析应用资源加载的详细网络计时数据,应用程序可以使用时间度量标准来确定加载特定资源所需要的时间,比如XMLHttpRequest
, <SVG>
, 图片,或者脚本。
https://developer.mozilla.org/zh-CN/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API
package-lock.json 在 npm 更改 node_modules 目录树 或者 package.json 时自动生成的 ,它准确的描述了当前项目npm包的依赖树,并且在随后的安装中会根据 package-lock.json 来安装,保证是相同的一个依赖树,不考虑这个过程中是否有某个依赖有小版本的更新。
当 npm install 时,会自动生成一个 package-lock.json 文件,和 package.json 在同一级目录下。package-lock.json 记录了项目的一些信息和所依赖的模块。这样在每次安装都会出现相同的结果。
CSS accent-color
属性可以在不改变浏览器默认表单组件基本样式的前提下重置组件的颜色。
目前支持下面这些 HTML 控件元素:
复选框:<input type=”checkbox”>
单选框 <input type=”radio”>
范围选择框:<input type=”range”>
进度条:<progress>
accent-color
属性具有继承性,只需要在对应表单控件元素的祖先元素上设置,响应的控件的颜色就会发生变化。
使用按位操作取整:
let x = 1.23 | 0; // 1
因为按位操作只支持32位的整型,所以小数点部分全部都被抛弃
当你需要过滤数组某个不符合条件的元素,并且将每个元素都格式化成想要的数据的时候
1.先filter后再map(low)
2.reduce写法 (medium)
3.flatMap --- 过滤的返回空数组即可 (good)
$i
直接在控制台安装npm包
有时候如果想在控制台直接调试 dayjs
或者 lodash
的某个 API
可以通过安装 Console Importer
插件
$i('name') 安装npm包
user-select
属性可以设置是否允许用户选择页面中的图文内容。user-modify
属性可以设置是否允许输入框输入内容,以及是否只允许输入纯文。user-drag
属性可以设置是否允许页面元素拖拽。提案链接:https://tc39.es/proposal-array-find-from-last/index.html
这一提案为数组(Array 与 TypedArray)引入了两个新方法 findLast
与 findLastIndex
,来支持从数组的结尾开始查找一个元素,以及它在数组中位于倒数第几项(如 -1、-2)。
我们知道 JavaScript 中 Array.find
方法会返回第一个符合条件的数组成员,如果我们想做的是获取最后一个符合条件的成员(如多次操作中取最后一次操作),就需要复制一个数组,调用 reverse 方法,然后才能进行搜索:
[...[]].reverse().find();
这意味着你需要额外创建一个数组并进行操作。
类似的,Array.findIndex
方法也会返回第一个符合条件的数组成员的索引,如果你希望获得最后一个符合条件成员的索引,也需要进行数组的复制和反转,然后配合数组的长度进行计算:
const arr = [1, 2, 3, 4];
arr.length - 1 - [...arr].reverse().findIndex(i => i % 2 === 1); // 2
arr.length - 1 - [...arr].reverse().findIndex(i => i % 2 === 10); // 4,错误
在第二处调用中,由于 findIndex 会在没有找到符合条件成员时返回 -1,此时就需要进行额外的处理。
基于此提案引入的方法,你可以使用符合直觉的方式来找到最后一个满足条件的成员:
const arr = [1, 2, 3, 4];
arr.findLast(i => i % 2 === 1); // 3
arr.findLastIndex(i => i % 2 === 1); // 2
arr.findLastIndex(i => i % 2 === 10); // -1
目前,我们已经可以在 Chrome 97 中使用这些 API 了。另外,现在也可以通过 core-js 和 es-shims 来使用这两个方法。
2022 年 6 月 22 日,第 123 届 ECMA 大会批准了 ECMAScript 2022 语言规范,其中包含 Object.hasOwn()。
在ES2022之前,可以使用 Object.prototype.hasOwnProperty() 来检查一个属性是否属于对象。 Object.hasOwn 特性是一种更简洁、更可靠的检查属性是否直接设置在对象上的方法:
const example = {
property: '123'
};
console.log(Object.prototype.hasOwnProperty.call(example, 'property'));
console.log(Object.hasOwn(example, 'property'));
该特性的浏览器支持如下:
记住一个模板的子树。元素和组件上都可以使用。该指令接收一个固定长度的数组作为依赖值进行记忆比对。如果数组中的每个值都和上次渲染的时候相同,则整个该子树的更新会被跳过。例如:
<ul v-for="member of members" :key="member.id" v-memo="[member.username]">
<li>{{ member.username }}</li>
</ul>
当组件重新渲染的时候,如果 member.username
的值维持不变,那么对这个 <ul>
以及它的所有子节点的更新都将被跳过。事实上,即使是虚拟 DOM 的 VNode 创建也将被跳过,因为子树的记忆副本可以被重用。
正确地声明记忆数组是很重要的,否则某些事实上需要被应用的更新也可能会被跳过。带有空依赖数组的 v-memo
(v-memo="[]"
) 在功能上等效于 v-once
。
v-memo
仅供性能敏感场景的针对性优化,会用到的场景应该很少。渲染 v-for
长列表 (长度大于 1000) 可能是它最有用的场景:
<ul v-for="member of members" :key="member.id"
v-memo="[member.name, member.id == selectedUser]">
<li>
<span :class="{ selected: selectedUser == member.id }">{{ user.name }}</span>
</li>
</ul>
v-memo
数组中也可以接收 条件判断语句,上面的代码演示中,当组件的 selectedUser
状态发生变化时,即使绝大多数 member
都没有发生任何变化,大量的 VNode 仍将被创建,此处使用的 v-memo
本质上代表着“仅在 member 从未选中变为选中时更新它,反之亦然”
在 v-for
中使用 v-memo
时,确保它们被用在了同一个元素上。 v-memo
在 v-for
内部是无效的。
File 文件格式(本地上传)的图片进行预览:
// 1. URL.createObjectURL()
// 创建DOMString,返回一个URL,URL和document绑定,表示指定的File对象
const url = URL.createObjectURL(uploadedFile)
// FileReader.readAsDataURL()
// 一个FileReader上面的实例方法,读取指定的File对象,
// 读取完成的时候触发回调,返回URL格式的字符串(base64)
const fileReader = new FileReader()
fileReader.readAsDataURL(uploadedFile)
fileReader.addEventListener('load', () => {
const url = fileReader.result as string
})
这两种方式的不同点:
总结:
多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,这就有点大材小用了。所以就有了 $attrs
/ $listeners
,通常配合 inheritAttrs 一起使用。
inheritAttrs:默认值为 true。默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置
inheritAttrs
到false
,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例 property$attrs
可以让这些 attribute 生效,且可以通过v-bind
显性的绑定到非根元素上。查 看 官 网
简单的说就是 inheritAttrs:true 继承除props之外的所有属性;inheritAttrs:false 只继承class属性
$attrs
:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
$listeners
:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
我们在安装项目时会用到众多 npm 依赖库,部分库在安装时会从 raw.githubusercontent.com 下载静态资源包。
而由于众所周知的原因,GitHub 域名会受到不可控的 DNS 污染,导致依赖安装失败。
此时我们可以手动配置host,或者使用 Google dns
**手动配置host之前,需要知道相关域名解析的IP地址,此时可访问 **https://ipaddress.com/website 进行查询,
例如我们通过该网站查询【raw.githubusercontent.com】的 IP,在结果页中找到该域名对应的 IPv4 的地址并添加到本地 host 即可,如下图:
tips: 如果有多个IP,可在本地使用 ping 命令找到其中最快的一个:
配置Google dns:
https://developers.google.cn/speed/public-dns/
https://raw.hellogithub.com/hosts
Tooltip和select等有浮层的组件,可以设置getPopupContainer属性,将浮层渲染到父节点上(默认渲染到 body 上)。
用法:
getPopupContainer={triggerNode => triggerNode.parentNode}
可以用于解决浮层滚动时的定位问题,而不需要修改样式。
pt 是一个专用的印刷单位“磅”,属于物理长度单位,其大小为 1/72 英寸,称为“绝对长度”。换算公式为: pt = px * 3/4
px 全称为 pixel,是针对于显示器屏幕分辨率而言的“相对长度”。默认情况下:16px = 1em = 1rem
em 全称为 font-size of the element,是指相对于父元素的字体大小的单位,也属于“相对长度”。
rem 全称为 font-size of the root element,是指相对于根元素的字体大小的单位,也属于“相对长度”。
meta 标签:自动刷新/跳转
假设要实现一个类似 PPT 自动播放的效果,你很可能会想到使用 JavaScript 定时器控制页面跳转来实现。但其实有更加简洁的实现方法,比如通过 meta 标签来实现:
<meta http-equiv="Refresh" content="5; URL=page2.html">
上面的代码会在 5s 之后自动跳转到同域下的 page2.html 页面。我们要实现 PPT 自动播放的功能,只需要在每个页面的 meta 标签内设置好下一个页面的地址即可。
另一种场景,比如每隔一分钟就需要刷新页面的大屏幕监控,也可以通过 meta 标签来实现,只需去掉后面的 URL 即可:
<meta http-equiv="Refresh" content="60">
常用的meta标签:
charset:用于描述HTML文档的编码形式
http-equiv:顾名思义,相当于http的文件头作用,比如下面的代码就可以设置http的缓存过期日期
viewport:移动前端最熟悉不过,Web开发人员可以控制视口的大小和比例
apple-mobile-web-app-status-bar-style:开发过PWA应用的开发者应该很熟悉,为了自定义评估工具栏的颜色。
margin和padding设置百分比的时候,百分数是相对于父级宽度的百分比
css3实现0.5px的细线
<style>
.line {
position: relative;
}
.line:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
background-color: #000000;
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
}
</style>
<div class="line"></div>
优化构建体积
加快构建速度
sideEffects: boolean | string[]
process.nextTick() 是 Nodejs 异步
API
的一部分,但并不属于事件循环。 process.nextTick() 会在事件循环的每个阶段操作完成后处理,即执行下一个tick--宏任务前,而不管事件循环的当前是哪个阶段 因此在调用回调之前就能拿到所有的变量、函数等。process.nextTick()还具有阻止事件循环继续的优势,适用于在事件循环继续之前,提醒用户有错误发生。
vue3对于关闭的特性,可以利用 Tree-Shaking
机制摇掉相关代码,使最终打包的资源体积最小化。
特性开关实现: 本质上是利用rollup.js的预定义常量插件来实现。比如
{
FEATURE_OPTION_API: isBundlerESMBuild ? __VUE_OPITIONS_API__
: true
}
__VUE_OPITIONS_API__
是个特性开关,通过设置该值来控制是否要包含兼容 vue2 选项API的调用方式
Chrome 103 测试版于 2022 年 5 月 26 日发布,预计将于 2022 年 6 月下旬成为稳定版。
关键变化如下:
沙盒 iframe 中阻止外部协议
移除元素 <param>
更多查看:https://developer.chrome.com/en/blog/deps-rems-103/
『包管理器的管理器』- Corepack
// 启用
corepack enable
// package.json
"packageManager": "pnpm@7.1.5"
// 升级全局版本
corepack prepare yarn@x.y.z --activate
简单的广告跟踪三步走:
HTML页面的生命周期
DOMContentLoaded:浏览器完全加载了HTML,Dom树构建完毕,但是像 <img>
和样式表等外部资源可能并未下载完毕
load:浏览器已加载所有资源
beforeunload:用户即将离开当前页(刷新或关闭)时触发。正要去服务器读取新的页面时调用,此时还没开始读取
unload:用户离开页面后触发。已从服务器读取到需要加载的新页面,即将替换当前页面时调用
js新出规范--管道运算符 |> 它可以代替我们原先丑陋的嵌套函数的写法,eg. fn1(fn2(x)) 用管道运算符可以写成: x |> fn1 |> fn2
async 和 defer的区别图解
HTTP状态码简易分类 1××开头 - 信息提示 2××开头 - 请求成功 3××开头 - 请求被重定向 4××开头 - 请求错误 5××开头 - 服务器错误
如何理解函数式编程
函数式编程具有五个鲜明的特点。
1. 函数是"第一等公民"
所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。
举例来说,下面代码中的print变量就是一个函数,可以作为另一个函数的参数。
var print = function(i){ console.log(i);};
[1,2,3].forEach(print);
2. 只用"表达式",不用"语句"
"表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
原因是函数式编程的开发动机,一开始就是为了处理运算(computation),不考虑系统的读写(I/O)。"语句"属于对系统的读写操作,所以就被排斥在外。
当然,实际应用中,不做I/O是不可能的。因此,编程过程中,函数式编程只要求把I/O限制到最小,不要有不必要的读写行为,保持计算过程的单纯性。
3. 没有"副作用"
所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。
4. 不修改状态
上一点已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。
在其他类型的语言中,变量往往用来保存"状态"(state)。不修改变量,意味着状态不能保存在变量中。函数式编程使用参数保存状态,最好的例子就是递归。下面的代码是一个将字符串逆序排列的函数,它演示了不同的参数如何决定了运算所处的"状态"。
function reverse(string) {
if(string.length == 0) {
return string;
} else {
return reverse(string.substring(1, string.length)) + string.substring(0, 1);
}
}
由于使用了递归,函数式语言的运行速度比较慢,这是它长期不能在业界推广的主要原因。
5. 引用透明
引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。
有了前面的第三点和第四点,这点是很显然的。其他类型的语言,函数的返回值往往与系统状态有关,不同的状态之下,返回值是不一样的。这就叫"引用不透明",很不利于观察和理解程序的行为。
URLSearchParams定义了一些实用的方法来处理URL的查询字符串。使用它的构造函数会返回一个新的URLSearchParams对象。开头的 ?
字符会被忽略。
一个简单的hooks用于获取链接query参数
const useQueryParams = (query: string = null) => {
const result: Record<string, string> = {};
new URLSearchParams(query||window.location.search).forEach((value, key) => {
result[key] = value;
});
return result;
}
使用
// http://localhost:3000/?userId=1889&num=112
const { userId, num } = useQueryParams();
// OR
const params = useQueryParams('userId=1889&num=112');
URLSearchParams MDN链接
react-router-dom
react-router-dom v6可以使用**useSearchParams **。react router v4/v5没有此hooks.
const [searchParams, setSearchParams] = useSearchParams();
searchParams.get("userId")
竟态问题可以简略描述为:
由于请求是异步,请求第一个接口后,数据1还没有响应回来,又立马请求了第二个接口,而第二个接口数据2的响应比数据1先得到,这样就有可能导致明明交互触发接口2得到的应该是数据2 却得到接口1的数据1
解决竟态问题可以利用AbortController接口,AbortController.signal是一个信号源可以用来停止网络请求
节流
// 使用时间戳
function throttle(func, wait) {
let preTime = 0;
return function () {
let nowTime = +new Date();
let context = this;
let args = arguments;
if (nowTime - preTime > wait) {
func.apply(context, args);
preTime = nowTime;
}
};
}
// 定时器实现
function throttle(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
}
};
}
防抖
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
let callNow = !timeout;
timeout = setTimeout(function () {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
}
};
}
cookie、localStorage、sessionStorage
1、cookie
其缺点:
2、localStorage 和 sessionStorage
它们的区别:
使用 canvas进行上传图片的压缩
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas 压缩图片</title>
</head>
<body>
<input type="file" id="upload">
<script>
const ACCEPT = ['image/jpg', 'image/png', 'image/jpeg']
const MAXSIZE = 3 * 1024 * 1024
function convertImageToBase64(file, callback) {
let render = new FileReader()
render.addEventListener('load', function(e) {
// 此时拿到base64的文件
const base64Image = e.target.result
callback && callback(base64Image)
render = null
})
render.readAsDataURL(file)
}
function compress(base64Image, callback) {
let maxW = 1024
let maxH = 1024
const image = new Image()
image.addEventListener('load', function(e) {
let ratio // 图片的压缩比
let needCompress = false // 是否需要压缩
if (maxW < image.naturalWidth) {
needCompress = true
ratio = image.naturalWidth / maxW
maxH = image.naturalHeight / ratio
}
if (maxH < image.naturalHeight) {
needCompress = true
ratio = image.naturalHeight / maxH
maxW = image.naturalWidth / ratio
}
if (!needCompress) {
maxW = image.naturalWidth
maxH = image.naturalHeight
}
const canvas = document.createElement('canvas')
canvas.setAttribute('id', '__compress__')
canvas.width = maxW
canvas.height = maxH
canvas.style.visibility = 'hidden'
document.body.appendChild(canvas)
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, maxW, maxH)
ctx.drawImage(image, 0, 0, maxW, maxH)
const compressImage = canvas.toDataURL('image/jpeg', 0.8)
callback && callback(compressImage)
canvas.remove()
})
image.src = base64Image
document.body.appendChild(image)
}
const upload = document.getElementById('upload')
upload.addEventListener('change', function(e) {
const [file] = e.target.files
if (!file) {
return
}
const {type: fileType, size: fileSize} = file
if (!ACCEPT.includes(fileType)) {
console.log('不支持的文件类型')
upload.value = ''
return
}
if (fileSize > MAXSIZE) {
console.log('文件超出大小')
upload.value = ''
return
}
convertImageToBase64(file, (base64Image) => {
compress(base64Image, (compressImage) => {
console.log(compressImage)
})
})
})
</script>
</body>
</html>
在 ES6 之后 Object 的键值对按照自然数、非自然数和 Symbol 进行排序,自然数是按照大小升序进行排序,其他两种都是按照插入的时间顺序进行排序。
globalThis
提供了一个标准的方式来获取不同环境下的全局 this
对象(也就是全局对象自身)。不像 window
或者 self
这些属性,它确保可以在有无窗口的各种环境下正常工作。所以,你可以安心的使用 globalThis
,不必担心它的运行环境。
需要注意的是,globalThis 虽然好用,在浏览器兼容方面有一些要求(如图),如果对浏览器兼容要求高的,最好写上polyfill。
vue3中computed会影响性能的原因主要是:
computed是 lazy
惰性的,只会在读取依赖更新时再去重新执行计算
正是因为是lazy的,所以有些情况下比如一个computed返回的是简单数据结构比如布尔值,由于依赖变了,让computed认为它需要变也就是 dirty
的,另一个依赖这个布尔值computed的也被通知要变化,然后去计算这个布尔值的computed
但其实这个布尔值computed返回的布尔值没有变,这样就会导致页面更新了
推荐返回布尔值的computed使用vueuse的eagerComputed
display:none
隐藏对应的元素,其 DOM 结构不会渲染。 visibility:hidden
隐藏对应的元素,但仍保留 DOM 结构。
主要区别在于:是否会占用空间
map与weekmap的区别:
Map
的键可以是任意类型,WeakMap
只接受对象作为键(null除外)
Map
的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键; WeakMap
的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的
Map
可以被遍历, WeakMap
不能被遍历
web 端图像处理之亮度计算
核心算法:
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
// 亮度
if (brightness != 0.0){
vec3 hsv_color = rgb2hsv(gl_FragColor);// RGB 转 HSV 色彩空间
if (brightness > 0.0) {
hsv_color.z *= 1.0 + 1.5 * brightness / 100.0;// 输入值正向范围(0~100)对应饱和度范围为(1~2.5)
} else if (brightness < 0.0) {
hsv_color.z *= 1.0 + 0.7 * brightness / 100.0;// 输入值反向范围(-100~0)对应饱和度范围为(0.3~1)
}
vec3 rgb_color = hsv2rgb(hsv_color);
gl_FragColor = vec4(rgb_color.xyz, gl_FragColor.w);
}
}
回流一定会触发重绘,而重绘不一定会回流
利用nodejs创造属于自己的加密货币
https://blog.logrocket.com/build-cryptocurrency-node-js-blockchain/
vue-router
在实现单页面前端路由时,提供了 Hash
和 History
两种模式
vue2 :根据 mode
参数决定采用哪种方式
vue3 : 采用 history
参数
2022 Frontend Developer Roadmap https://roadmap.sh/roadmaps/frontend.png
避免大数据number类型丢失精度,造成一定安全性问题----BigInt
BigInt是一种新的数据类型,用于当整数值大于Number数据类型支持的范围时。
这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库
介绍一个很有趣的javascript特性--jsfuck
https://www.jianshu.com/p/e7246218f424
问题:
代码:
const reg = /(?<=<)[^>]+/
控制台报错:
SyntaxError: Invalid regular expression: invalid group specifier name
原因分析:Safari不支持零宽断言
那什么是零宽断言?
用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧: 断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
正则零宽断言,一共4种 1、(?=xxx) 例:\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分 2、(?<=xxx) 例:(?<=\bre)\w+\b会匹配以re开头的单词的后半部分 3、(?!xxx) 例:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字 4、(?<!xxx) 例:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字
在我上面所写的正则表达式中,就用到了 零宽断言
:?<=<
解决:
修改正则后即可:
const reg = /<([^<>]*)>/
浏览器渲染UI过程:
闭包的变量是存在栈中还是堆中?
闭包的变量其实存放在堆中的scope中,以此保证闭包变量不会被回收
HTTP有哪些⽅法?
HTTP1.0定义了三种请求⽅法:GET,POST和HEAD⽅法
HTTP1.1新增了五种请求⽅法:OPTIONS,PUT,DELETE,TRACE和CONNECT
伪类与伪元素的区别
伪类用于当已有的元素处于某个状态时,为其添加对应的样式,这个状态是根据用户行为而动态变化的。比如说,当用户悬停在指定的元素时,我们可以通过:hover来描述这个元素的状态。
伪元素用于创建一些不在文档树中的元素,并为其添加样式。它们允许我们为元素的某些部分设置样式。比如说,我们可以通过::before来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。
可视化理解代码块的调用栈,执行上下文
https://pythontutor.com/visualize.html#mode=edit
Canvas 和 SVG 的区别:
实现不可变数据有三种主流的⽅法:
script 标签中 defer 和 async 的区别有:
script
:会阻碍 HTML 解析,只有下载好并执行完脚本才会继续解析 HTML。
async script
:解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。
defer script
:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。
content
。IE 盒模型:content + padding + border
** 。** 可以**通过 <b>box-sizing</b>
** 来改变元素的盒模型: content-box
:标准盒模型(默认值);box-sizing: border-box
:IE 盒模型。async/await 和 Promise 的区别有:
『每日工具』- https://qwerty.kaiyi.cool/
判断JS 数据类型的方法有:
typeof
:能准确判断基本类型,函数, 对引用类型(null、对象、数组)不能精确判断,因为都返回 object
instanceof
:只能判断引用类型 ,其内部运行机制是判断在其原型链中能否找到该类型的原型Object.prototype.toString.call()
:所有数据类型都是能判断的,还有 Error 对象,Date 对象等JavaScript 共有 8
种数据类型,分别为: Undefined
、 Null
、 Boolean
、 Number
、 String
、 Object
、 Symbol
、 BigInt
6分钟 幼稚园小朋友也能看到的kafka消息队列。
https://www.bilibili.com/video/BV1vx411f7hA?spm_id_from=333.337.search-card.all.click
开发人员的百科全书:
https://devdocs.io/
🍁 HTTP/HTTPS向服务端传递数据的5种基本方式:
pnpm 在安装依赖时使用了 Hard Link(硬链接) 机制,该机制和的区别 Symbolic link(软连接)是:
服务端渲染(SSR),其实就是由浏览器做的一些事情,我们放到了服务端去做。
🍃优缺点:
优点:首屏渲染快,利于SEO、可以生成缓存片段,生成静态文件、相对客户端渲染而言节能
缺点:服务端压力较大
常数枚举只能使用常数枚举表达式并且不同于常规的枚举的是它们在编译阶段会被删除。 常数枚举成员在使用的地方被内联进来。 这是因为常数枚举不可能有计算成员
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
编译后
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
实现Comet的手段主要有两个:长轮询和HTTP流。
vue3组件通信方式有:
前端离线存储的方案有:
ts里type和interface的区别?🤔 type:不仅可以用来表示基本类型,还能用来表示对象类型 interface(接口):仅限于描述对象类型😜