当前位置: 首页 > web >正文

前端开发笔记与实践

一、Vue 开发规范与响应式机制

1. 组件命名规范

  • 自定义组件使用大驼峰命名法(如 MyComponent),符合 Vue 官方推荐,便于与原生 HTML 元素区分。

2. Proxy vs defineProperty

特性Proxy(Vue3)Object.defineProperty(Vue2)
拦截范围支持对象增删改查等所有基本操作只能监听已有属性
数组支持自动拦截数组变异方法需手动重写数组方法
性能更高效层级嵌套需递归处理

Vue3 使用 Proxy 实现更全面的响应式拦截,而 Vue2 依赖 defineProperty 实现有限拦截。

3. 响应式核心流程

  1. Observer:将数据转换为响应式对象(通过 definePropertyProxy
  2. Watcher:追踪依赖,记录哪些函数(如 render)用到了哪些数据
  3. Dep:每个属性维护一个依赖列表,当属性变化时通知 Watcher 更新
  4. Scheduler:异步调度更新,避免重复渲染,提高性能

4. 调度器作用

  • 合并多次变更,减少 render 触发次数
  • 异步执行更新(基于 nextTick 和微任务队列)
  • 确保每个 Watcher 只执行一次更新

5. Vue3响应式性能对照

操作Vue2 (defineProperty)Vue3 (Proxy)
初始化1000属性15ms3ms
新增100属性需要Vue.set直接赋值
数组操作特殊处理原生支持
内存占用每个属性1KB整个对象3KB

二、CSS 与 SCSS 进阶

1. CSS 新单位

单位计算依据典型应用场景
vmin视口宽高中较小值移动端全面屏适配(适配小屏幕)
vmax视口宽高中较大值大屏展示元素尺寸控制(适配宽屏)
dvh动态视口高度解决移动浏览器工具栏遮挡问题
svh/lvh小/大视口高度特定视口比例布局
/* 确保元素在任何设备上都可见 */
.modal {width: min(90vw, 800px);height: max(60vh, 400px);/* 移动端避开地址栏 */height: calc(100dvh - 60px);
}

2. SCSS 循环与变量

$num: 20;@for $i from 1 through $num {.btn:nth-child(#{$i}) {transform: scale(0.1 * $i);}
}

三、JavaScript 进阶技巧

1. 判断是否是数组

方法是否可靠说明
Array.isArray()✅ 推荐ES6 标准方法
obj instanceof Array受原型链影响
Object.prototype.toString.call(obj)可被 Symbol.toStringTag 修改

2. 稀疏数组判断

function isSparseArray(arr) {if (!Array.isArray(arr)) return false;for (let i = 0; i < arr.length; i++) {if (!(i in arr)) return true;}return false;
}

3. 数组去空字符串

const arr = ['', '1'];
const filtered = arr.filter(Boolean); // ['1']

4. 字符串路径转类名

const path = 'view/home/index';
const className = path.split('/').join('-'); // view-home-index

5. 垃圾回收机制

  • 垃圾判定:不可达内存
  • 回收策略
    • 引用计数(易产生循环引用泄漏)
    • 标记清除(主流浏览器采用)
  • 闭包问题:词法环境未释放导致内存膨胀
  • 手动释放:将引用设为 null

四、TypeScript 技巧

1. 函数参数类型约束

const obj = {age: 18,name: 'zhangsan'
};function fn(key: keyof typeof obj) {const v = obj[key];
}

2. 获取三方库函数参数/返回值类型

import { fn } from "some-lib";type FnParams = Parameters<typeof fn>[0]; // 获取第一个参数类型
type FnReturn = ReturnType<typeof fn>;   // 获取返回值类型

3. 元组生成联合类型

const obj = {a: 1,b: 2,z: 36
};
type KeysType = keyof typeof obj; // 'a' | 'b' | ... | 'z'function getValue(key: KeysType) {console.log(obj[key]);
}

五、文件上传与下载

1. 文件上传交互方式

  • 多选:<input type="file" multiple>

  • 文件夹选择:<input type="file" webkitdirectory mozdirectory odirectory>

  • 拖拽上传:

    div.ondragover = e => e.preventDefault();
    div.ondrop = e => {e.preventDefault();for (const item of e.dataTransfer.items) {const entry = item.webkitGetAsEntry();if (entry.isFile) {entry.file(file => console.log(file));} else {const reader = entry.createReader();reader.readEntries(entries => console.log(entries));}}
    };
    
  • 拖拽上传增强版

    class AdvancedDropzone {constructor(selector) {this.el = document.querySelector(selector);this.setupEvents();this.preview = this.createPreview();}setupEvents() {this.el.addEventListener('dragover', this.highlight.bind(this));this.el.addEventListener('dragleave', this.unhighlight.bind(this));this.el.addEventListener('drop', this.handleDrop.bind(this));}async handleDrop(e) {e.preventDefault();this.unhighlight();const entries = Array.from(e.dataTransfer.items).map(item => item.webkitGetAsEntry());const files = [];for (const entry of entries) {if (entry.isFile) {files.push(this.getFile(entry));} else {files.push(...await this.traverseDirectory(entry));}}this.previewFiles(files);}async traverseDirectory(dir) {const reader = dir.createReader();const entries = await new Promise(resolve => {reader.readEntries(resolve);});const files = [];for (const entry of entries) {if (entry.isFile) {files.push(await this.getFile(entry));} else {files.push(...await this.traverseDirectory(entry));}}return files;}
    }
    
  • 大文件分片上传

    class ChunkedUploader {constructor(file, options = {}) {this.file = file;this.chunkSize = options.chunkSize || 5 * 1024 * 1024;this.concurrent = options.concurrent || 3;this.chunks = Math.ceil(file.size / this.chunkSize);this.queue = [];}async upload() {const chunks = Array.from({ length: this.chunks }, (_, i) => i);const results = await pMap(chunks, this.uploadChunk.bind(this), {concurrency: this.concurrent});return this.finalize();}async uploadChunk(index) {const start = index * this.chunkSize;const end = Math.min(start + this.chunkSize, this.file.size);const chunk = this.file.slice(start, end);const form = new FormData();form.append('chunk', chunk);form.append('index', index);form.append('total', this.chunks);await axios.post('/upload', form, {onUploadProgress: this.createProgressHandler(index),__chunkIndex: index});}
    }
    

2. 文件上传网络请求

方式支持进度支持取消
XHR / Axios✅ 上传/下载
Fetch✅ 下载✅(AbortController)

3. 文件下载方式

  • <a> 标签下载(同源限制):

    <a href="http://xxx.pdf" download>Download</a>
    
  • Blob + URL.createObjectURL(跨域无 token 限制):

    fetch(url).then(res => res.blob()).then(blob => {const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'file.pdf';a.click();URL.revokeObjectURL(url);
    });
    

六、性能优化技巧

1. 环境兼容性封装(一次性判断)

const addEvent = (() => {if (ele.addEventListener) {return (ele, eventName, handler) => ele.addEventListener(eventName, handler);} else if (ele.attachEvent) {return (ele, eventName, handler) => ele.attachEvent('on' + eventName, handler);} else {return (ele, eventName, handler) => ele['on' + eventName] = handler;}
})();

2. Token 无感刷新方案

  1. 请求失败且为 401 错误
  2. 检查是否为刷新接口本身 → 是则跳过
  3. 若已有刷新 Promise 存在 → 复用
  4. 发起刷新请求 → 替换新 token 重新发起原始请求
  5. 失败 → 清除 token 跳转登录页
let refreshPromise: Promise<any> | null = null;export async function refreshToken() {if (refreshPromise) return refreshPromise;refreshPromise = new Promise(async resolve => {try {const res = await axios.get('/refresh_token', {headers: { Authorization: `Bearer ${getRefreshToken()}` },__isRefreshToken: true});if (res.code === 0) resolve(true);else resolve(false);} catch (e) {resolve(false);} finally {refreshPromise = null;}});return refreshPromise;
}

七、扩展知识

1. 单点登录(SSO)与 JWT 关系

  • 单点登录:用户只需登录一次即可访问多个系统
  • JWT:是一种 Token 生成与验证机制,常用于身份认证
  • 关系:JWT 可作为 SSO 的 Token 实现方式之一,但二者没有必然联系
http://www.xdnf.cn/news/6720.html

相关文章:

  • Visual Studio 2022 中添加“高级保存选项”及解决编码问题
  • WebMvcConfigurer介绍-笔记
  • GESP2025年3月认证C++二级( 第三部分编程题(2)时间跨越)
  • MongoDB 应用实战
  • 多尺度对比度调整
  • DDD领域驱动介绍
  • MODBUS RTU调试助手使用方法详解
  • 基于Mongodb的分布式文件存储实现
  • Java实现生产者-消费者模式:从基础到高级实践
  • MiniMax语音模型Speech-02近日登顶多个全球榜单,详细技术解析
  • 【Reality Capture 】02:Reality Capture1.5中文版软件设置与介绍
  • Lua中使用module时踩过的坑
  • 计算机指令分类和具体的表示的方式
  • 【Win32 API】 lstrcmpA()
  • Java内存泄露生产环境排查过程,通透了
  • 计算机网络 : Socket编程
  • EXCEL在一列数据前统一添加负号
  • 6种方式来探究数据集的的方法worldquant
  • STM32外设AD-定时器触发 + DMA读取模板
  • RKNN开发环境搭建(ubuntu22.04)
  • 网络世界的“百变身份“:动态IP让连接更自由
  • 解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式
  • 【Python 操作 MySQL 数据库】
  • maven和npm区别是什么
  • 几种排序方式的C语言实现(冒泡、选择、插入、希尔等)
  • 大数据技术的主要方向及其应用详解
  • 【问题排查】easyexcel日志打印Empty row!
  • DeepSearch代表工作
  • 时钟产生的公共模块示例
  • Java 泛型与类型擦除:为什么解析对象时能保留泛型信息?