跳到主要内容

picgo插件开发

· 阅读需 2 分钟
Bowen Zhang
本文作者

借鉴文档

Typora配置picgo-core自动上传图片,及picgo-core上传组件开发

PicGo插件开发文档

写在前面

为什么要自定义一个上传插件呢 因为 gitee 用不了了😔 觉得图片还是放到自己的服务器上安全 使用过web-uploader插件但是有问题调不通我的接口,于是自己写个上传插件方便一些 我的自定义上传插件 :picgo-plugin-bitbw-upload 插件地址

基于service-worker实现部署后提示用户刷新

· 阅读需 1 分钟
Bowen Zhang
本文作者

Vue项目部署新版本后提示用户刷新浏览器

vue-cli 创建带pwd的项目

vue create pwa-product

# 选择 pwd

修改 src/registerServiceWorker.js

registerServiceWorker

/* eslint-disable no-console */

import { register } from "register-service-worker";

if (process.env.NODE_ENV === "production" && navigator.serviceWorker) {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
"App is being served from cache by a service worker.\n" +
"For more details, visit https://goo.gl/AFskqB"
);
},

registered(registration) {
console.log("Service worker has been registered.");
// 通过测试新的服务工作线程来定期检查应用更新
setInterval(() => {
registration.update();
}, 1000); // 这里为了测试 每秒检查一次
},
cached() {
console.log("Content has been cached for offline use.");
},
updatefound() {
console.log("New content is downloading.");
},
// 有个更新 通知页面更新
updated(registration) {
console.log("New content is available; please refresh.");
// 创建一个自定义事件
const event = new CustomEvent("swupdatefound", { detail: registration });
// 触发这个事件
document.dispatchEvent(event);
},
offline() {
console.log(
"No internet connection found. App is running in offline mode."
);
},
error(error) {
console.error("Error during service worker registration:", error);
},
});

let refreshing;
// 监听需要更新事件 调用 window.location.reload()
navigator.serviceWorker.addEventListener("controllerchange", function () {
if (refreshing) return;

window.location.reload();

refreshing = true;
});
}

在页面中添加事件监听

在 main.js 或 store 中添加事件监听

// 添加对应自定义事件的监听
document.addEventListener("swupdatefound", (e) => {
// 提示用户刷新
let res = confirm("新内容可用,请刷新");
if (res) {
// e.detail == registration
// waiting.postMessage({ type: "SKIP_WAITING" }) 是固定写法
// 用于触发更新 navigator.serviceWorker.addEventListener("controllerchange"...)
e.detail.waiting.postMessage({
type: "SKIP_WAITING",
});
}
});

为什么 waiting.postMessage({ type: "SKIP_WAITING" }) 会触发更新

在打包下的 dist 目录下service-worker.js 看到一下代码

// self 是 worker 子线程的标准
// waiting.postMessage({ type: "SKIP_WAITING" }) 会触发下面事件监听
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
// 调用 触发 controllerchange
self.skipWaiting();
}
});

常见面试题汇总

· 阅读需 5 分钟
Bowen Zhang
本文作者

js 函数的防抖(debounce)与节流(throttle)

原文:函数防抖和节流;

序言:

我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove, resize, onscroll 等等,有些时候,我们并不能或者不想频繁触发事件,咋办呢?这时候就应该用到函数防抖和函数节流了!

准备材料:

<div
id="content"
style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"
></div>

<script>
let num = 1;
let content = document.getElementById("content");

function count() {
content.innerHTML = num++;
}
content.onmousemove = count;
</script>

这段代码, 在灰色区域内鼠标随便移动,就会持续触发 count() 函数,导致的效果如下:

img

接下来我们通过防抖和节流限制频繁操作。

函数防抖(debounce)

短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行。

// 非立即执行版
function debounce(func, wait) {
let timer;
return function () {
let context = this; // 注意 this 指向
let args = arguments; // arguments中存着e

if (timer) clearTimeout(timer);

timer = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}

我们是这样使用的:

content.onmousemove = debounce(count, 1000);

非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。效果如下:img

// 立即执行版
function debounce(func, wait) {
let timer;
return function () {
let context = this; // 这边的 this 指向谁?
let args = arguments; // arguments中存着e

if (timer) clearTimeout(timer);

let callNow = !timer;

timer = setTimeout(() => {
timer = null;
}, wait);

if (callNow) func.apply(context, args);
};
}

立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。用法同上,效果如下:

img

// 合成版
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行
*/
function debounce(func, wait, immediate) {
let timer;
return function () {
let context = this,
args = arguments;

if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, wait);
}
};
}

节流(throttle)

指连续触发事件但是在 n 秒中只执行一次函数。即 2n 秒内执行 2 次... 。节流如字面意思,会稀释函数的执行频率。

同样有两个版本,时间戳和定时器版。

// 时间戳版
function throttle(func, wait) {
let previous = 0;
return function () {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
};
}

使用方式如下:

content.onmousemove = throttle(count, 1000);

效果如下:

img

可以看到,在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次。

// 定时器版
function throttle(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
};
}

用法同上,效果如下:

img

可以看到,在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。

我们应该可以很容易的发现,其实时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。

同样地,我们也可以将时间戳版和定时器版的节流函数结合起来,实现双剑合璧版的节流函数。

/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait, type) {
if (type === 1) {
let previous = 0;
} else if (type === 2) {
let timeout;
}
return function () {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();

if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
}
};
}

附录:

  关于节流/防抖函数中 context(this) 的指向解析:

首先,在执行 throttle(count, 1000) 这行代码的时候,会有一个返回值,这个返回值是一个新的匿名函数,因此 content.onmousemove = throttle(count,1000); 这句话最终可以这样理解:

content.onmousemove = function() {
let now = Date.now();
let context = this;
let args = arguments;
...
console.log(this)
}

到这边为止,只是绑定了事件函数,还没有真正执行,而 this 的具体指向需要到真正运行时才能够确定下来。所以这个时候如果我们把前面的 content.onmousemove 替换成 var fn 并执行 fn fn() ,此时内部的 this 打印出来就会是 window 对象。

其次,当我们触发 onmousemove 事件的时候,才真正执行了上述的匿名函数,即 content.onmousemove() 。此时,上述的匿名函数的执行是通过 对象.函数名() 来完成的,那么函数内部的 this 自然指向 对象。

最后,匿名函数内部的 func 的调用方式如果是最普通的直接执行 func() ,那么 func 内部的 this 必然指向 window ,虽然在代码简单的情况下看不出什么异常(结果表现和正常一样),但是这将会是一个隐藏 bug,不得不注意啊!所以,我们通过匿名函数捕获 this,然后通过 func.apply() 的方式,来达到 content.onmousemove = func 这样的效果。

可以说,高阶函数内部都要注意 this 的绑定。

输入防抖节流

<!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>Document</title>
</head>
<body>
<input class="input" value="" type="text" />
<button class="btn">点击</button>
<script>
document
.querySelector(".input")
.addEventListener("input", throttle(handleFn, 500, true));
let index = 1;
function handleFn(e) {
console.log("index", index);
console.log("handleFn", e, this.value);
index++;
}
// 防抖 间隔delay时间内多次触发,只执行第一次,或最后一次
function debounce(fn, delay, triggerNow = false) {
let timer = null;
return function (...arg) {
const context = this;
// clearTimeout 保证只能首次 或者最后一次被执行,否则在规定delay的时间内都会被清理掉
if (timer) clearTimeout(timer);
// 立即执行版 一段delay时间内多次触发只有第一次被执行
if (triggerNow) {
let first = !timer;
if (first) fn.call(context, ...arg);
timer = setTimeout(() => {
// 恢复 timer 以便首次执行
timer = null;
}, delay);
// 最后一次执行版 一段delay时间内多次触发只有最后一次被执行
} else {
timer = setTimeout(() => {
fn.call(context, ...arg);
}, delay);
}
};
}
// 节流 一段delay时间出发多次,只执行一次 ,fristTrigger 第一次执行 最后一次执行
function throttle(fn, delay, fristTrigger = false) {
let timer = null; // 定时器默认为null
let last = 0; // 最后一次时间戳默认为0
return function (...arg) {
const context = this;
if (fristTrigger) {
// 一定时间内执行第一次
// 当前时间戳 - 之前时间戳 > delay 再执行
const cur = Date.now();
if (cur - last > delay) {
fn.call(context, ...arg);
last = cur;
}
} else {
// 没有定时器再执行 执行清空定时器 ,一定时间内执行最后一次
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.call(context, ...arg);
}, delay);
}
}
};
}
</script>
</body>
</html>

Web前端高频面试题全解析记录

· 阅读需 3 分钟
Bowen Zhang
本文作者

var 变量提升

var 申明的变量会被提升到当前作用域的最顶端 所谓作用域是 function 这样的函数才算是, if else for 等带 {} 的是没有作用域的无论嵌套多少层都会提升

(function () {
console.log(i); //var i 被提升到这里 结果是 undefind ,如果没提升就会报 Uncaught ReferenceError: i is not defined
if (false) {
if (false) {
// for 中 var i = 0; 会被提到最上面
for (var i = 0; i < 10; i++) {}
}
}
})();
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack'; // 这个会被提升到当前作用域的最顶端 var name
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();

Array(3) 和 Array.from({length:3})

Array(3) 是创建了一个 length: 3 没有经过初始化的数组,数组每一项其实是empty也就是未经初始化 Array.from({length:3}) 是创建了一个 length: 3 经过初始化的数组,数组每一项是 undefind

使用时的区别 Array.prototype.map filter forEach 等, 只有数组中被初始化过元素才会被触发,也就是说未经初始化的元素压根不会被遍历到

手写 async await


// 包装 generator 函数
function asyncToGenerator(generatorFunc) {
// 返回的是一个新的函数
return function () {
// 先调用generator函数 生成迭代器
// 对应 var gen = testG()
const gen = generatorFunc.apply(this, arguments);
// 返回一个promise 因为外部是用.then的方式 或者await的方式去使用这个函数的返回值的
// var test = asyncToGenerator(testG)
// test().then(res => console.log(res))
return new Promise((resolve, reject) => {
// 内部定义一个step函数 用来一步一步的跨过yield的阻碍
// key有next和throw两种取值,分别对应了gen的next和throw方法
// arg参数则是用来把promise resolve出来的值交给下一个yield
function step(key, arg) {
let generatorResult;

// 这个方法需要包裹在try catch中
// 如果报错了 就把promise给reject掉 外部通过.catch可以获取到错误
try {
generatorResult = gen[key](arg);
} catch (error) {
return reject(error);
}
// gen.next() 得到的结果是一个 { value, done } 的结构
const { value, done } = generatorResult;
if (done) {
// 如果已经完成了 就直接resolve这个promise
// 这个done是在最后一次调用next后才会为true
// 以本文的例子来说 此时的结果是 { done: true, value: 'success' }
// 这个value也就是generator函数最后的返回值
return resolve(value);
} else {
// 除了最后结束的时候外,每次调用gen.next()
// 其实是返回 { value: Promise, done: false } 的结构,

// 这里要注意的是Promise.resolve可以接受一个promise为参数
// 并且这个promise参数被resolve的时候,这个then才会被调用
return Promise.resolve(
// 这个value对应的是yield后面的promise
value
).then(
/*
// value这个promise被resove的时候,就会执行next
// 并且只要done不是true的时候 就会递归的往下解开promise
// 对应
gen.next().value.then(value => {
gen.next(value).value.then(value2 => {
gen.next()
// 此时done为true了 整个promise被resolve了
// 最外部的test().then(res => console.log(res))的then就开始执行了
}) */
function onResolve(val) {
step("next", val);
},
// 如果promise被reject了 就再次进入step函数
// 不同的是,这次的try catch中调用的是gen.throw(err)
// 那么自然就被catch到 然后把promise给reject掉啦
function onReject(err) {
step("throw", err);
}
);
}
}
step("next");
});
};
}
// 模拟 async 的 generator 函数
function* generatorFunc() {
yield new Promise((resolve) =>
setTimeout(() => {
console.log("Promise padding");
resolve("Promise res");
}, 100)
);
console.log("Promise end");
return "res";
}
// 使用
var asyncFn = asyncToGenerator(generatorFunc);
asyncFn().then((res) => console.log(res));

最好用的内网穿透工具合集

· 阅读需 4 分钟
Bowen Zhang
本文作者

1、ngrok

ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

官网地址:

https://ngrok.com

使用步骤:

(1)进入 ngrok 官网注册账号,并下载 ngrok。

(2)在目标机器上,填写授权码,运行 ngrok。

./ngrok authtoken 授权码

(3)将 HTTP 隧道转发到本地端口 80,如下图,通过外网域名即可访问到本地 80 端口。

./ngrok http 80

img

2、frp

frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。

git 项目地址:

https://github.com/fatedier/frp

使用步骤:

(1)将 frps 及 frps.ini 放到有公网 IP 的机器上,修改 frps.ini 文件,配置一个名为 ssh 的反向代理:

# frps.ini[common]bind_port = 7000
[ssh]listen_port=6000auth_token=123

(2)启动 frps:

./frps -c ./frps.ini

(3)将 frpc 及 frpc.ini 放到处于内网环境的机器上,修改 frpc.ini 文件,设置 frps 所在服务器的 IP 为 x.x.x.x:

# frpc.ini[common]server_addr = 192.168.172.131server_port = 7000auth_token =123
[ssh]type = tcplocal_ip = 127.0.0.1local_port = 22remote_port = 6000

(4)启动 frpc:

./frpc -c ./frpc.ini

(5)通过 ssh 访问内网服务器,假设用户名为 test:

ssh -p 6000 test@x.x.x.x

3、Sunny-Ngrok

一条命令解决的外网访问内网问题,无需任何配置,一条命令让外网访问您的内网不再是距离。Ngrok 客户端,支持 Windows、Linux、Mac,提供 python、PHP 等版本。

官网地址:

https://www.ngrok.cc

使用步骤:

(1) 开通 http 隧道,设置隧道协议、本地端口等信息。

img

(2)通过隧道 id 启动隧道。

img

(3)在公网上访问域名,即可访问到内网的网站。

img

4、Natapp

基于 ngrok 的内网映射工具,免费版本提供 http,tcp,udp 全隧道穿透、随机域名/随机 TCP,UDP 端口、不定时强制更换域名/端口和自定义本地端口。

下载地址:

https://natapp.cn

(1)购买隧道,设置隧道协议和本地端口。

img

(2)下载客户端,到目标主机,运行 natapp。

img

(3)将 natapp 分配的网址复制下来,在浏览器中访问,可以看到内网穿透成功了!

img

5、Earthworm 内网穿透

EW 是一套便携式的网络穿透工具,具有 SOCKS v5 服务架设和端口转发两大核心功能,可在复杂网络环境下完成网络穿透。

支持 Windows、Linux、MacOS、Arm-Linux。

项目地址:

http://rootkiter.com/EarthWorm

使用方法:

(1)正向 SOCKS v5 服务器,适用于目标网络边界存在公网 IP 且可任意开监听端口。

./ew -s ssocksd -l 1080

(2)反弹 SOCKS v5 服务器,适用于目标网络边界不存在公网 IP,需要通过反弹方式创建 socks 代理

a) 先在一台具有公网 ip 的主机A上运行以下命令: ./ew -s rcsocks -l 1080 -e 8888
b) 在目标主机B上启动 SOCKS v5 服务 并反弹到公网主机的 8888端口 ./ew -s rssocks -d 1.1.1.1 -e 8888

(3)多级级联,适用于多层级的复杂网络环境,将内网深层的服务转发到外网。

复制代码

## 二级级联测试用例

# 方式一:利用lcx_tran $ ./ew -s ssocksd -l 9999 $ ./ew -s lcx_tran -l 1080 -f 127.0.0.1 -g 9999
# 方式二: $ ./ew -s lcx_listen -l 1080 -e 8888 $ ./ew -s ssocksd -l 9999 $ ./ew -s lcx_slave -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999

## 三级级联测试用例
$ ./ew -s rcsocks -l 1080 -e 8888 $ ./ew -s lcx_slave -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999 $ ./ew -s lcx_listen -l 9999 -e 7777 $ ./ew -s rssocks -d 127.0.0.1 -e 7777

复制代码

6、reDuh

ReDuh 是一个通过 HTTP 协议建立隧道传输各种其他数据的工具,通过在服务器上传 JSP/PHP/ASP 脚本,就可以轻易地连接到服务器后面的主机。

github 项目地址:

https://github.com/sensepost/reDuh

(1)上传服务端 jsp 脚本到目标机器

img

(2)使用 reDuh 客户端连接服务端脚本上传后的地址。

java -jar reDuhClient.jar http://192.168.172.1/reDuh.jsp

img

7、reGeorg

reGeorg 是 reDuh 的继承者,利用了会话层的 socks5 协议,结合 Proxifier 使用效率会更高。

下载地址:

https://github.com/sensepost/reGeorg

使用方法:

(1)将 tunnel 脚本(aspx | ashx | jsp | php)上传到 Web 服务器,访问显示“Georg says, ‘All seems fine’“,表示脚本运行正常。

img

(2)在攻击者机器上,启动 reGeorgSocksProxy.py,监听 9999 端口,看到 Checking if Georg is ready,确认正常运行。

img

8、Tunna

Tunna 是一款神奇的工具,它可以通过 HTTP 封装隧道通信任何 TCP,以及用于绕过防火墙环境中的网络限制。

github 项目地址:

https://github.com/SECFORCE/Tunna

img

9、sSocks

sSocks 是一个 socks 代理工具套装,可用来开启 socks 代理服务,支持 socks5 验证,支持 IPV6 和 UDP,并提供反向 socks 代理服务,即将远程计算机作为 socks 代理服务端,反弹回本地,极大方便内网的渗透测试。

下载地址:

http://sourceforge.net/projects/ssocks/

使用方法:

(1)正向代理

./ssocksd --bind 192.168.172.131 --port 1234

(2)反向代理

## 监听6020端口转发到6010./rcsocks -l 6020 -p 6010 -vv
## 反向连接代理主机6010端口./rssocks -s 192.168.172.131:6010 -vv

Typora使用技巧

· 阅读需 1 分钟
Bowen Zhang
本文作者

typora,postman,vscode 等都是使用 electron 构建而成的桌面应用

这篇文章主要记录下 typora 日常使用中的技巧

win 命令行添加 typora 直接打开 md 文档的方法

添加 path 环境变量

C:\app\Typora\bin

新版的 typora 没有 bin 目录 那就直接C:\app\Typora

注意:添加环境变量后需要重启计算机

通过修改注册表,在右键新建菜单中添加 typora

  1. win+R 调出运行窗口,输入 regedit,弹出注册表窗口
  2. 在窗口的搜索栏中输入 Computer\HKEY_CLASSES_ROOT .md(有的可能是 计算机\HKEY_CLASSES_ROOT .md),按回车,找到.md 项
  3. 点击.md,双击右栏的默认项,弹出编辑框后在“数值数据”框中输入“Typora.md”,点击确定
  4. OpenWithProgids 查看是否有 \Typora.exe
  5. 点击.md,右键新建->项,取名“ShellNew”
  6. 点击 ShellNew,右键新建->字符串值,取名“NullFile” 至此,完成所有步骤,回到桌面刷新一下,右键新建菜单查看结果。

总结:其实就是两步 (1)修改.md 的默认值 (2)添加 ShellNew,添加 NullFile

image-20210427142049929

原文:https://blog.csdn.net/m0_46588308/article/details/105919561

Windows Termial设置

· 阅读需 5 分钟
Bowen Zhang
本文作者

安装 Windows Termial

https://github.com/microsoft/terminal

在 PowerShell 中设置 Powerline

https://docs.microsoft.com/en-us/windows/terminal/tutorials/powerline-setup

安装 Cascadia Mono PL 字体

https://github.com/microsoft/cascadia-code/releases

使用notepad $PROFILE打开编辑文本

设置启动后导入 posh-git, oh-my-posh ,

设置主题 powerline:Set-PoshPrompt paradox

Import-Module posh-git
Import-Module oh-my-posh
Set-PoshPrompt paradox

注意事项

使用 Set-Theme 会报错:Set-Theme : 无法将“Set-Theme”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。

原因:oh-my-posh v3 不支持 Set-Theme 命令 ,需要使用 Set-PoshPrompt -Theme xxx

解决方案:https://www.icode9.com/content-4-866063.html

官网介绍:https://ohmyposh.dev/docs/upgrading/

官方是使用 Get-PoshThemes 查看支持主题;

分屏操作

https://docs.microsoft.com/zh-cn/windows/terminal/panes

配置

settting.json

// This file was initially generated by Windows Terminal 1.6.10571.0
// It should still be usable in newer versions, but newer versions might have additional
// settings, help text, or changes that you will not see unless you clear this file
// and let us generate a new one for you.

// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation
{
"$schema": "https://aka.ms/terminal-profiles-schema",

"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

// You can add more global application settings here.
// To learn more about global settings, visit https://aka.ms/terminal-global-settings

// If enabled, selections are automatically copied to your clipboard.
"copyOnSelect": true,

// If enabled, formatted data is also copied to your clipboard
"copyFormatting": true,

// A profile specifies a command to execute paired with information about how it should look and feel.
// Each one of them will appear in the 'New Tab' dropdown,
// and can be invoked from the commandline with `wt.exe -p xxx`
// To learn more about profiles, visit https://aka.ms/terminal-profile-settings
"profiles": {
"defaults": {
// Put settings here that you want to apply to all profiles.
"startingDirectory": null,
"fontFace": "MesloLGM Nerd Font",
"fontSize": 12
},
"list": [
{
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false,
// 浅色主题
// "acrylicOpacity": 0.7,
// "colorScheme" : "Frost",
// "cursorColor" : "#000000",
// "fontFace" : "Cascadia Code PL",
// "useAcrylic": true
// 深色主题
"acrylicOpacity": 0.7,
"colorScheme": "Vintage",
"cursorColor": "#FFFFFD",
"fontFace": "MesloLGM Nerd Font",
"useAcrylic": true
},
{
"guid": "{3ef3d962-7a99-4b13-93b6-b92a4d42a2e0}",
"hidden": false,
"name": "bash",
"commandline": "C:\\Program Files\\Git\\bin\\bash.exe",
"colorScheme": "Raspberry",
"cursorColor": "#FFFFFF",
// "fontFace" : "Cascadia Code PL",
"padding": "5, 5, 5, 5",
"suppressApplicationTitle": true,
"tabTitle": "bash"
},
{
// Make changes here to the cmd.exe profile.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "命令提示符",
"commandline": "cmd.exe",
"hidden": false,
"closeOnExit": true,
"colorScheme": "Retro",
"cursorColor": "#FFFFFF",
"cursorShape": "filledBox",
"fontSize": 16,
"padding": "5, 5, 5, 5",
"tabTitle": "Command Prompt",
"fontFace": "PxPlus IBM VGA8",
"experimental.retroTerminalEffect": true
},
{
"guid": "{2c4de342-38b7-51cf-b940-2309a097f518}",
"hidden": false,
"name": "Ubuntu",
// "source": "Windows.Terminal.Wsl",
"colorScheme": "Raspberry",
"cursorColor": "#FFFFFF",
"fontFace": "MesloLGM Nerd Font",
"padding": "5, 5, 5, 5",
"suppressApplicationTitle": true,
"tabTitle": "Ubuntu"
},
{
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"hidden": false,
"name": "PowerShell",
"source": "Windows.Terminal.PowershellCore",
"acrylicOpacity": 0.7,
"colorScheme": "Vintage",
"cursorColor": "#FFFFFD",
"fontFace": "MesloLGM Nerd Font",
"useAcrylic": true
},
{
"guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
"hidden": true,
"name": "Azure Cloud Shell",
"source": "Windows.Terminal.Azure"
}
]
},

// Add custom color schemes to this array.
// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes
"schemes": [
// 毛玻璃
{
"name": "Frost",
"background": "#FFFFFF",
"black": "#3C5712",
"blue": "#17b2ff",
"brightBlack": "#749B36",
"brightBlue": "#27B2F6",
"brightCyan": "#13A8C0",
"brightGreen": "#89AF50",
"brightPurple": "#F2A20A",
"brightRed": "#F49B36",
"brightWhite": "#741274",
"brightYellow": "#991070",
"cyan": "#3C96A6",
"foreground": "#000000",
"green": "#6AAE08",
"purple": "#991070",
"red": "#8D0C0C",
"white": "#6E386E",
"yellow": "#991070"
},
// 复古
{
"name": "Retro",
"background": "#000000",
"black": "#00ff00",
"blue": "#00ff00",
"brightBlack": "#00ff00",
"brightBlue": "#00ff00",
"brightCyan": "#00ff00",
"brightGreen": "#00ff00",
"brightPurple": "#00ff00",
"brightRed": "#00ff00",
"brightWhite": "#00ff00",
"brightYellow": "#00ff00",
"cyan": "#00ff00",
"foreground": "#00ff00",
"green": "#00ff00",
"purple": "#00ff00",
"red": "#00ff00",
"white": "#00ff00",
"yellow": "#00ff00"
},
// ubuntu
{
"name": "Raspberry",
"background": "#3C0315",
"black": "#282A2E",
"blue": "#0170C5",
"brightBlack": "#676E7A",
"brightBlue": "#80c8ff",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76",
"cyan": "#3F8D83",
"foreground": "#FFFFFD",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48"
}
],

// Add custom actions and keybindings to this array.
// To unbind a key combination from your defaults.json, set the command to "unbound".
// To learn more about actions and keybindings, visit https://aka.ms/terminal-keybindings
"actions": [
// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.
// These two lines additionally bind them to Ctrl+C and Ctrl+V.
// To learn more about selection, visit https://aka.ms/terminal-selection
{ "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+c" },
{ "command": "paste", "keys": "ctrl+v" },

// Press Ctrl+Shift+F to open the search box
{ "command": "find", "keys": "ctrl+f" },
{ "command": "duplicateTab", "keys": "ctrl+shift+d" },
// Press Alt+Shift+D to open a new pane.
// - "split": "auto" makes this pane open in the direction that provides the most surface area.
// - "splitMode": "duplicate" makes the new pane use the focused pane's profile.
// To learn more about panes, visit https://aka.ms/terminal-panes
{
"command": {
"action": "splitPane",
"split": "vertical",
"splitMode": "duplicate"
},
"keys": "shift+tab"
},
{
"command": {
"action": "splitPane",
"split": "horizontal",
"splitMode": "duplicate"
},
"keys": "alt+shift+-"
},
{
"command": {
"action": "splitPane",
"split": "auto",
"splitMode": "duplicate"
},
"keys": "alt+shift+d"
},
{ "command": "closePane", "keys": "shift+w" }
]
}

添加注册列表(右键菜单)

https://blog.csdn.net/u011532601/article/details/106305373/

使用别人写好的 bat 程序

下载地址:https://github.com/BroJenuel/Explorer-Context-Menu-Integration-for-windows-terminal

手动配置右键打开

  • Win+R 输入 regedit 进入注册表目录 HKEY_CLASSES_ROOT\Directory\Background\shell

在这里新建一个项命名为 WT 并设置(默认)值为你想要的名称,比如 Windows Terminal Here

  • 再新建字符串值 Icon 即显示图标,并将值设设置 C:\ProgramFiles\WindowsApps\Microsoft.WindowsTerminal`version`\WindowsTerminal.exe

    Win10 系统下 WindowsApps 文件夹拒绝访问如何获取权限:

    http://www.xitongcheng.com/jiaocheng/win10_article_45151.html

  • 注意:version值看你安装的具体版本,可通过 Everything 搜索查证,或者设置为 cmd 的图标 C:\Windows\System32\cmd.exe 免去更新的麻烦,再或者设置你自己的图标,这个不影响使用

  • 如有需要的话可以将这个命令置顶,则添加新字符串值 Position,值为 Top

  • 然后再新建一个项 command,默认值%USERPROFILE%\AppData\Local\Microsoft\WindowsApps\wt.exe

  • 注意:如失效,可将%USERPROFILE%改为指定用户目录如 C:\Users`username,并注销重启,username`记得改成自己的用户名

一般出现 explorer.exe 错误多是没有用管理员权限写入导致的

注意:自动添加的右键菜单会出现复制窗口但工作目录变的情况

删除程序自带的右键菜单

github 上有对应的 issues:https://github.com/microsoft/terminal/issues/8105

😓 看来大家都不喜欢程序自动添加的右键菜单

完成后记得重新启动资源管理器

问题:

https://github.com/microsoft/terminal/issues/9806

powershell.exe 中的普通空格

image-20210414173814189

在 Windows terminal 中空格变成 

image-20210414172703793

解决

更换Oh my Posh官方推荐字体:https://ohmyposh.dev/docs/fonts/

使用Meslo LGM NF

image03

setting.json

"fontFace" : "MesloLGM Nerd Font",

修改 vscode 终端字体

setting.json

"terminal.integrated.fontFamily": "MesloLGSDZ Nerd Font"

注意:vscode 只能使用等宽字体 所以得单独设置

Git bash 乱码问题

解决:https://www.cnblogs.com/ssrs-wanghao/articles/9216955.html

我就用下面命令一下解决

git config --global core.quotepath false

picgo + typroa + smms|github|gitee 实现自动上传图床

· 阅读需 1 分钟
Bowen Zhang
本文作者

typora 结合 PicGo 设置 github 图床

详细教程:https://blog.csdn.net/beichuchuanyue/article/details/105493948

最近一直在用 ubuntu 所以令行) 实现直接使用 picgo-core (命上传图片

picgo-core 配置文件

如果配置好了 picgo app 直接把 iconfig 粘进来就行

{
"picBed": {
"current": "github",
// 具体配置
"github": {
"branch": "分支",
"customUrl": "https://raw.githubusercontent.com/用户名/仓库/分支",
"path": "img/", //具体文件夹`路径/`
"repo": "zhangbowen-github/my-gallery", // `/用户名/仓库`
"token": "sdfasdfasdfasdf" //Settings -> Developer settings -> Personal access tokens->创建 全选
},
"uploader": "github"
},
"settings": {
"shortKey": {
"picgo:upload": {
"enable": true,
"key": "CommandOrControl+Shift+P",
"name": "upload",
"label": "快捷上传"
}
},
"server": {
"enable": true,
"host": "127.0.0.1",
"port": 36677 //端口号不要改
},
"showUpdateTip": true,
"pasteStyle": "markdown",
"autoRename": true,
"rename": false,
"autoStart": true,
"miniWindowOntop": false,
"checkBetaUpdate": true
},
"picgoPlugins": {},
"debug": true,
"PICGO_ENV": "GUI",
"needReload": false
}

注意上传同名图片会导致失败

常见报错:https://blog.csdn.net/qq754772661/article/details/111385955

PicGo 设置 gitee(码云)图床

详细教程

// 具体配置
"gitee": {
"branch": "master",
"customPath": "default",
"customUrl": "https://gitee.com/zhangbowen-1/my-gallery/raw/master",
"path": "/img",// `/路径`
"repo": "zhangbowen-1/my-gallery/img",// `/用户名/仓库/路径`
"token": "asdfasdfdfasdfasdfsadfasd" // 设置-》私人令牌-》生产新令牌
}

typora 结合 PicGo 设置 smms 图床

  • smms 注册账号
  • smms Dashboard 找到 API Token 获取 token
  • npm 全局安装 picgo
  • 修改 picgo 配置文件
  • 修改 typora 设置偏好 图像 上传服务设定 修改为 自定义命令 (custom command) 命令 :picgo upload