Skip to main content

树莓派4b更换清华源(buster)

· One min read

解决方案

修改`/etc/apt/sources.list.d/raspi.list`

deb http://mirrors.tuna.tsinghua.edu.cn/raspberry-pi-os/raspbian/ buster main non-free contrib rpi 
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspberry-pi-os/raspbian/ buster main non-free contrib rpi

修改之后更新`sudo apt update`

docker常用命令

· One min read

docker常用命令

#列出镜像
docker images
#删除镜像
docker rmi
#删除全部镜像
docker rmi $(docker images -q)
#列出全部容器
docker ps -a
#重启容器
docker restart
#删除容器docker rm
#查看容器日志
docker logs
#删除所有停止的容器
docker container prune
#删除所有容器
docker rm $(docker ps -aq)
#进入容器
docker exec -it 775c7c9ee1e1 /bin/bash

docker-compose常用命令

#启动docker并加入后台进程
docker-compose up -d
#更新容器镜像
docker-compose pull
#关闭所有容器
docker-compose stop
#重启nginx
docker-compose restart nginx
#启动nginx
docker-compose start nginx
#关闭nginx
docker-compose stop nginx
#查看全部container
docker-compose ps
#删除全部停止的container
docker-compose rm

element ui省市区地区选择器

· 2 min read

需求场景

element ui一直没有开箱即用省市区地区选择器,可能是考虑国际化的原因。想要实现,可以基于cascader组件。那么问题来了,哪里有稳定持续维护的省市区数据源?看到不少文章使用的是`element-china-area-data`npm 包,看了下数据源已经很久没更新了,此外这个包的省市区还加上了市辖区三个字,感觉没啥意义。

解决方案

由于移动端经常使用vant组件库,里面的Area组件刚好提供了数据源npm包https://www.npmjs.com/package/@vant/area-data,为了保持移动端和桌面端省市区数据的一致性,于是发布了一个基于此数据源生成的符合element ui cascader组件格式的npm包https://www.npmjs.com/package/@urcloud/area-data

实现功能

  • 将vant area的数据格式转为Element UI的数据格式
  • 省市区地区选择器支持全部选项
  • 支持Element UI和Element Plus

数据格式

[
{
label:'北京市',
value:'110000',
children:[
{
label:'北京市',
value:'110100',
children:[
{
lable:'东城区',
value:'110101'
},
...
]
},
...
]
},
...
]

使用方式

<template>
<div class="demo-title demo-1">vant数据源:</div>
<el-cascader
v-model="value1"
:options="options1"
></el-cascader>
<div class="demo-title demo-2">vant数据源:加全部</div>
<el-cascader
v-model="value2"
:options="options2"
></el-cascader>
</template>
<script>
import {defineComponent} from 'vue';
import {getAreaTree} from '@urcloud/china-area-data';
export default defineComponent({
setup(){
return {
value1:'',
options1:getAreaTree(),
value2:'',
options2:getAreaTree(true),
}
}
})
</script>

ts中enum的使用方式

· 3 min read

需求场景

枚举的作用类似于常量,多数情况下优先使用枚举而不是常量。

简单场景

enum Platform {
"andorid" = 1,
"ios" = 2,
}

简单场景下,推荐使用 const,因为 enum 会成对象,const 只生成常量,占用的开销少,缺点是不能遍历 enum

const enum Platform {
"andorid" = 1,
"ios" = 2,
}

复杂场景(结合 namespace)

在使用枚举时,往往会需要一个辅助函数去展示属性的值,这个时候可以配合 namespace

enum Platform {
"andorid" = 1,
"ios" = 2,
}
namespace Platform {
export function getText(value: number) {
if (value === 1) {
return "ANDORID_PLATFORM";
}
if (value === 2) {
return "IOS_PLATFORM";
}
}
}

这样写的一个好处就是枚举合辅助方法能保持在同一命名空间下,维护方便。缺点就是如果需要遍历枚举的属性,就会多出命名空间中方法属性。

2023-03-16 更新

由于 ts 目前提供的 enum 功能简单,最终也是编译成对象。使用上只是语义上更清晰了而已,但是复杂场景需要方法支持的时候并不好用。所以我的实际项目上使用 buildEnum 辅助函数生成 enum 对象(普通 Object 对象),配合 ts 的推导,可以自动提示 enum 对象的所有属性和方法。

export const ReportStatus = buildEnum(
{
ToHandle: 0,
Handled: 1,
},
[
{
symbol: "ToHandle",
label: "待处理",
},
{
symbol: "Handled",
label: "已处理",
},
]
);

export function buildEnum<T extends Record<string, string | number>>(
obj: T,
labelArr: {
symbol: string;
label: string;
}[]
) {
return Object.assign(obj, {
Options: labelArr.map((v) => {
return {
label: v.label,
value: obj[v.symbol],
};
}),
getLabel(value: string | number) {
const macthed = labelArr.filter((v) => obj[v.symbol] == value)[0];
return macthed?.label ?? "";
},
});
}

vue3中的v-model和sync

· 2 min read

vue2中v-model

<div v-model="title"></div>

它实际上是下面写法的语法糖

<div :value="title" @input="title = $event"></div>

vue2中sync

<div title.sync="title"></div>

它实际上是下面写法的语法糖

<div :value="title" @update:title="title = $event"></div>

可以发现其实v-model和sync都差不多,v-model中value属性和input事件是一对,sync中自定义属性title和update:title是一对。可以说sync是v-model的超集,v-model也可以算是sync表单情况的语法糖。

vue3中v-model

在vue2中v-model和sync是类似的功能,所以作者做了优化,将两种写法合并到一起,为了降低心智吧。

<div v-model="title"></div>

他实际上是下面写法的语法糖

  <div :modelValue="title" @update:modelValue="title = $event"></div>

可以看到vue3中不再是value属性和input事件,而是 modelValue 属性和update: modelValue 事件

sync写法

<div v-model:title="title"></div>

清除input type="number"默认箭头

· One min read

需求场景

在移动端,部分手机的input当type为number时会出现上下箭头。

解决方案

input[type='number'] {
-moz-appearance: textfield;
}
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
-webkit-appearance: none;
}

windows开机运行frpc(bat脚本)

· One min read

步骤一:在 frp 安装目录下新建 frpc.bat 启动脚本,脚本内容如下

@echo off
:home
frpc -c frpc.ini
goto home

点击开始菜单,输入 “任务计划程序” 并打开,点击右侧的 “创建任务”

步骤二:新建计划任务

**常规:**名称随意填写,安全选项选择 “不管用户是否登录都要运行”,勾选“使用最高权限运行”

**触发器:**点击新建,选择 “启动时”

**操作:**点击新建,选择 “启动程序,在程序或脚本一栏选择第一步创建的 frpc .bat,下面的 “起始于” 填写 frpc .bat 的路径(不要包含 frpc.bat)

vue部署到阿里云oss

· One min read

环境条件

基于vue-cli创建的项目

需求场景

vue-cli构建的项目在build之后会生成dist目录,我们需要把dist目录里面的index.html上传至服务器,css,js,img等其他文件上传至oss。

步骤一:修改vue.config.js中的publicPath

const ossUrlPrefix='test.oss-cn-shanghai.aliyuncs.com';
module.exports = {
publicPath:process.env.NODE_ENV == "development" ? '/' : ossUrlPrefix,
}

步骤二:新建.deploy.config.js,修改package.json

module.exports = {
distPath: './dist',
jsonPath: './deploy.version.json',
maxVersionCountOfMode: 5,
oss: {
accessKeyId: '',
accessKeySecret: '',
region: 'oss-cn-shanghai',
bucket: 'test',
prefix: (mode, version) => {
return mode + '@' + version
},
},
stag: {
host: '',
username: '',
password: '',
serverPath: '',
},
prod: {
host: '',
username: '',
password: '',
serverPath: '',
},
}
{
"scripts": {
"deploy:stag": "oss-deploy upload stag",
"clear:stag": "oss-deploy clear stag",
"deploy:prod": "oss-deploy upload prod",
"clear:prod": "oss-deploy clear prod"
}
}

步骤三:build & deploy

npm run build:prod
npm run deploy:prod

详细文档

https://www.npmjs.com/package/@urcloud/oss-deploy

shell终端使用代理

· One min read

需求场景

有时候下载部分软件,需要使用代理,比如homebrew,所以需要终端网络走代理。

解决方案

 alias setproxy="export ALL_PROXY=socks5://127.0.0.1:1080" 
alias unsetproxy="unset ALL_PROXY"

Windows 终端

set HTTPS_PROXY=http://127.0.0.1:10808
set HTTP_PROXY=http://127.0.0.1:10809

set HTTPS_PROXY=
set HTTP_PROXY=

Windows WSL2解决方案

 cat /etc/resolv.conf|grep nameserver|awk '{print $2}'
alias setproxy="export ALL_PROXY=socks5://172.21.160.1:10808"
alias unsetproxy="unset ALL_PROXY"

Object.keys在typescript中的使用

· One min read

需求场景

当在ts中使用Object.keys时会报错。

    Object.keys(Detail).forEach((key) => {
Detail[key] = res.data[key];
});

解决方案

看到很多解决方案,最后发现国外一大佬的解决方案是最好的,通过重新定义Object的ts声明文件解决。

type ObjectKeys<T> =
T extends object ? (keyof T)[] :
T extends number ? [] :
T extends Array<any> | string ? string[] :
never;
interface ObjectConstructor {
keys<T>(o: T): ObjectKeys<T>
}

参考文档

typescript-better-object-keys