


前言在越来越深入使用ts的时候,我们会遇到这种痛点,有人声明了一个类型A,然后另一个人声明了B类型,此时我需要将A、B类型交叉起来,再增加一些新属性,这很好,但是当我们将鼠标移动到定义的新类型C上面的时候,你会发现你只能看到自己新增的属性,A、B类型只能看到一个名字,你无法感知到它们具体都有哪些属性。当然,这在开发中并不会有多大的影响,大不了跳转查看就是了,但是我们能不能不跳转进行预览呢?于是晚上刷小破站看到国外的一个大神的视频,讲述了一个有趣的分享,他分享了一个自定义的Prettify类型,通过使用这个类型我们就能查看到完整的属性了。 不多说,上教程。教程interface Test ...
前言由于最近研究了下br和gzip的配置,个人对于这个压缩处理推荐的逻辑是这样的:当访问的资源本地存在br文件的时候,优先使用br,br不存在的时候,访问gz文件,如果gz还不存在,就走默认资源处理或者返回源文件那么这套该怎么配置呢?教程全局nginx配置:gzip on; gzip_static on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 2; gzip_types text/plain application/javascript applica...
前言网上充斥着各种cv的教程,看的我真的要吐了,在国内环境下,根本没法正确编译brotli,为此我自己写一篇完全可用的教程。首先说一下流程:我们需要先卸载nginx,然后通过安装宝塔的服务器,用git拉取一个ngx_brotli项目,然后进入该项目,调用git submodule update --init,当内容返回checkout的时候才算扩展拉取成功。但是大部分人都会卡在这里,因为国情的原因,我们没法正确的拉取到项目。当我们拉取完毕后在宝塔点击安装nginx,选择编译安装,将刚刚拉取的模块加载进来一起编译安装。然后就等待安装完成即可。解决ngx_brotli拉取问题[hide]首先...
前言最近遇到这么一个头疼的需求,第三方提供了两份sdk,一个是针对安卓端使用的,一个是针对ios端使用的,但是他们都会在全局window上挂载同名属性对象,这就让我很难受了。<script src="/sdk/sdk.min.js"></script> <script src="/sdk/ios_sdk.min.js"></script>前端如果想要使用这个sdk就必须在head引入它,但是它又有两个脚本,后来的脚本又会覆盖上一个脚本在全局挂载的对象。理论上一个优秀的sdk不应该出现这种问题,它应该自...
前言通过vite官方的多页面打包示例,我发现它不会将html文件进行压缩处理,使用了一些第三方插件处理多页面,也都无法对html文件进行压缩处理,于是只能自己想办法了。效果图教程[hide]依赖安装pnpm i posthtml htmlnano cssnano terser svgo -D其中主力是posthtml和htmlnano,其它依赖都是他们的子依赖。编写插件创建文件:vite-plugin-html.tsimport type { Plugin } from "vite"; import posthtml from "posthtml"...
前言用了1天发现NFS的共享对windows来说真的是噩梦,权限问题太多了,最后在共享的磁盘中处理git仓库操作,各种问题,最后选择放弃,还是使用windows更加友好的SMB共享。对于linux之间的磁盘共享,通过NFS可以提供性能,对于windows的共享,还是得SMB。教程pve通过ssh连接,安装依赖:[hide]apt-get install samba samba-client理论上将pve自己是smb提供方,应该是不需要安装samba-client客户端的,但是由于又要在数据中心挂载目录,所以还是装一下吧。安装完成后我们配置一下smb配置。首先我们的共享目录就以上次挂载的磁...
上一章我们挂载了一个磁盘,但是这个磁盘如果要给其他虚拟机使用,粗暴的方式就是给其他虚拟机直接在硬件那添加一个磁盘,但是这种方式并不是共享,而是占用指定的空间,显然这并不方便。于是我选择了NFS的方式进行共享,这样linux系统可以使用,windows系统也可以使用。[hide]pve安装NFS通过ssh连接pve。apt-get update apt-get install nfs-kernel-server上一篇我们挂载的磁盘创建的目录是mnt/sda1,我们继续使用它。nano /etc/exports添加一行:/mnt/sda1 *(rw,sync,no_root_squash)...
擦除磁盘对于新的硬盘来说,其实没啥必要擦除,但是如果你是一个已经格式化过的硬盘,你希望重新开始,或者说你的磁盘格式不对,可以先用pve的可视化操作快速擦除一下。擦除完我们还需要进行格式化分区并挂载目录。分区格式化[hide]先输入:fdisk /dev/sda 打开指定的分区表并准备操作格式化处理,其中的sda就是上面我们通过pve查看到的新增的磁盘设备,如果你不知道,你可以通过下面这个命令去查看所有磁盘设备:fdisk -l可以看到用我这里已经有两块已经格式化的磁盘分区。其中sda就是本次教程完成后的效果。找到你需要格式化处理的分区输入fdisk 分区路径进入help界面。先输入n再输...
搞不懂为啥安装最新版的Debian12后就无法像之前那样通过sudo进行提权处理,解决方法如下:先通过普通用户登入,ssh连接或者Debian本地终端也行,输入以下命令:su -此时我们输入root账号的密码就不会提示不是 sudoers 文件了,但是这并不能解决问题,我们继续:visudo此时会打开一个文件,我们往下翻找到root ALL=(ALL:ALL) ALL 这行字符,在它的下一行我们输入一行文本:你当前用于提权的账号 ALL=(ALL:ALL) ALL如果你当前用于提权的账号是aaaa,那么实际文本内容就是:aaaa ALL=(ALL:ALL) ALL输入完毕后CTRL...
前言其实也没有真正意义上的同步,当我们在远程仓库删除了某个分支,通过git命令只能将本地origin/xxx的分支删除,实际上本地还有对应的分支没有被删除。为此我们还需要手动删除本地对应的分支。教程git remote update origin --prune这个命令是git fetch和git remote prune的组合操作。它会更新所有远程分支,并删除本地已经不存在于远程仓库的分支。此时我们查看本地分支,假设你删除的是test分支,你会发现本地对应的origin/test确实没有了,但是还存在一个test分支。这个没办法只能手动删除了。git branch -d test然后就行了。
依赖{ "scripts": { "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" }, "devDependencies": { "...
前言随着日常代码的产出,有些时候我们希望代码的注释能够区分一下优先级和类型,比如我发现了一个问题,但是这个问题可能需要以后有时间再修复,又或许为了实现某个功能,我使用了hack的方式,我希望能够给后来者一个提醒,方便接手人的维护,基于这些需求,我找到了一个插件:TODO Highlight它可以很方便的实现注释上的高亮处理,因为我暂时还不需要去大量查询todo,所以就没安装TODO Tree这个插件。实现看下效果图:由于官方默认只预设了TODO:和FIXME:,其他是我自己拓展的,大家可以按照下面的教程配置一下。自定义扩展TODOvscode -> 文件 -> 首选项 -&g...
vite中环境变量获取方式vite在处理环境变量时和之前webpack并不一样,它只会将环境变量文件中VITE_为前缀的变量加载到import.meta.env对象上去,而且并不支持动态key的形式:import.meta.env[key] //无效的因为import.meta.env.xxx打包时会被替换成字符串,比如有这么一个环境变量:VITE_NAME="aaa";const name = import.meta.env.VITE_NAME; //打包后 const name = "aaa";所以如果你是一个动态的key,那就没法进行正确...
前言移动端开发的时候,总是会遇到编写全局浮动组件的情况,比如客服图标啦,消息通知啦,但是浮动就会产生一个问题:阻挡了下层内容展示,常见的做法就是让这个浮动的内容支持拖拽功能,用户将浮动组件拖拽到其他位置即可。这里我参考了vConsole组件,自己根据实际情况编写了一个拖拽指令。代码指令文件:drag.tsimport type { Directive } from "vue"; /** 指令接收的参数 */ interface BindingValue { /** 出现位置的偏移量 [x,y] */ offset?: [number, number]...
随着JavaScript的代码复杂度日益增加,为了减少开发和维护的难度,模块化的需求出现了,从1999年至今,模块化的发展走过了一些重要的阶段,本篇重点讲解这些比较突出的模块化方式。命名空间早期一个比较简单的模块化方式就是通过命名空间,通过约定俗成的全局变量的方式,将一些属性或者方法存放在一个大写的变量对象中,然后去使用。var MY_MODULE = { name: "a", fn1: function() {}, fn2: function() {} }这样一来可以减少全局作用域上的变量数量,但是这个实现的本身它还是一个对象,这个就导致它的...
前言最近有一个想法,就是在使用rem适配大小的时候,往往我们会引入一个用于设置根元素大小的js脚本文件,但是对于这个脚本的处理根据不同情况会有不同的调用方式。以插件:amfe-flexible为例:比如我们是一个纯spa项目,一般就会在main.ts中import引入这个脚本:import "amfe-flexible";一般来说,这种做法没什么问题,因为spa的html渲染是js操作的,我们在渲染之前就引入了这个脚本,所以体验上会先通过amfe-flexible设置根元素大小,再进行html渲染,用户体验良好。随着业务的变化,我们可能会有SSR的需求,首屏loadi...
前言unplugin-auto-import这个插件用于解决在书写组件时,总是需要从vue中import引入相同依赖的重复劳动。import { computed, ref } from 'vue' const count = ref(0) const doubled = computed(() => count.value * 2)使用自动引入后就不需要手动一个个importconst count = ref(0) const doubled = computed(() => count.value * 2)对于想偷懒的人来说,还是挺不错的。插件会在代...
引入ts类型在我们刚开始学习ts的时候,常常是会创建一个types.ts文件,然后在里面声明一个类型并导出:export interface User { name: string; age: number; }使用的时候通过import导入:import { User } from "./types"; const user:User = { name: "a", age: 18 };很高兴你已经学会了如何引入ts类型,教程结束!当然,这是骗你的,但是这种用法确实是最开始ts所提供的,你不能说它错了,我们需要思考一下ts是如何被...
最近碰到一个巨奇葩的问题,项目中采用了unplugin-vue-components,但是vant的组件引入又是import手动按需引入,加上一些很奇怪的配置,导致项目配置变得复杂了,于是抽空将项目的配置全部梳理了一遍,并将import手动按需去除,全部采用自动引入的方式,通过分析打包后的包体,可以看到减少了100kb左右的大小,效果非常可观。但是问题也出在这了,当我使用自动引入的时候,vant的Dialog组件出现了问题,表现为:当我通过组件的形式使用时,弹窗会自动打开,显示还有问题,但是查看v-model:show变量是false;我开始以为是样式问题,单独引入dialog样式无效,...
前言实现一个自定义的置入按钮,然后实现置入html代码的功能,比如我们在使用外部iframe标签时,如果直接粘贴,会被识别为string值,从而导致无法正确展示内容,所以我们需要一个置入功能。我一开始想通过控制options的方式来实现,发现不太行,最后转用:先声明html结构,然后options关联的方式。教程自定义工具栏目前个人觉得最方便的方式就是先写html结构,然后options中通过container进行关联。<div id="quill-edit-toolbar" class="ql-toolbar ql-snow"> ...
前言上一篇是修改官方的图片上传行为,这次是修改官方视频按钮默认行为,你会发现官方的视频默认行为,总是采用iframe的形式,如果我们希望是原生video元素,就没办法了,于是就有了本篇教程。这次自定义和图片就略有不同了,我们不能直接这么插入:editor.insertEmbed(range.index, 'video', src, Quill.sources.USER);如果采用这种方式,会导致和官方的行为一致,变成插入的是iframe元素了。为此,我们需要了解一个新知识:Blot官方文档对于Blot的介绍很少,我们可以理解是一种行为扩展的方式,可以对用户输入的内容进...
前言当我们接手了一些二手项目之后,在后期的需求改动时,肯定会遇到大改的情况,可能之前的整个文件我们都不能要了,但是,从开发安全的角度来讲,之前的代码对我们而言是有用的,比如出了问题,我们需要还原成旧的,或者逻辑发现问题,需要和旧的逻辑进行比对排查。在linux的操作中,会有一个很棒的行为习惯,当我们去改动一个很重要的文件时,会先创建一份.back文件,然后再去改动,如果出现问题,可以用back文件进行还原。那么这种行为我觉得可以用在前端项目开发中,这样当新代码出现问题,可以查看旧的代码进行比对,出现问题也能及时还原。当然这种方式从整体来说,对代码的要求是很高的,需要满足里氏替换原则才能实...
前言quill默认图片上传是将图片转为base64字符串,这个主意很不错,但是如果考虑后端存储的大小,就不太美丽了,因为base64的字符串大小往往比实际图片大小占用还要大一些,所以一般的做法是自定义文件上传,后端返回外链地址,用链地址来代替base64,以减少富文本的内容大小。我目前的做法是将官方默认图片上传的行为改变,这样按钮样式啥的就不用自己操心了。教程修改默认按钮行为我们在初始化quill实例的时候,会传入一个options来控制样式和顶部菜单功能。import type { QuillOptionsStatic } from 'quill'; const ...
最近评论