Mr. Panda
Tech For Fun

栈溢出( Sunday, September 19, 2021)

栈溢出系列文章——解决技术问题,积累开发经验。

本期内容包括:React: 怎么修复 useRef “Cannot Assign to … Read Only Property” 的错误?、TypeScript:ts-node直接运行typescript文件等。

React: 怎么修复 useRef “Cannot Assign to ... Read Only Property” 的错误?

如果你遇到了这种错误,很有可能是 useRef 的值的类型被定义成了 React.RefObject,因为 React.RefObject 会将 current 引用定义为 readonly。

interface RefObject<T> {
  readonly current: T | null;
}

查看 React 中 useRef 的类型可以看到如下 3 中重载(overload):

function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T | null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;

interface MutableRefObject<T> {
  current: T;
}

什么情况下 TS 会将 useRef 推断为 RefObject 类型呢?

  1. useRef 的初始值为null;
  2. cuurent 属性的类型被初始化为一个确定的类型。

例如:

const elem = useRef<HTMLDivElement>(null);
type Test = typeof elem; // Test = React.RefObject<HTMLDivElement>

修复这种问题的方式就是将 useRef 定义为可修改的。可以通过在 useRef 类型定义中添加 null 类型来解决问题。

const elem = useRef<HTMLDivElement | null>(null);
type Test = typeof elem; // Test = React.MutableRefObject<HTMLDivElement|null>

TypeScript:ts-node直接运行typescript文件

正常 ts 文件都要编译成 js 文件才能运行,但是在开发时有时需要运行 ts 文件,可通过 ts-node 直接运行 ts 文件。

//全局安装typescript和ts-node
npm install -g typescript
//npm install -g typescript-node 由于typescript-node不支持更高版本的ts
npm install -g ts-node //typescript@>=2.7

ts-node foo.ts

TypeScript:`(...args: never[]) => void` 和 `(...args: any[]) => void`的含义

  • (…args: never[]) => void: 意思是函数不接受任何参数。
  • (…args: any[]) => void:意思是函数可接受任意参数。

参见:

Mac: 解决 homebrew 下载过慢问题

使用国内镜像源替换homebrew镜像源。把三个仓库地址全部替换成国内Alibaba提供的地址:

  • 替换/还原brew.git仓库地址
# 替换成阿里巴巴的 brew.git 仓库地址:
cd "$(brew --repo)"
git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git
 
#=======================================================
 
# 还原为官方提供的 brew.git 仓库地址
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git
  • 替换/还原homebrew-core.git仓库地址
替换成阿里巴巴的 homebrew-core.git 仓库地址:
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git
=======================================================
还原为官方提供的 homebrew-core.git 仓库地址
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git
  • 替换/还原homebrew-bottles

这个步骤跟你的macOs系统使用的shell版本有关系,首先查看shell版本

echo $SHELL

如果你的输出结果是 /bin/zsh,参考?的 zsh 终端操作方式
如果你的输出结果是 /bin/bash,参考?的 bash 终端操作方式

  • zsh终端操作方式
# 替换成阿里巴巴的 homebrew-bottles 访问地址:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc
 
#=======================================================
 
# 还原为官方提供的 homebrew-bottles 访问地址
vi ~/.zshrc
# 然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.zshrc
  • bash终端操作方式
# 替换 homebrew-bottles 访问 URL: 
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile
 
#=======================================================
 
# 还原为官方提供的 homebrew-bottles 访问地址
vi ~/.bash_profile
# 然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.bash_profile

JavaScript: call(),apply() 和 bind()

call

  • 功能:执行 function、明确指定 this 指向。
  • 语法:fn.call(this, arg1, arg2..., argn)。
  • 使用情境:需要明确指定 this 的指向。

apply

apply 和 call 功能和场景使用一样,不同的是 apply 可以以数组的方式传参。

语法:fn.apply(this, [arg1, arg2..., argn])

bind

  • 功能:明确指定 this 指向、返回一个函数(注意:bind 不会执行此函数)。
  • 语法:fn.bind(this, arg1, arg2..., argn)。
  • bind 除了可以明确指定 this 指向之外,还可以预先传入一些参数给目标方法(类似于 Currying Function)。当我们需要先记住部分参数或者对不断传入固定参数给方法是,可以使用 bind 起到简化语法的作用。
  • bind polyfill
function bind(t, callback) {
  var outerArgs = Array.from(arguments).slice(2);
  return function () {
    var innerArgs = Array.from(arguments);
    return callback.apply(t, outerArgs.concat(innerArgs));
  };
}

function add() {
  return Array.from(arguments).reduce(function (sum, num) {
    return sum + num;
  });
}

var addWithBind = bind(null, add, 1, 5);
console.log(addWithBind(8)); // 14

URL Scheme: h5通过 URL Scheme 打开本地app

链接格式

<a href="[scheme]://[host]/[path]?[query]"> 唤起应用 </a>
  • scheme (唤起协议)和host(唤起指定host)是必须存在的,并且要保证scheme和host和原生应用内是一致的。
  • 后面的path(协议路径)和query(参数)可以没有。
  • 需要应用进行对应处理才能打开本地app。

常见 URL Scheme

  • 系统默认应用
名称URL SchemeBundle identifier
Safarihttp://
mapshttp://maps.google.com
Phonetel://
SMSsms://
Mailmailto://
iBooksibooks://
App Storeitms-apps://itunes.apple.com
Musicmusic://
Videosvideos://
系统默认应用常见 URL Scheme
  • 第三方软件
名称URL SchemeBundle identifier
QQmqq://
微信weixin://
腾讯微博TencentWeibo://
淘宝taobao://
支付宝alipay://
微博sinaweibo://
weico微博weico://
QQ浏览器mqqbrowser://com.tencent.mttlite
uc浏览器dolphin://com.dolphin.browser.iphone.chinese
欧朋浏览器ohttp://com.oupeng.mini
搜狗浏览器SogouMSE://com.sogou.SogouExplorerMobile
百度地图baidumap://com.baidu.map
Chromegooglechrome://
优酷youku://
京东openapp.jdmoble://
人人renren://
美团imeituan://
1号店wccbyihaodian://
我查查wcc://
有道词典yddictproapp://
知乎zhihu://
点评dianping://
微盘sinavdisk://
豆瓣fmdoubanradio://
网易公开课ntesopen://
名片全能王camcard://
QQ音乐qqmusic://
腾讯视频tenvideo://
豆瓣电影doubanmovie://
网易云音乐orpheus://
网易新闻newsapp://
网易应用apper://
网易彩票ntescaipiao://
有道云笔记youdaonote://
多看duokan-reader://
全国空气质量指数dirtybeijing://
百度音乐baidumusic://
下厨房xcfapp://
第三方软件常见 URL Scheme

VSCode: 添加自定义代码段

参见:[VS Code]跟我一起在Visual Studio Code 添加自定义snippet(代码段),附详细配置

Mac: 自定义快捷键打开应用程序

参见:在Mac OS X 自定义快捷键打开应用

Mac: 使用终端打开应用程序

打开任意路径下的一个应用程序

打开命令通常需要你在当前路径中输入完整的文件路径。但是,在打开命令的后面加上-a,会让终端打开这个应用程序。

# 如果想要打开iTunes程序:
open -a iTunes
# 如果应用程序的名字中存在空格,请使用引号:
open -a "App Store"

使用特定的应用程序来打开一个文件

输入文件路径和文件名,后面加上-a和应用程序的名字。

# 使用文本编辑器来打开一个.doc文件:
open Downloads/Instructions.doc -a TextEdit


添加额外的选项

输入info open来查看修改打开命令的选项列表,info 是 Linux 命令,作用是查看命令帮助信息。

# 使用-e来指定“文本编辑器”,-t代表默认的文本程序:
open Downloads/Instructions.doc -e
# 加上-g选项会让应用程序留在后台,这样你就会继续停留在终端程序中:
open -g -a iTunes

参见:如何在Mac电脑上使用终端打开应用程序

VSCode: ctrl+s 后会在当前目录下自动生成dist目录

解决办法:关闭compile-hero插件。

Git: Git 撤销和回滚操作

参见:Git撤销&回滚操作

Yarn: yarn 安装 node-sass 速度缓慢

# 配置 node-sass 的二进制包镜像地址为淘宝源
yarn(npm) config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g

TypeScript: TypeScript "Cannot Find CSS/SCSS Module"

在项目中添加 declarations.d.ts 文件:

// We need to tell TypeScript that when we write "import styles from './styles.scss' we mean to load a module (to look for a './styles.scss.d.ts'). 
declare module '*.scss'; 

参见:Can't import CSS/SCSS modules. TypeScript says "Cannot Find Module"

Git: 更换远程仓库地址

方法一 : 通过命令直接修改远程仓库地址
git remote 查看所有远程仓库
git remote xxx 查看指定远程仓库地址
git remote set-url origin 你新的远程仓库地址

方法二: 先删除在添加你的远程仓库
git remote rm origin
git remote add origin 你的新远程仓库地址

Yarn: 创建yarn.lock文件

yarn install --update-checksums

Mac: 查看已连接的WI-FI密码

  1. 打开 Keychain Access.app;
  2. 搜索 wifi 名称;
  3. 右键:将密码拷贝到剪贴板。

CSS:隐藏滚动条并可以滚动内容

// webkit
.element::-webkit-scrollbar { width: 0 !important }
// IE 10+
.element { -ms-overflow-style: none; }
// Firefox
.element { overflow: -moz-scrollbars-none; }

CSS: 数字字母自动换行

汉字会自动换行,但数字和字母不会换行的解决办法:

word-break:break-all或word-wrap:break-word。

CSS: 高度随宽度比例变化

padding-bottom 实现

  • padding 设置为百分比时是相对于父元素宽度而言的。
  • 可以使用百分比的 padding-bottom 代替 height 来实现高度与宽度成比例的效果。
  • 将 padding-bottom 设置为想要实现的 height 的值,同时将 height 设置为 0 以使元素的“高度”等于 padding-bottom 的值。

隐藏的图片

  • div 容器如果不给定高度,它的高度会随着容器内部的元素变化而变化。
  • 在容器内部添加一张符合宽高比例的图片,给图片设置宽度100%,高度auto。
  • 图片只设置宽度的话,高度会随宽度来进行比例变化,这样内部的子容器的高度也会按照比例缩放。
  • 图片占位隐藏,也可以用别的盒子覆盖上。
  • 这种方法不需要考虑任何兼容性。由于图片只需要一个形状,可以使用 base64图片来减少 http 请求。

vw 和 vh

将父容器的宽度和高度定义为相同的vw,这样父容器的高度和宽度就是相同值,子容器的宽高值设为百分比,不管父容器大小如何变,子容器的高度和宽s度比都是不会变的。

  • vw: 相对于视窗的宽度
  • vh: 相对于视窗的高度
  • vmin: 相对于视口的宽度或高度中较小的
  • vmax:相对于视口的宽度或高度中较大的

Jonsam

一个理科IT宅男,喜欢旅游、分享和美食,做点想做的事情,遇见想见的人。

🍒 美食 | 🌐 FE | 🕌 旅行 | 💻 加班 | ♍ 处女座

jonsam ng

jonsam ng

文章作者

海阔凭鱼跃,天高任鸟飞。

栈溢出( Sunday, September 19, 2021)
栈溢出系列文章——解决技术问题,积累开发经验。 本期内容包括:React: 怎么修复 useRef “Cannot Assign to … Read Only Property” 的错误?、TypeScript:ts-node直接运行typescript文…
扫描二维码继续阅读
2021-09-19