首页
归档
关于
友人帐
Search
1
Mac OS 终端利器 iTerm2 + Oh My Zsh
12,063 阅读
2
前端 History 路由及 API 反向代理的 Nginx 配置
9,913 阅读
3
解决 Xcode Command Line Tools 错误或无法安装问题
3,975 阅读
4
Mac下右键使用VSCode打开项目
3,283 阅读
5
Nodejs 爬取one和墨迹天气定时发邮件
2,968 阅读
码上世界
内容分享
生活印记
其他
登录
Search
羽叶
累计撰写
82
篇文章
累计收到
158
条评论
首页
栏目
码上世界
内容分享
生活印记
其他
页面
归档
关于
友人帐
搜索到
82
篇与
羽叶
的结果
2022-03-11
JS 判断带 emoji 的字符串长度的究极方法
历史的坑JS 的字符串长度是个奇怪的设定,很多编程语言,获取字符串的长度是得到 字节长度,比如一个正常的汉字是两个字节,但在 js 中,'汉'.length 是 1 。看上去很方便,殊不知,这个特性埋下的坑。比如:😀 : '😀'.length 得到的是 2𠮷 : '𠮷''.length 得到的也是 2JS 内部字符以 UTF-16 的格式储存 (一种兼容 utf-8,但可储存编码比utf-8多8位),简单点说,就是最多存 16 位的编码,但中华文化博大精深,字太多了,有些字排到后面,都不只 16 位编码了,于是,在 js 中只能用 2 个 utf-16 来储存,于是,这个𠮷这就被 js 当成长度为 2 了。生辟字很少见的,但 emoji 不少见啊,还很流行,关键的是,大多都是 编码超过 16 位,也就是说 js 中长度不止为 1 可能有的 emoji 长度为 2 都不止。比如这个 👨👩👧👧 ,运行 '👨👩👧👧'.length 在 js 中 答案为 11 , 这里不去深究 Emoji 的历史了,有兴趣可以去了解下。解决办法那在需求中,比如评论输入框中 限定 20 的字符, 很明显 直接用 length 判断长度 ,用户两个 emoji 就不够了,显然不能满足需求其他一些 for ... of 和 codePointAt 方法在一些情况下是可以解决长度问题,但在 组合 emoji 中就无能为力了弊端的实现function length(s) { let len = 0; for (let i = 0; i < s.length; i++) { len++; // 0xffff 是16进制,一个f相当4位二进制,4个f就是16位 if (s.codePointAt(i) > 0xffff) i++; } return len; }length("😀"); //1 length("𠮷"); //1这个方法一些情况可以获取真实长度,但是在 组合 emoji 比如 👨👩👧👧 就会有问题。length("👨👩👧👧"); // 7 很明显不对究极解决这里需要引入 lodash 的 toArray 方法 转成数组 再获取数组的长度有兴趣的可以去 https://github.com/lodash/lodash/blob/master/toArray.js 源码了解它的实现 这里先不去深究了function trueLength(str) { return _.toArray(str).length; }不想引入loadsh 我这边根据源码重新写了一个const countStrLen = (string) => { const reUnicode = /\ud83c[\udffb-\udfff](?=\ud83c[\udffb-\udfff])|(?:[^\ud800-\udfff][\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]?|[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|\ud83c[\udffb-\udfff])?)*/g; return (string.match(reUnicode) || []).length } countStrLen('👨👩👧👧') //1或者直接挂载在原型链上String.prototype.countLengtn = function() { const reUnicode = /\ud83c[\udffb-\udfff](?=\ud83c[\udffb-\udfff])|(?:[^\ud800-\udfff][\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]?|[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe2f\u20d0-\u20ff\u1ab0-\u1aff\u1dc0-\u1dff]|\ud83c[\udffb-\udfff])?)*/g; return (this.toString().match(reUnicode) || []).length } "𠮷👨👩👧👧👨👩👧👧😀𠮷".countLengtn() // 5
2022年03月11日
52 阅读
1 评论
2 点赞
2022-03-08
JS 循环里如何使用多个异步
循环里多个异步串行运行方法for 循环const items = [3000, 2000, 1000, 4000]; const testPromise = (param) => { return new Promise((resolve) => { setTimeout(() => { console.log( `时间(s):${Math.floor(Date.now() / 1000)},结果:${param} ` ); resolve(); }, param); }); }; (async () => { console.log(`开始时间(s):${Math.floor(Date.now() / 1000)}`); for (let item of items) { await testPromise(item); } console.log(`结束时间(s):${Math.floor(Date.now() / 1000)}`); })();reduce 方法const items = [3000, 2000, 1000, 4000]; const testPromise = (param) => { return new Promise((resolve) => { setTimeout(() => { console.log( `时间(s):${Math.floor(Date.now() / 1000)},结果:${param} ` ); resolve(); }, param); }); }; (async () => { console.log(`开始时间(s):${Math.floor(Date.now() / 1000)}`); const result = items.reduce((resPromise, next) => { return resPromise.then(() => { return testPromise(next); }); }, Promise.resolve()); result.then(() => { console.log(`结束时间(s):${Math.floor(Date.now() / 1000)}`); }); })();这里异步生成器的方法,但是实现不是很简约,就不展示了!多个异步并行运行方法这里使用 promise.all()const items = [3000, 2000, 1000, 4000]; const testPromise = (param) => { return new Promise((resolve) => { setTimeout(() => { console.log( `时间(s):${Math.floor(Date.now() / 1000)},结果:${param} ` ); resolve(); }, param); }); }; (async () => { const promises = items.map((item) => { return testPromise(item); }); await Promise.all(promises); })();
2022年03月08日
29 阅读
0 评论
0 点赞
2022-01-24
国内 jsDelivr 已死,网站资源该何去何从?
jsDelivr 备案吊销后,网站资源该何去何从?最近发现许多网站(包括本站点)加载时间已经超出平常。之前是 Jsdelivr CDN 的 SSL 证书过期了,导致服务断了很长时间。然而不知何种原因,jsDelivr 的域名备案在 2021 年 12 月 20 日被吊销,导致国内的 CDN 提供商网宿移除了 jsDelivr。现在 jsDelivr 的国内线路为 Fastly 提供, 所以现在的速度相比之前慢了许多。国内部分替代加速平台https://cdn.baomitu.comhttp://staticfile.orghttps://www.bootcdn.cn
2022年01月24日
96 阅读
2 评论
0 点赞
2021-12-06
解决网页无法复制和无右键菜单问题
解决 如 CSDN 网站无法复制的问题将下面链接鼠标拖入到浏览器书签栏,然后再不能复制的网页,点击该书签即可!🔓解除网页限制测试:该文字不可复制,点击运行书签即可复制
2021年12月06日
38 阅读
0 评论
2 点赞
2021-11-21
闲置域名出售
闲置域名出售出一些闲置域名,有意可发邮件 点此发邮件域名状态价格xxkid.com已卖出--dva.cool可购买议价bili.icu可购买议价bsset.com已卖出--gtwar.com可购买议价imgbao.com可购买议价voicenice.com可购买议价
2021年11月21日
50 阅读
1 评论
0 点赞
2021-10-17
如何同步淘宝镜像中 npm 包
因为淘宝镜像的存在,国内访问速度快了 但也存在一些问题 同步不及时那如何快速同步自己需要的包呢步骤找到需要同步包的名字 这边假设 包名字为 vite 访问淘宝镜像包同步地址 https://npmmirror.com/sync/{包的名字} 如上假设包名字为 vite 则访问 https://npmmirror.com/sync/vite 就可以同步了
2021年10月17日
138 阅读
1 评论
0 点赞
2021-10-11
目前可用的二维码 api 服务接口
汇集了目前可用的二维码 api 服务接口{alert type="warning"}每个都有二维码示例图,如果示例图不可见 则该服务已挂掉{/alert}青旨 API 提供https://api.tqz.ink/api/qrcode?text=https://yuye.fun&size=200示例:韩小韩 APIhttps://api.vvhan.com/api/qr?text=https://www.yuye.fun示例:网易 lofter 二维码 api 接口https://www.lofter.com/genBitmaxImage?url=https://www.yuye.fun示例:qrcode 提供的二维码 api, s=1-20 可更改尺寸 国外服务https://qrcode.jp/qr?q=https://www.yuye.fun&s=10示例:qrserver 提供的二维码 api,国外服务https://api.qrserver.com/v1/create-qr-code/?size=100×100&data=https://www.yuye.fun示例:kegood 提供的二维码 api 服务调用参数说明:url: 二维码对应的网址或需要生成二维码的信息m : 二维码白色边框尺寸,缺省值: 0pxe : 容错级别(errorLevel),可选参数如下(缺省值 L):L水平 7%的字码可被修正M水平 15%的字码可被修正Q水平 25%的字码可被修正H水平 30%的字码可被修正p : 二维码尺寸,可选范围1-10(具体大小和容错级别有关)(缺省值:3)https://qrs.kegood.com/?m=1&e=L&p=10&url=https://www.yuye.fun示例:api.pwmqr.comhttps://api.pwmqr.com/qrcode/create/?url=https://www.yuye.fun示例:
2021年10月11日
191 阅读
4 评论
0 点赞
2021-10-11
下载新版Edge离线安装包
微软官方的下载直链,点击即可下载当前正式版最新离线安装包:64位:https://go.microsoft.com/fwlink/?LinkID=209343732位:https://go.microsoft.com/fwlink/?LinkID=2093505或者使用商业版如下地址选择喜欢的版本下载:https://www.microsoft.com/zh-cn/edge/business/download
2021年10月11日
154 阅读
1 评论
0 点赞
2021-10-11
下载 chrome 离线安装包
特殊情况需要下载 Chrome 离线安装包, 一般下载的都是在线安装 很不方便默认安装模式下下载下来的是一个触发在线安装的程序,自动加载下载然后安装,但是这样有时候非常慢,或者有时候无法联网,所以最好还是安装离线完整的版本方法1、打开 Chrome 浏览器主页:https://www.google.cn/chrome/2、在网址最后加上:?standalone=1&platform=win64,也就是 https://www.google.cn/chrome/?standalone=1&platform=win64 回车键后打开的是 64位下载页面,点击“下载Chrome”按钮,得到的就是 Google Chrome 64位离线安装包其中 ?standalone=1 指离线安装包,platform=win64 指64位Windows 版本。如果加上的只是?standalone=1可以用来下载32位的Chrome离线包。用mac替换win,就可以下载 Mac 版本的了。
2021年10月11日
60 阅读
0 评论
0 点赞
2021-09-14
跨浏览器窗口通讯的7种方式
演示和源码多页面通讯的demo, 为了正常运行,请用最新的chrome浏览器打开。 demo地址demo的源码地址两个浏览器窗口间通信WebSocket这个没有太多解释,WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。当然是有代价的,需要服务器来支持。 js语言,现在比较成熟稳定当然是 socket.io和ws. 也还有轻量级的ClusterWS。你可以在The WebSocket API (WebSockets) 看到更多的关于Web Socket的信息。定时器 + 客户端存储定时器:setTimeout/setInterval/requestAnimationFrame 客户端存储: cookie/localStorage/sessionStorage/indexDB/chrome的FileSystem定时器没啥好说的,关于客户端存储。cookie: 每次会带到服务端,并且能存的并不大,4kb?,记得不太清楚localStorage/sessionStorage 应该是5MB, sessionStorage关闭浏览器就和你说拜拜。indexDB 这玩意就强大了,不过读取都是异步的,还能存 Blob文件,真的是很high。chrome的FileSystem ,Filesystem \& FileWriter API,主要是chrome和opera支持。这玩意就是文件系统。postMessageCross-document messaging 这玩意的支持率98.9\%。 好像还能发送文件,哈哈,强大。 不过仔细一看 window.postMessage(),就注定了你首先得拿到window这个对象。 也注定他使用的限制, 两个窗体必须建立起联系。 常见建立联系的方式:window.openwindow.openeriframe提到上面的window.open, open后你能获得被打开窗体的句柄,当然也可以直接操作窗体了。到这里,我觉得一般的前端人员能想到的比较正经的方案应该是上面三种啦。 当然,我们接下来说说可能不是那么常见的另外三种方式。StorageEventPage 1localStorage.setItem('message',JSON.stringify({ message: '消息', from: 'Page 1', date: Date.now() })Page 2window.addEventListener("storage", function(e) { console.log(e.key, e.newValue, e.oldValue) })如上, Page 1设置消息, Page 2注册storage事件,就能监听到数据的变化啦。上面的e就是StorageEvent,有下面特有的属性(都是只读):key :代表属性名发生变化.当被clear()方法清除之后所有属性名变为nullnewValue:新添加进的值.当被clear()方法执行过或者键名已被删除时值为nulloldValue:原始值.而被clear()方法执行过,或在设置新值之前并没有设置初始值时则返回nullstorageArea:被操作的storage对象url:key发生改变的对象所在文档的URL地址Broadcast Channel这玩意主要就是给多窗口用的,Service Woker也可以使用。 firefox,chrome, Opera均支持,有时候真的是很讨厌Safari,浏览器支持77\%左右。使用起来也很简单, 创建BroadcastChannel, 然后监听事件。 只需要注意一点,渠道名称一致就可以。 Page 1 var channel = new BroadcastChannel("channel-BroadcastChannel"); channel.postMessage('Hello, BroadcastChannel!'Page 2 var channel = new BroadcastChannel("channel-BroadcastChannel"); channel.addEventListener("message", function(ev) { console.log(ev.data) })SharedWorker这是Web Worker之后出来的共享的Worker,不通页面可以共享这个Worker。 MDN这里给了一个比较完整的例子simple-shared-worker。这里来个插曲,Safari有几个版本支持这个特性,后来又不支持啦,还是你Safari,真是6。虽然,SharedWorker本身的资源是共享的,但是要想达到多页面的互相通讯,那还是要做一些手脚的。 先看看MDN给出的例子的ShareWoker本身的代码:onconnect = function(e) { var port = e.ports[0]; port.onmessage = function(e) { var workerResult = 'Result: ' + (e.data[0] * e.data[1]); port.postMessage(workerResult); } 上面的代码其实很简单,port是关键,这个port就是和各个页面通讯的主宰者,既然SharedWorker资源是共享的,那好办,把port存起来就是啦。 看一下,如下改造的代码: SharedWorker就成为一个纯粹的订阅发布者啦,哈哈。var portList = []; onconnect = function(e) { var port = e.ports[0]; ensurePorts(port); port.onmessage = function(e) { var data = e.data; disptach(port, data); }; port.start(); }; function ensurePorts(port) { if (portList.indexOf(port) < 0) { portList.push(port); } } function disptach(selfPort, data) { portList .filter(port => selfPort !== port) .forEach(port => port.postMessage(data)); }MessageChannelChannel Messaging API的 MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据。其需要先通过 postMessage先建立联系。MessageChannel的基本使用:var channel = new MessageChannel(); var para = document.querySelector('p'); var ifr = document.querySelector('iframe'); var otherWindow = ifr.contentWindow; ifr.addEventListener("load", iframeLoaded, false); function iframeLoaded() { otherWindow.postMessage('Hello from the main page!', '*', [channel.port2]); } channel.port1.onmessage = handleMessage; function handleMessage(e) { para.innerHTML = e.data; } 至于在线的例子,MDN官方有一个版本 MessageChannel 通讯
2021年09月14日
134 阅读
3 评论
0 点赞
1
2
...
9