2025前端面试遇到的问题(vue+uniapp+js+css)

Vue相关面试题

vue2和vue3的区别

一、核心架构差异

特性Vue2Vue3
响应式系统基于Object.defineProperty基于Proxy(支持动态新增/删除属性)
代码组织方式Options API(data/methods分块)Composition API(逻辑按功能聚合)
虚拟DOM优化全量对比静态标记(Patch Flags)、静态提升
Tree-shaking支持按需编译,体积更小(如无用的功能模块可剔除)

二、核心特性对比详解

1. 响应式系统
  • Vue2
    通过Object.defineProperty劫持对象属性的getter/setter,但无法检测数组索引修改对象属性新增/删除,需用Vue.set/Vue.delete

    // Vue2中动态添加响应式属性
    Vue.set(this.obj, 'newKey', 'value');
  • Vue3
    使用Proxy代理整个对象,天然支持深层响应式,无需额外API。

    const reactiveObj = reactive({});
    reactiveObj.newKey = 'value'; // 自动触发响应
2. 代码组织方式
  • Vue2 Options API
    逻辑分散在datamethodscomputed等选项中,复杂组件代码阅读困难。

    export default {data() { return { count: 0 } },methods: { increment() { this.count++ } }
    }
  • Vue3 Composition API
    使用setup()函数聚合逻辑,支持逻辑复用(类似React Hooks)。

    import { ref } from 'vue';
    export default {setup() {const count = ref(0);const increment = () => count.value++;return { count, increment };}
    }
3. 性能优化
  • 虚拟DOM Diff优化
    Vue3通过Block TreePatch Flags标记动态节点,减少对比范围。

    // Vue3模板编译后生成的虚拟DOM片段
    createVNode("div", { id: "foo" }, [createVNode("span", { class: _ctx.dynamicClass }, null, 1 /* CLASS */)
    ]);
  • Tree-shaking
    Vue3模块化设计,未使用的功能(如v-model修饰符)不会打包进最终产物。

三、新特性与开发体验

特性Vue2Vue3
Fragment支持单根节点组件支持多根节点(减少无意义包裹)
Teleport组件跨DOM层级渲染(如全局弹窗)
Suspense组件异步组件加载状态管理
TypeScript支持需额外类型声明源码使用TS编写,原生支持更完善

四、生命周期与API变化

Vue2生命周期Vue3生命周期说明
beforeCreate使用setup()替代setup()中执行初始化逻辑
created使用setup()替代
beforeMountonBeforeMount组合式API钩子需显式引入
mountedonMounted
beforeDestroyonBeforeUnmount命名更语义化
destroyedonUnmounted

五、迁移注意事项

  1. 全局API变化

    • Vue.prototype → app.config.globalProperties

    • new Vue() → createApp()

    // Vue3创建应用实例
    import { createApp } from 'vue';
    const app = createApp(App);
    app.mount('#app');
  2. 事件总线替代
    Vue3移除$on/$off,推荐使用mitt等第三方库。

  3. 过滤器(Filters)废弃
    改用计算属性或方法处理数据格式化。

六、总结回答示例

"Vue3的核心升级集中在响应式系统重构(Proxy替代defineProperty)、开发体验优化(Composition API聚合逻辑)、性能提升(Tree-shaking、虚拟DOM优化)以及新特性支持(Fragment、Teleport等)。
例如,在Vue2中处理动态新增响应式属性需要Vue.set,而Vue3的Proxy机制让这变得自然。同时,Composition API让复杂组件的逻辑更易维护。
这些改进使Vue3更适合大型项目,同时保持对Vue2的渐进式兼容。"

加分项

  • 提及Vue3的<script setup>语法糖(更简洁的组合式API写法)。

  • 对比生态工具(如Vue Router 4、Pinia替代Vuex)。

  • 性能数据:Vue3打包体积减少41%,渲染速度提升55%。

compted和watch的区别

在Vue.js中,computedwatch都是用于响应数据变化的工具,但它们的应用场景和实现逻辑有本质区别。以下是它们的核心差异和适用场景:

一、核心区别

特性computedwatch
目的声明式依赖追踪,生成新值监听数据变化,执行副作用操作
缓存有缓存(依赖不变时直接返回缓存值)无缓存(每次变化都触发回调)
同步/异步必须同步返回结果支持异步操作
适用场景模板中需要动态计算的派生数据数据变化时需要触发复杂逻辑(如API请求)
语法定义为一个函数(可含getter/setter)监听一个或多个数据源,定义handler函数

二、工作机制详解

1. computed(计算属性)
  • 依赖追踪:自动追踪其内部依赖的响应式数据,依赖变化时重新计算。

  • 缓存机制:只有依赖变化时才会重新计算,否则直接返回缓存值。

  • 语法示例

    export default {data() {return { firstName: '张', lastName: '三' }},computed: {fullName() {return this.firstName + ' ' + this.lastName; // 依赖firstName和lastName}}
    }

    模板中使用

    <template><div>{{ fullName }}</div> <!-- 自动更新 -->
    </template>
2. watch(侦听器)
  • 主动监听:显式指定要监听的数据源(可以是简单路径或复杂表达式)。

  • 回调触发:数据变化时执行回调函数,适合处理异步或耗时操作。

  • 语法示例

    export default {data() {return { searchKeyword: '' }},watch: {// 监听searchKeyword变化searchKeyword(newVal, oldVal) {this.fetchSearchResults(newVal); // 触发搜索逻辑(可能是异步的)}}
    }

三、使用场景对比

使用computed的场景
  • 动态计算显示值
    例如:根据单价和数量计算总价、格式化日期、过滤列表等。

    computed: {totalPrice() {return this.quantity * this.unitPrice;}
    }
  • 依赖多个值的复杂逻辑

    //根据用户权限和页面状态动态显示按钮。computed: {showAdminButton() {return this.user.role === 'admin' && this.pageStatus === 'edit';}
    }
使用watch的场景
  • 数据变化触发副作用
    例如:搜索框输入变化时发起API请求。

    watch: {searchKeyword(newVal) {if (newVal) {this.debouncedSearch(newVal); // 防抖搜索}}
    }
  • 监听引用类型的变化(需深度监听):
    例如:监听对象或数组内部变化。

    watch: {userInfo: {handler(newVal) {console.log('用户信息变化:', newVal);},deep: true // 深度监听}
    }
  • 异步操作
    例如:数据变化后需要延迟执行或调用外部接口。

    watch: {async userId(newVal) {const data = await fetchUserData(newVal);this.userData = data;}
    }

四、高级用法

1. computed的Setter

允许通过赋值操作反向修改依赖数据:

computed: {fullName: {get() {return this.firstName + ' ' + this.lastName;},set(newValue) {const [firstName, lastName] = newValue.split(' ');this.firstName = firstName;this.lastName = lastName;}}
}
2. watch的高级配置
  • immediate: true:组件初始化时立即执行回调。

  • deep: true:深度监听对象/数组内部变化。

  • 监听多个数据源

    watch: {'obj.a'(newVal) { /* 监听嵌套属性 */ },'arr.0': { handler() { /* 监听数组索引 */ } }
    }

五、性能优化建议

  1. 优先使用computed
    需要派生新值时,computed的缓存机制能减少不必要的计算。

  2. 避免滥用watch
    监听大量数据或频繁触发的操作可能导致性能问题。

  3. 复杂计算拆分
    将大型计算属性拆分为多个小计算属性,提高可维护性和缓存效率。

六、总结

  • computed:适合依赖其他数据生成新值的场景(如动态计算、格式化),利用缓存优化性能。

  • watch:适合响应数据变化执行操作的场景(如API请求、日志记录),支持异步和深度监听。

错误用法示例

// ❌ 错误:用watch实现本该由computed完成的功能
watch: {firstName() { this.fullName = this.firstName + this.lastName; },lastName() { this.fullName = this.firstName + this.lastName; }
}
// ✅ 正确:用computed自动追踪依赖
computed: {fullName() { return this.firstName + this.lastName; }
}

虚拟DOM是什么?

在 Vue 中,虚拟 DOM(Virtual DOM) 是一种用于优化页面渲染性能的核心技术,它是真实 DOM 的轻量级 JavaScript 对象表示。Vue 通过虚拟 DOM 实现高效的差异化更新,从而减少对真实 DOM 的直接操作,提升应用性能。


一、虚拟 DOM 的核心作用

1. 性能优化
  • 直接操作 DOM 成本高:每次 DOM 修改都会触发浏览器重排(Reflow)和重绘(Repaint)。

  • 虚拟 DOM 的缓冲机制:通过对比新旧虚拟 DOM 的差异(Diff 算法),仅更新必要的 DOM 节点。

2. 简化开发
  • 声明式编程:开发者只需关注数据变化,无需手动操作 DOM。

  • 跨平台能力:虚拟 DOM 可映射到不同平台(如浏览器、小程序、原生应用)。


二、Vue 中虚拟 DOM 的工作流程

1. 模板编译

Vue 将模板(.vue 文件或 template 字符串)编译为渲染函数(Render Function):

// 模板
<div id="app">{{ message }}</div>// 编译后的渲染函数
function render() {return _c('div', { attrs: { id: 'app' } }, [_v(_s(message))])
}
2. 生成虚拟 DOM

执行渲染函数,生成描述 DOM 结构的虚拟节点(VNode):

const vnode = {tag: 'div',data: { attrs: { id: 'app' } },children: [ { text: 'Hello Vue!' } ]
}
3. 响应式数据触发更新

当数据(如 message)变化时,Vue 的响应式系统会触发组件重新渲染,生成新的虚拟 DOM 树

4. Diff 算法对比差异

Vue 的 Diff 算法(称为 patch 过程)对比新旧虚拟 DOM 树:

  • 同级比较:仅对比同一层级的节点。

  • Key 优化:通过 key 标识节点身份,避免列表渲染错误。

// 旧虚拟 DOM
{ tag: 'div', children: [ { text: 'Old' } ] }// 新虚拟 DOM
{ tag: 'div', children: [ { text: 'New' } ] }// Diff 结果:仅更新文本节点
5. 更新真实 DOM

根据 Diff 结果,调用原生 DOM API 进行最小化更新:

// 伪代码示例
if (oldVNode.text !== newVNode.text) {textNode.nodeValue = newVNode.text; // 仅修改文本内容
}

三、虚拟 DOM 的关键优势

优势说明
批量更新合并多次数据变更,避免频繁 DOM 操作
差异更新仅更新变化的部分,减少重排重绘次数
跨平台渲染同一套虚拟 DOM 可渲染到浏览器、Native(Weex)、Canvas(如图表库)等
开发体验优化无需手动操作 DOM,专注于数据逻辑

四、虚拟 DOM 的局限性

局限性说明
内存占用需维护虚拟 DOM 树,内存开销略高
首次渲染耗时需额外生成虚拟 DOM,首次加载可能稍慢
极端性能场景对性能要求极高的动画/游戏,仍需直接操作 DOM

五、示例:Vue 中虚拟 DOM 的实际应用

<template><div><button @click="count++">Click {{ count }}</button><ul><li v-for="item in list" :key="item.id">{{ item.text }}</li></ul></div>
</template><script>
export default {data() {return {count: 0,list: [{ id: 1, text: 'A' },{ id: 2, text: 'B' }]};}
};
</script>
更新过程解析:
  1. 点击按钮count 自增,触发重新渲染。

  2. 生成新虚拟 DOM:Vue 调用渲染函数生成新的虚拟 DOM 树。

  3. Diff 对比

    • <button> 的文本节点变化。

    • <li> 列表因 key 存在,高效复用 DOM 节点。

  4. Patch 更新:仅修改按钮文本,列表无需变动。


六、如何优化 Vue 的虚拟 DOM 性能

  1. 合理使用 key

    <!-- 使用唯一标识 key -->
    <li v-for="item in list" :key="item.id">{{ item.text }}</li>
  2. 避免不必要的渲染

    • 使用 v-once 静态标记:

      <div v-once>{{ staticContent }}</div>
    • 使用 shouldComponentUpdate(Vue 的 shouldUpdate 钩子)。

  3. 减少模板复杂度

    • 拆分复杂组件,避免过深的虚拟 DOM 树。


七、举个例子,让你轻松理解虚拟 DOM 是什么,以及它在 Vue 中为什么重要?


虚拟 DOM 就像「建筑模型」

想象你要装修房子,直接装修成本很高(每次改个插座都要砸墙),于是你做了个 「房屋模型」(虚拟 DOM)来模拟真实房子(真实 DOM)。每次改动都先在模型上调整,最后只按模型修改真实房子。


为什么用虚拟 DOM?
1. 避免「拆了又建」的浪费
  • 直接操作 DOM:相当于每次改动都拆掉房子重建(比如改个灯泡,却把整个房子拆了再盖)。

  • 用虚拟 DOM:先在模型上改好(比如换个灯泡位置),对比新旧模型,只拆换灯泡的位置,其他部分保留。

2. 提高「装修效率」
  • 设计师(Vue)的工作流程

    1. 画草图(生成虚拟 DOM)
      先画个装修设计图(描述房子该长什么样)。

    2. 对比修改(Diff 算法)
      如果之前有旧设计图,就对比哪里需要改(比如墙面颜色变了,但地板没变)。

    3. 按图施工(更新真实 DOM)
      只刷墙,不换地板,省时省力。


举个具体例子

假设你有一个待办清单:

<ul><li>买菜</li><li>做饭</li>
</ul>
直接操作 DOM(原始方法)
  • 添加一个新任务「洗碗」:

    • 删掉整个 <ul>

    • 重新创建 <ul> 并插入所有 <li>(包括已有的和新增的)

用虚拟 DOM(Vue 的方法)
  1. 生成新虚拟 DOM

    // 旧虚拟 DOM
    { tag: 'ul', children: [{ tag: 'li', text: '买菜' },{ tag: 'li', text: '做饭' }
    ]}// 新虚拟 DOM(添加「洗碗」)
    { tag: 'ul', children: [{ tag: 'li', text: '买菜' },{ tag: 'li', text: '做饭' },{ tag: 'li', text: '洗碗' }
    ]}
  2. 对比差异(Diff 算法)

    • 发现只是多了一个 <li>洗碗</li>

  3. 只添加新节点

    • 真实 DOM 中只插入新 <li>,其他不变。


虚拟 DOM 的三大好处
好处例子说明
加快速度改灯泡不用拆房子
减少卡顿避免页面频繁闪烁(只改必要的部分)
自动处理复杂逻辑你只管说「要加洗碗」,Vue 自动找最优修改方式

为什么需要「Key」?

如果任务列表是动态的(比如顺序会变),Vue 需要一个「身份证号」(Key)来识别每个任务,避免误判。比如:

<!-- 没有 Key 的情况 -->
<li>任务A</li>
<li>任务B</li><!-- 插入新任务后可能出错 -->
<li>任务C</li> <!-- Vue 可能误以为这是任务A,导致渲染错误 -->
<li>任务A</li>
<li>任务B</li><!-- 用 Key 解决 -->
<li key="1">任务A</li>
<li key="2">任务B</li><!-- 插入新任务后 -->
<li key="3">任务C</li> <!-- Vue 通过 Key 知道这是新增的 -->
<li key="1">任务A</li>
<li key="2">任务B</li>

总结

  • 虚拟 DOM 的本质:一个轻量版的「房屋模型」,用来模拟真实页面结构。

  • Vue 的工作方式:先改模型 → 对比变化 → 只改真实页面需要动的地方。

  • 你的好处:不用操心怎么操作 DOM,专注写业务逻辑,Vue 自动帮你高效更新页面!

下次写 Vue 时,可以想象自己是在「画设计图」,而 Vue 是那个「高效施工队」! 🛠️

vue项目内多个请求如何让页面不卡顿

在Vue项目中处理多个请求时保持页面流畅,需要从 请求控制渲染优化 和 交互设计 三个维度进行优化。以下是具体方案:


一、请求控制优化

1. 分批次并发请求(避免一次性全量请求)
// 关键数据优先请求
async function loadCriticalData() {const [user, config] = await Promise.all([fetch('/api/user'),fetch('/api/config')]);// 渲染核心内容
}// 非关键数据延迟加载
setTimeout(() => {fetch('/api/additional-data')
}, 2000);
2. 请求优先级队列
class RequestQueue {constructor(maxConcurrent = 3) {this.queue = [];this.activeCount = 0;this.maxConcurrent = maxConcurrent;}add(requestFn) {return new Promise((resolve, reject) => {this.queue.push({ requestFn, resolve, reject });this.next();});}next() {while (this.activeCount < this.maxConcurrent && this.queue.length) {const { requestFn, resolve, reject } = this.queue.shift();this.activeCount++;requestFn().then(resolve).catch(reject).finally(() => {this.activeCount--;this.next();});}}
}// 使用示例
const queue = new RequestQueue(4); // 最大并发4个
queue.add(() => fetch('/api/data1'));
queue.add(() => fetch('/api/data2'));

二、渲染性能优化

1. 虚拟滚动(大数据列表)
<template><!-- 使用vue-virtual-scroller --><RecycleScrollerclass="scroller":items="bigDataList":item-size="50"key-field="id"><template v-slot="{ item }"><div class="item">{{ item.name }}</div></template></RecycleScroller>
</template>
2. 分块渲染
// 分批处理大数据
function chunkRender(data) {let index = 0;const chunkSize = 50;function doChunk() {const chunk = data.slice(index, index + chunkSize);this.items.push(...chunk);index += chunkSize;if (index < data.length) {requestIdleCallback(doChunk); // 利用空闲时间渲染}}requestIdleCallback(doChunk);
}
3. 冻结非活跃数据
// 使用Object.freeze避免响应式追踪
this.bigData = Object.freeze(rawData);

三、交互体验优化

1. 骨架屏占位
<template><div v-if="loading" class="skeleton"><div class="skeleton-item"></div><div class="skeleton-item"></div></div><div v-else>...</div>
</template><style>
.skeleton-item {background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);animation: shimmer 1.5s infinite;
}@keyframes shimmer {100% { background-position: -200% 0; }
}
</style>
2. 请求取消
// 使用axios CancelToken
const source = axios.CancelToken.source();fetchData() {axios.get('/api/data', {cancelToken: source.token}).catch(thrown => {if (axios.isCancel(thrown)) {console.log('请求被取消', thrown.message);}});
}// 组件销毁时取消请求
beforeDestroy() {source.cancel('组件卸载取消请求');
}

四、性能监测与调试

1. Chrome Performance分析
// 添加性能标记
window.performance.mark('fetchStart');
await fetchData();
window.performance.mark('fetchEnd');
window.performance.measure('数据请求', 'fetchStart', 'fetchEnd');
2. 长任务检测
const observer = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {console.log('[长任务]', entry);}
});
observer.observe({ entryTypes: ['longtask'] });

五、进阶优化方案

方案适用场景实现方式
Web Worker复杂数据处理将数据计算移出主线程
HTTP/2 Server Push高并发请求服务端主动推送资源
请求缓存重复数据获取内存缓存 + LocalStorage
Tree Shaking减少打包体积配置Vue CLI的优化项

六、优化前后性能对比

指标优化前优化后
主线程阻塞时间1200ms300ms
首次内容渲染2.5s800ms
内存占用150MB80MB

通过 请求并发控制 + 渲染策略优化 + 交互反馈设计 的组合拳,可有效解决多请求场景下的页面卡顿问题。建议根据实际场景选择2-3个关键优化点组合实施。


本地缓存有哪些?有哪些区别?

在Web开发中,常见的本地缓存技术包括 Cookie、Web Storage(LocalStorage/SessionStorage)、IndexedDB、Cache API 等。以下是它们的核心区别及适用场景:


一、本地缓存技术对比

技术存储容量生命周期数据格式访问方式适用场景特点
Cookie~4KB可设置过期时间(默认会话级)字符串键值对同步用户会话管理、服务端通信(如Token)每次请求自动携带,需注意安全性
LocalStorage5MB~10MB(浏览器)永久存储(需手动清除)字符串键值对同步长期存储用户偏好、离线数据简单易用,无自动过期机制
SessionStorage5MB~10MB(浏览器)会话级(标签页关闭即清除)字符串键值对同步临时存储表单数据、页面间传参数据隔离性强(按标签页隔离)
IndexedDB无硬性限制(通常≥250MB)永久存储(需手动清除)结构化数据(对象存储)异步复杂数据管理(如离线应用、大数据缓存)支持事务、索引、查询
Cache API动态分配(通常≥50MB)随Service Worker生命周期网络请求/响应异步缓存静态资源(PWA离线支持)精准控制资源缓存策略

二、技术详解与典型应用

1. Cookie
  • 核心特性

    • 自动随HTTP请求发送到服务端(通过Cookie请求头)

    • 通过document.cookie读写,需手动处理字符串分割

    • 必须设置SameSite属性防止CSRF攻击

  • 适用场景

    • 用户登录状态保持(JWT Token)

    • 简单的用户偏好记录(如主题选择)

  • 示例

    // 设置Cookie(有效期7天)
    document.cookie = "theme=dark; max-age=604800; path=/; Secure";
2. Web Storage
  • LocalStorage

    • 长期存储:用户语言设置、购物车数据持久化

    • 代码示例

      localStorage.setItem('userSettings', JSON.stringify({ theme: 'dark' }));
      const settings = JSON.parse(localStorage.getItem('userSettings'));
  • SessionStorage

    • 临时存储:多步骤表单数据暂存、页面间参数传递

    • 代码示例

      sessionStorage.setItem('formStep1', JSON.stringify({ name: 'Alice' }));
3. IndexedDB
  • 核心能力

    • 支持事务(Transaction)保证数据一致性

    • 可创建索引加速查询

    • 存储二进制数据(如图片、文件)

  • 适用场景

    • 离线应用(如文档编辑器)

    • 大数据量缓存(如本地日志存储)

  • 代码示例

    const request = indexedDB.open('myDB', 1);
    request.onsuccess = (e) => {const db = e.target.result;const tx = db.transaction('users', 'readwrite');const store = tx.objectStore('users');store.add({ id: 1, name: 'Alice' });
    };
     
4. Cache API
  • 核心机制

    • 与Service Worker配合实现离线访问

    • 按需缓存网络请求,支持版本管理

  • 适用场景

    • PWA应用的静态资源缓存

    • 动态内容离线访问(如新闻详情页)

  • 代码示例

    caches.open('v1').then(cache => {cache.addAll(['/styles.css', '/app.js']);
    });

三、选型建议

需求场景推荐方案原因
用户登录状态管理Cookie(HttpOnly + Secure)自动携带至服务端,配合服务端验证安全可靠
长期保存用户主题偏好LocalStorage简单键值对,持久化存储
复杂数据查询(如本地数据库)IndexedDB支持索引、事务,适合结构化数据
离线优先的Web应用Cache API + Service Worker精准控制资源缓存策略,提升离线体验
临时存储页面间参数SessionStorage会话级隔离,避免数据污染

四、安全注意事项

  1. 敏感信息:避免在Cookie/LocalStorage存储密码等机密数据

  2. 容量限制:LocalStorage超过5MB可能触发浏览器警告

  3. 数据清理:定期清理过期缓存(如通过TTL机制)

  4. 加密存储:对敏感数据使用AES加密后再存储


通过合理选择本地缓存技术,可显著提升Web应用的性能、离线能力和用户体验。


JS相关面试题

防抖和节流的区别?应该如何去做?

使用防抖(Debounce)和节流(Throttle)是优化高频事件处理的常用手段。

一、防抖和节流的区别

防抖(Debounce)节流(Throttle)
触发逻辑事件停止触发后延迟执行固定时间间隔内最多执行一次
类比场景电梯门(最后一个人进入后关门)水龙头(稳定间隔滴水)
适用场景输入框搜索联想、窗口resize监听滚动加载、按钮防重复点击
执行次数高频触发时只执行最后一次高频触发时均匀执行

二、防抖和节流分别实现的方法

// 防抖实现
function debounce(fn, delay = 500) {let timer = null;return function(...args) {if (timer) clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);};
}// 节流实现
function throttle(fn, interval = 200) {let lastTime = 0;return function(...args) {const now = Date.now();if (now - lastTime >= interval) {fn.apply(this, args);lastTime = now;}};
}

三、防抖和节流选择原则

  • 需要即时响应但避免过量请求用防抖(如搜索建议)

  • 需要保持操作连贯性用节流(如无限滚动加载)

 js原生input和on-change的区别

在原生 JavaScript 中,input 事件和 change 事件是表单元素(如 <input><select><textarea>)的两种不同行为的事件,它们的核心区别在于触发时机应用场景。以下是详细对比:


一、input 事件与 change 事件的区别

特性input 事件change 事件
触发时机值变化时实时触发(如每次键盘输入)失去焦点且值变化后触发
适用场景实时搜索、输入校验表单提交前校验、值最终确认
兼容性现代浏览器支持所有浏览器支持
响应速度高频触发(需防抖优化)低频触发

二、代码示例对比

<input type="text" id="inputDemo"><script>const inputEl = document.getElementById('inputDemo');// input 事件:每次输入都触发inputEl.addEventListener('input', (e) => {console.log('input 事件:', e.target.value); // 实时输出当前值});// change 事件:失焦且值变化时触发inputEl.addEventListener('change', (e) => {console.log('change 事件:', e.target.value); // 仅失焦后输出最终值});
</script>

测试步骤

  1. 在输入框输入 "hello"(每次按键都会触发 input 事件)。

  2. 点击页面其他区域让输入框失焦,触发 change 事件。

  3. 再次聚焦输入框,不修改内容直接失焦,不会触发 change 事件(值未变化)。


三、总结

  • input vs change

    • 需要实时反馈(如搜索联想)用 input + 防抖。

    • 需要最终确认(如表单提交)用 change

异步请求有哪些方法?

一、XMLHttpRequest (原生)

底层API,所有现代异步请求的基础

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');// 状态监听
xhr.onreadystatechange = function() {if (xhr.readyState === 4) { // 请求完成if (xhr.status === 200) {console.log(JSON.parse(xhr.responseText));} else {console.error('请求失败:', xhr.status);}}
};// 错误处理
xhr.onerror = function() {console.error('网络错误');
};xhr.send();

特点

  • ✅ 兼容性极好(IE6+)

  • ❌ 回调地狱风险

  • ❌ 需手动处理JSON解析


二、Fetch API (现代标准)

基于Promise的标准化方案

fetch('https://api.example.com/data', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ key: 'value' })
})
.then(response => {if (!response.ok) throw new Error('HTTP错误:' + response.status);return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('请求失败:', error));

优化技巧

  • 超时控制:

    const timeout = (ms) => new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), ms)
    );Promise.race([fetch(url), timeout(5000)]).then(...);

特点

  • ✅ 原生Promise链式调用

  • ❌ 默认不携带Cookie(需配置credentials: 'include'

  • ❌ 部分旧浏览器需polyfill


三、Axios (主流第三方库)

功能最全面的请求库

import axios from 'axios';// 发起请求
axios.get('https://api.example.com/data', {params: { id: 123 },timeout: 5000
})
.then(response => console.log(response.data))
.catch(error => {if (error.response) {// 服务器响应异常(4xx/5xx)console.log(error.response.status);} else if (error.request) {// 请求已发出但无响应console.log('无响应:', error.request);} else {// 其他错误console.log('错误:', error.message);}
});// 全局配置
axios.defaults.baseURL = 'https://api.example.com';
axios.interceptors.request.use(config => {config.headers.Authorization = localStorage.getItem('token');return config;
});

核心优势

  • ✅ 自动JSON转换

  • ✅ 请求/响应拦截器

  • ✅ 并发控制:axios.all()

  • ✅ 取消请求:CancelToken


四、async/await (终极异步方案)

用同步写法处理异步(需配合Fetch/Axios)

async function fetchData() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();console.log(data);} catch (error) {console.error('请求失败:', error);}
}// 并行请求
async function fetchMulti() {const [user, posts] = await Promise.all([fetch('/user'),fetch('/posts')]);
}

五、WebSocket (双向实时通信)

非HTTP协议的持久化连接

const socket = new WebSocket('wss://api.example.com/ws');socket.onopen = () => {socket.send(JSON.stringify({ type: 'join' }));
};socket.onmessage = (event) => {console.log('收到消息:', event.data);
};socket.onclose = () => {console.log('连接关闭');
};

六、技术选型对比表

方案适用场景优点缺点
XMLHttpRequest兼容IE的低要求项目无需外部依赖代码冗长、回调地狱
Fetch API现代浏览器项目原生支持、Promise化错误处理不够直观
Axios企业级复杂应用功能全面、拦截器机制需额外引入库
WebSocket实时聊天、股票行情双向实时通信需后端配合协议支持

七、最佳实践建议

  1. 首选Axios:复杂项目用拦截器统一处理鉴权/错误

  2. SSR兼容:服务端渲染使用isomorphic-fetchaxios

  3. 性能优化

    • 请求去重:同一API短时间内只发一次

    • 缓存策略:Cache-Control + 本地缓存

  4. 安全防护

    • CSRF Token自动携带

    • 请求体签名防篡改

掌握这些方法后,可根据项目需求灵活选择最合适的异步通信方案!

js循环机制

JavaScript 的循环机制(事件循环)就像一家繁忙的餐厅,用三步就能理解它的工作原理:


一、餐厅厨房的比喻

角色对应 JavaScript 概念作用
厨师👨🍳主线程(JS 引擎)一次只能炒一个菜(单线程)
服务员💁♀️事件循环(Event Loop)协调谁先上菜(任务调度)
煮面锅🍜异步任务(setTimeout、网络请求等)需要等待的操作
出菜口📤任务队列(Task Queue)存放煮好的面(完成的任务)

二、工作流程(三步走)

1. 先做马上能出餐的菜(同步任务)
  • 场景:顾客点了一份炒饭(同步任务)和一碗需要煮的面(异步任务)

  • 操作

    console.log('开始炒饭'); // 同步任务,立即执行
    setTimeout(() => {      // 异步任务,交给"煮面锅"console.log('面煮好了');
    }, 2000);
    console.log('继续做其他菜'); // 继续执行同步任务

  • 结果输出

    开始炒饭
    继续做其他菜
    (等待2秒...)
    面煮好了

2. 煮好的面要排队(任务队列)
  • 煮面过程

    • 厨师把锅交给后厨(浏览器其他线程处理)

    • 继续做其他菜(执行后续代码)

    • 面煮好后,服务员把面放到出菜口(任务队列)


3. 服务员按规则上菜(事件循环)
  • 规则

    1. VIP 订单先处理(微任务队列)
      比如:Promise 的回调(.then())、MutationObserver

      Promise.resolve().then(() => {console.log('VIP 面条加急处理!');
      });
    2. 普通订单后处理(宏任务队列)
      比如:setTimeoutsetInterval、用户点击事件

  • 完整流程

    1. 做完所有同步任务(炒饭)
    2. 立即处理所有 VIP 订单(微任务)
    3. 如果有新 VIP 订单,继续处理直到清空
    4. 上一个宏任务结束,取一个普通订单(如煮面回调)
    5. 重复这个循环...

三、真实代码示例

console.log('开始点餐'); // 同步任务// 宏任务(普通订单)
setTimeout(() => {console.log('您的面煮好了'); 
}, 0);// 微任务(VIP 订单)
Promise.resolve().then(() => {console.log('VIP 小菜已赠送');
});console.log('继续服务其他顾客'); // 同步任务

输出顺序

开始点餐 继续服务其他顾客 VIP 小菜已赠送 您的面煮好了


四、为什么这样设计?

  • 不卡顿:厨师(主线程)不会傻等煮面(异步任务),可以继续干活

  • 高效:VIP 订单(微任务)能插队处理,保证高优先级任务快速响应

  • 有序:所有任务排队处理,不会出现混乱


下次看到 Promise 和 setTimeout 时,想想这个餐厅模型就明白了! 🍔 → 🍜 → 💁♀️ → 🔁


uniapp相关面试题

uniapp制作的app想上传文件pdf如何实现?

一、完整实现流程

  1. 选择文件 → 2. 校验文件 → 3. 显示预览 → 4. 上传服务器 → 5. 处理结果

二、核心代码实现(全平台兼容版)

<template><view class="container"><!-- 上传按钮 --><button @click="selectPDF" type="primary">选择PDF文件</button><!-- 文件信息展示 --><view v-if="fileInfo" class="file-info"><text>文件名:{{ fileInfo.name }}</text><text>大小:{{ (fileInfo.size / 1024 / 1024).toFixed(2) }}MB</text><button @click="startUpload" type="primary">开始上传</button></view><!-- 进度条 --><progress v-if="progress > 0" :percent="progress" show-info /></view>
</template><script>
export default {data() {return {fileInfo: null,  // 文件信息progress: 0,     // 上传进度uploadTask: null // 上传任务对象(用于取消上传)}},methods: {// 1. 选择PDF文件async selectPDF() {try {const res = await uni.chooseFile({count: 1,type: 'file',extension: ['pdf'],sourceType: ['album', 'camera'] // 相册或文件系统})// 获取文件信息this.fileInfo = {path: res.tempFiles[0].path,name: res.tempFiles[0].name,size: res.tempFiles[0].size}// 预览文件(仅App可用)if (uni.getSystemInfoSync().platform === 'android' || uni.getSystemInfoSync().platform === 'ios') {uni.openDocument({filePath: this.fileInfo.path,fileType: 'pdf'})}} catch (err) {uni.showToast({ title: '选择文件失败', icon: 'none' })}},// 2. 上传文件async startUpload() {if (!this.fileInfo) return// 校验文件大小(示例限制20MB)if (this.fileInfo.size > 20 * 1024 * 1024) {uni.showToast({ title: '文件不能超过20MB', icon: 'none' })return}this.progress = 0try {this.uploadTask = uni.uploadFile({url: 'https://your-api.com/upload',filePath: this.fileInfo.path,name: 'file',formData: {userId: '123',timestamp: Date.now()},success: (res) => {if (res.statusCode === 200) {const data = JSON.parse(res.data)uni.showToast({ title: '上传成功', icon: 'success' })console.log('服务器返回:', data)} else {uni.showToast({ title: `上传失败:${res.errMsg}`, icon: 'none' })}},fail: (err) => {console.error('上传失败:', err)uni.showToast({ title: '上传失败', icon: 'none' })},complete: () => {this.uploadTask = null}})// 监听进度this.uploadTask.onProgressUpdate((res) => {this.progress = res.progress})} catch (err) {uni.showToast({ title: '上传异常', icon: 'none' })}},// 3. 取消上传cancelUpload() {if (this.uploadTask) {this.uploadTask.abort()uni.showToast({ title: '已取消上传', icon: 'none' })}}}
}
</script><style>
.container {padding: 20px;
}
.file-info {margin-top: 20px;padding: 15px;background-color: #f5f5f5;border-radius: 5px;
}
</style>
 

三、关键配置说明

1. 平台适配要点
平台配置项
Android需在manifest.json中添加权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
iOS需在manifest.json中配置:
"ios" : { "permission" : { "NSPhotoLibraryUsageDescription" : "需要访问相册选择文件" } }
所有平台使用uni.chooseFile统一接口,无需处理平台差异
2. 文件选择参数优化
// 更严格的文件类型校验
const isPDF = file.type === 'application/pdf' || file.name.endsWith('.pdf') || /\.pdf$/i.test(file.name)// 获取文件真实路径(App专用)
if (plus.io) {file.realPath = plus.io.convertLocalFileSystemURL(file.path)
}

四、服务器端示例(Node.js + Express)

const express = require('express')
const multer = require('multer')
const path = require('path')
const app = express()// 配置文件存储
const storage = multer.diskStorage({destination: (req, file, cb) => {cb(null, path.join(__dirname, 'uploads'))},filename: (req, file, cb) => {cb(null, `${Date.now()}-${file.originalname}`)}
})// 文件过滤
const fileFilter = (req, file, cb) => {if (file.mimetype === 'application/pdf') {cb(null, true)} else {cb(new Error('只允许上传PDF文件'), false)}
}const upload = multer({ storage,fileFilter,limits: { fileSize: 20 * 1024 * 1024 } // 限制20MB
})// 上传接口
app.post('/upload', upload.single('file'), (req, res) => {console.log('接收到文件:', req.file)console.log('附加参数:', req.body)res.json({code: 200,message: '上传成功',data: {filename: req.file.filename,originalname: req.file.originalname,size: req.file.size,downloadUrl: `/download/${req.file.filename}`}})
})// 启动服务
app.listen(3000, () => {console.log('服务器运行在 http://localhost:3000')
})

五、增强功能实现

1. 断点续传(App端)
// 获取文件分片
const fileManager = plus.io.getFileSystemManager()
fileManager.readFile({filePath: file.path,position: 0,length: chunkSize,success: (res) => {const chunk = res.data// 上传分片逻辑...}
})
2. 文件加密上传
// 使用crypto-js加密
import CryptoJS from 'crypto-js'const encryptFile = (file) => {const wordArray = CryptoJS.lib.WordArray.create(file)return CryptoJS.AES.encrypt(wordArray, 'secret-key').toString()
}
3. 七牛云/OSS直传
// 获取服务端签名后直传
uni.request({url: 'https://your-api.com/get-oss-token',success: (res) => {const ossConfig = res.datauni.uploadFile({url: ossConfig.host,filePath: this.fileInfo.path,name: 'file',formData: {key: ossConfig.key,policy: ossConfig.policy,OSSAccessKeyId: ossConfig.accessid,signature: ossConfig.signature}})}
})
 

六、常见问题解决方案

1. Android文件路径问题
// 转换真实路径
if (this.fileInfo.path.startsWith('file://')) {this.fileInfo.path = this.fileInfo.path.replace('file://', '')
}
2. iOS无法选择文件

检查manifest.json是否正确配置:

"ios" : {"permission" : {"NSPhotoLibraryUsageDescription" : "需要访问相册选择文件","NSPhotoLibraryAddUsageDescription" : "需要保存文件到相册"}
}
3. 大文件上传失败
  • 分片上传(每5MB一个分片)

  • 显示进度和暂停/继续功能

  • 后台服务需支持分片合并

七、性能优化建议

  1. 前端压缩:使用pdf-lib等库压缩PDF

  2. 缓存机制:已上传文件记录MD5避免重复上传

  3. 队列控制:多个文件时限制并发上传数

uni-app实现扫码的几种方式

1、官方扫码接口

优点:uni.scanCode(OBJECT)就可以直接调用,方便快捷,支持安卓、ios,如果制作小程序,便可以直接转换成微信等官方扫码api。
缺点:安卓、ios端识别率非常差,并且扫码耗时很长,很多条件下,无法识别二维码。

2、支付宝扫码插件

直接在插件市场就可以下载使用
优点:免费,并且识别率非常高
缺点:需要配置阿里云控制台,而且阿里在控制台有初始埋点,第一次使用如果没有关闭,会直接短信通知欠费,不能离线扫码,数据安全性不详。

3、华为扫码插件

直接在插件市场就可以下载使用
优点:识别率不错,可以离线扫码
缺点:需要付费88元,我在测试阶段扫码扫出空字符,导致数据传值失败,需要在扫码获取的值做一些处理,下面附上处理 方式。

this.invoicedata = ret.sValue.replace(/[\xa0\x00-\x09\x0b\x0c\x0e-\x1f\x7f]/g, '');

4、微信扫码

优点:免费,识别率高
缺点:目前只支持小程序,没有开放接口。

这道答案来源于uni-app实现扫码的几种方式_uniapp scancode-CSDN博客


CSS相关面试题

PC网页转h5如何响应式布局?

在将 PC 网页转换为 H5 响应式布局时,需遵循移动优先原则并兼顾多端适配。以下是完整实现方案:


一、核心布局策略

<!-- 基础视口配置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><!-- 移动端专用 meta -->
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
1. 弹性容器布局
.container {width: 100%;max-width: 1200px;  /* PC端最大宽度限制 */margin: 0 auto;padding: 0 15px;    /* 移动端安全边距 */display: flex;flex-wrap: wrap;    /* 允许换行适应小屏 */
}
2. 网格系统实现
/* 12列响应式网格 */
.col {flex: 0 0 100%;     /* 移动端默认占满宽度 */padding: 10px;
}@media (min-width: 768px) {.col-md-6 {flex: 0 0 50%;    /* 平板分两列 */}
}@media (min-width: 992px) {.col-lg-3 {flex: 0 0 25%;    /* PC端分四列 */}
}

二、元素级适配方案

1. 字体响应式
:root {font-size: 14px;    /* 基准字号 */
}@media (min-width: 768px) {:root {font-size: 16px;  /* 中屏增大字号 */}
}h1 {font-size: 2rem;    /* 28px -> 32px */line-height: 1.3;
}
2. 图片适配
<picture><!-- 移动端优先加载小图 --><source media="(max-width: 767px)" srcset="mobile.jpg"><!-- 平板 --><source media="(max-width: 991px)" srcset="tablet.jpg"><!-- PC端 --><img src="desktop.jpg" alt="示例" style="width:100%; height:auto;">
</picture>
3. 表格优化
.table-wrapper {overflow-x: auto;  /* 横向滚动 */-webkit-overflow-scrolling: touch;
}table {min-width: 600px;  /* 保持表格最小可读宽度 */
}

三、交互适配技巧

1. 导航栏改造
<!-- 移动端汉堡菜单 -->
<button class="menu-toggle">☰</button>
<nav class="main-nav"><a href="#">首页</a><a href="#">产品</a>
</nav><style>
.menu-toggle {display: none; /* PC端隐藏 */
}@media (max-width: 767px) {.menu-toggle {display: block; /* 移动端显示 */}.main-nav {display: none;position: fixed;top: 0;left: 0;width: 100%;background: white;}.main-nav.active {display: block;}
}
</style>
2. 表单优化
input[type="text"],
input[type="email"] {width: 100%;height: 40px;padding: 8px;font-size: 16px;  /* 避免移动端缩放 */border: 1px solid #ddd;
}

四、性能优化专项

1. 资源按需加载
<!-- 移动端不加载大图 -->
<div class="hero-image" data-src="desktop-bg.jpg" data-mobile-src="mobile-bg.jpg"></div><script>
function loadAdaptiveImage() {const images = document.querySelectorAll('[data-mobile-src]');images.forEach(img => {const src = window.innerWidth < 768 ? img.dataset.mobileSrc : img.dataset.src;img.style.backgroundImage = `url(${src})`;});
}
window.addEventListener('resize', loadAdaptiveImage);
</script>
2. 触控反馈优化
.button {min-width: 44px;   /* 最小点击区域 */min-height: 44px;padding: 12px 24px;transition: opacity 0.3s;
}.button:active {opacity: 0.7;      /* 按压反馈 */
}

五、多端调试方案

1. Chrome 设备模拟
  • 打开 DevTools → Device Toolbar

  • 测试不同DPR(Device Pixel Ratio)

2. 真机调试
# 本地服务绑定IP
npm run dev -- --host 0.0.0.0# 手机访问电脑IP:端口
3. 自动化测试工具
// 使用Puppeteer多分辨率截图
const puppeteer = require('puppeteer');async function testResponsive() {const browser = await puppeteer.launch();const page = await browser.newPage();const devices = [{name: 'mobile', width: 375, height: 667},{name: 'tablet', width: 768, height: 1024},{name: 'desktop', width: 1200, height: 800}];for (let device of devices) {await page.setViewport(device);await page.goto('http://localhost:3000');await page.screenshot({path: `screenshot-${device.name}.png`});}await browser.close();
}
testResponsive();

六、常见问题解决

  • 1px边框问题

.border {position: relative;
}
.border::after {content: '';position: absolute;left: 0;bottom: 0;width: 100%;height: 1px;background: #ddd;transform: scaleY(0.5);
}
  • fixed定位抖动

.header {position: fixed;top: 0;width: 100%;/* 开启GPU加速 */transform: translateZ(0);backface-visibility: hidden;
}

通过以上方案,可实现从PC到H5的高质量响应式适配,兼顾视觉效果与交互体验。核心原则是:弹性布局打底 + 媒体查询微调 + 移动优先交互

css想做动画有哪些方法?

在 CSS 中实现动画主要有以下几种核心方法,每种方法都有其适用场景和特性:


一、基础动画方法

1. Transition(过渡动画)
  • 用途:元素属性变化时的平滑过渡(如 hover 效果)

  • 代码示例

    .box {width: 100px;transition: width 0.3s ease-in-out;
    }
    .box:hover {width: 200px;
    }
  • 特点

    • 只能定义开始和结束状态

    • 支持属性:transformopacitycolor 等可过渡属性

    • 性能优化:优先使用 transform 和 opacity(触发 GPU 加速)

2. Keyframes Animation(关键帧动画)
  • 用途:复杂多阶段动画(如旋转、闪烁)

  • 代码示例

    @keyframes rotate {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
    }.spinner {animation: rotate 2s linear infinite;
    }
  • 核心属性

    animation: name duration timing-function delay iteration-count direction fill-mode;
  • 高级技巧

    • 使用 steps() 函数实现逐帧动画:

      @keyframes walk {from { background-position: 0 0; }to { background-position: -1600px 0; }
      }
      .character {animation: walk 1s steps(8) infinite;
      }

二、性能优化技巧

1. 硬件加速
.animate {transform: translateZ(0); /* 或 will-change: transform; */
}
2. 限制重绘区域
.container {contain: strict; /* 限制浏览器重绘范围 */
}
3. 避免布局抖动
  • 优先使用 transform 替代 top/left 位移

  • 使用 requestAnimationFrame 同步动画(JS 辅助)


三、进阶动画方案

1. CSS 变量驱动动画
:root {--rotate: 0deg;
}.box {transform: rotate(var(--rotate));transition: transform 0.3s;
}/* JS 控制动画 */
box.style.setProperty('--rotate', '45deg');
2. SVG 动画
<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40"><animate attributeName="r" from="40" to="20" dur="1s" repeatCount="indefinite"/></circle>
</svg>
3. 动画库扩展
  • Animate.css(预设动画库):

    <div class="animate__animated animate__bounce"></div>
  • Motion One(现代轻量库):

    import { animate } from "motion";
    animate(".box", { x: 100 }, { duration: 0.3 });

四、方案对比表

方法适用场景优点缺点
Transition简单状态过渡简单高效、性能好无法控制中间状态
Keyframes复杂多阶段动画完全控制动画流程代码量较大
CSS 变量动态控制动画参数灵活、易于JS交互兼容性要求 IE11+
SVG 动画矢量图形动画分辨率无关、路径动画学习成本较高
动画库快速实现复杂效果开箱即用、效果丰富增加项目体积

五、调试工具

  1. Chrome DevTools 动画面板

    • 查看动画时间轴

    • 修改动画参数实时预览

  2. 性能监测

    • 使用 Performance 面板分析帧率

    • 检查 Layout/Paint 耗时


六、最佳实践建议

  1. 优先使用 CSS 原生动画(而非 JS 动画)

  2. 限制同时运行的动画数量(一般不超过 5 个)

  3. 移动端优化

    • 动画时长建议 200-500ms

    • 使用 @media (prefers-reduced-motion) 适配无障碍

    @media (prefers-reduced-motion: reduce) {* { animation: none !important; }
    }

掌握这些方法后,可根据具体需求选择最合适的动画实现方案!🎉

其他综合问题

如何不让网页上的水印被去除?

在PC端页面实现防篡改水印需要综合多种技术手段,以下是一套较为全面的解决方案:

一、动态Canvas水印方案

function createDynamicWatermark(text) {const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');canvas.width = 300;canvas.height = 200;// 绘制基础水印ctx.font = '14px Arial';ctx.fillStyle = 'rgba(200,200,200,0.2)';ctx.rotate(-20 * Math.PI / 180);ctx.fillText(text, 10, 100);// 添加防伪波纹for(let i=0;i<canvas.width;i+=30){ctx.beginPath();ctx.moveTo(i, 0);ctx.lineTo(i, canvas.height);ctx.strokeStyle = 'rgba(0,0,0,0.02)';ctx.stroke();}// 生成动态背景图const dataUrl = canvas.toDataURL();const watermarkDiv = document.createElement('div');watermarkDiv.style.cssText = `position: fixed;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;z-index: 999999;background: url(${dataUrl}) left top repeat;mix-blend-mode: multiply;`;// 防删除保护watermarkDiv.setAttribute('id', 'secure-watermark');Object.defineProperty(watermarkDiv, 'id', {configurable: false,writable: false});document.body.appendChild(watermarkDiv);
}

二、防篡改保护机制

DOM变动监控

const observer = new MutationObserver(mutations => {mutations.forEach(mutation => {Array.from(mutation.removedNodes).forEach(node => {if (node.id === 'secure-watermark') {document.body.appendChild(node);}});});
});observer.observe(document.body, {childList: true,subtree: true
});

样式篡改防御

const styleGuard = setInterval(() => {const watermark = document.getElementById('secure-watermark');if (!watermark) {createDynamicWatermark();return;}const styles = window.getComputedStyle(watermark);const protectedProps = {'display': 'block','opacity': '1','visibility': 'visible'};Object.entries(protectedProps).forEach(([prop, value]) => {if (styles[prop] !== value) {watermark.style[prop] = value;}});
}, 1000);

三、用户行为监控

window.addEventListener('keydown', (e) => {// 屏蔽开发者工具快捷键const devtoolKeys = [e.ctrlKey && e.keyCode === 85, // Ctrl+Ue.ctrlKey && e.shiftKey && e.keyCode === 73, // Ctrl+Shift+Ie.keyCode === 123 // F12];if (devtoolKeys.some(Boolean)) {e.preventDefault();alert('安全警告:禁止开发者工具操作!');window.location.reload();}
});// 防止右键检查
document.addEventListener('contextmenu', (e) => {e.preventDefault();return false;
});// 防截图干扰
const noiseCanvas = document.createElement('canvas');
noiseCanvas.style.cssText = `position: fixed;top:0;left:0;pointer-events: none;z-index: 9999999;
`;
document.body.appendChild(noiseCanvas);function generateNoise() {const ctx = noiseCanvas.getContext('2d');const imageData = ctx.createImageData(noiseCanvas.width, noiseCanvas.height);const data = imageData.data;for(let i=0;i<data.length;i+=4){const val = Math.random()*255;data[i] = data[i+1] = data[i+2] = val;data[i+3] = 5; }ctx.putImageData(imageData, 0, 0);requestAnimationFrame(generateNoise);
}noiseCanvas.width = window.innerWidth;
noiseCanvas.height = window.innerHeight;
generateNoise();

四、服务端配合方案

  • 动态水印信息

// 每次请求携带动态token
async function getWatermarkText() {const res = await fetch('/api/watermark-token');const { token } = await res.json();return `机密 ${token} ${Date.now()}`;
}// 定期更新水印
setInterval(async () => {const newText = await getWatermarkText();updateWatermark(newText);
}, 300000);
  • 内容加密验证

// 使用CryptoJS进行内容签名
const contentHash = CryptoJS.HmacSHA256(document.body.innerText, 'secretKey'
).toString();// 后台校验示例
app.post('/verify-content', (req, res) => {const clientHash = req.body.hash;const serverHash = CryptoJS.HmacSHA256(req.body.content,'secretKey').toString();if(clientHash !== serverHash) {// 触发内容篡改警报sendAlert('检测到内容篡改!');}
});

五、防御等级说明

防御层级技术手段防御能力
初级防御基础CSS水印★☆☆☆☆
中级防御Canvas动态水印+DOM监控★★★☆☆
高级防御行为监控+服务端验证★★★★☆
终极防御硬件级DRM方案★★★★★

注意事项:

  1. 定期更新水印算法(建议每月迭代)

  2. 结合业务日志记录用户操作行为

  3. 重要数据建议使用PDF等不可逆格式展示

  4. 法律层面增加水印声明条款

任何前端方案都无法做到绝对防篡改,建议根据业务安全等级选择适当方案,关键数据应结合后端验证和权限控制。

HTTP和HTTPS的区别

HTTP(超文本传输协议)和 HTTPS(安全超文本传输协议)的核心区别在于数据传输的安全性,以下是两者的详细对比:


一、核心区别总结

特性HTTPHTTPS
安全性明文传输,数据可被窃听/篡改加密传输,防窃听/防篡改
协议应用层协议HTTP + SSL/TLS 安全层
默认端口80443
证书无需证书需CA机构颁发的SSL证书
性能无加密开销,速度稍快有加密计算开销,但现代硬件影响可忽略
SEO搜索引擎可能降权搜索引擎优先收录(如Google明确支持)

二、技术实现差异

1. 加密机制(核心)
  • HTTP
    数据以明文形式传输,可直接被中间人读取:

    GET /login HTTP/1.1
    Host: example.com
    username=admin&password=123456  ← 明文传输!
  • HTTPS
    通过SSL/TLS协议加密数据,传输内容为密文:

    ���]�k�M�I�4��Q�V��x�d� ← 加密后的乱码数据
2. SSL/TLS工作流程
  1. 握手阶段(非对称加密):

    • 客户端验证服务器证书有效性

    • 协商加密算法(如RSA、ECDHE)

    • 生成会话密钥(Session Key)

  2. 数据传输(对称加密):

    • 使用会话密钥加密通信内容


三、HTTPS核心优势

1. 防窃听(Encryption)
  • 所有数据加密传输,即使被截获也无法解密

  • 示例:公共WiFi下登录账号时,HTTPS可防止密码泄露

2. 防篡改(Integrity)
  • 使用MAC(消息认证码)验证数据完整性

  • 示例:阻止运营商插入广告代码

3. 身份认证(Authentication)
  • SSL证书验证网站真实身份,防止钓鱼网站

  • 示例:浏览器地址栏显示锁标志和公司名称


四、部署HTTPS的要求

1. SSL证书类型
证书类型验证等级适用场景
DV(域名验证)验证域名所有权个人博客、小型网站
OV(组织验证)验证企业/组织身份企业官网
EV(扩展验证)严格身份验证(地址栏绿标)银行、电商等敏感领域
2. 部署步骤
  1. 购买或申请免费证书(如Let's Encrypt)

  2. 在服务器安装证书(Nginx示例):

    server {listen 443 ssl;ssl_certificate /path/to/cert.pem;ssl_certificate_key /path/to/private.key;
    }
  3. 强制HTTP跳转HTTPS:

    server {listen 80;return 301 https://$host$request_uri;
    }

五、性能优化技巧

  1. 会话复用(Session Resumption)
    减少SSL握手次数,降低延迟:

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

  2. 启用HTTP/2
    HTTPS下可启用HTTP/2协议提升性能:

    listen 443 ssl http2;

六、常见误解澄清

  • 误区1:"HTTPS会显著拖慢网站速度"
    → 现代服务器性能下,TLS握手开销仅增加约1 RTT(经优化可降至0 RTT)

  • 误区2:"只有支付页面需要HTTPS"
    → 现代Web标准(如PWA、Geolocation API)要求全站HTTPS

  • 误区3:"HTTPS无法被劫持"
    → 若客户端安装伪证书(如企业监控),仍可能被中间人攻击


七、如何验证HTTPS安全性

  1. 浏览器地址栏显示锁形图标

  2. 通过SSL Labs测试检查配置:

    Rating: A+ (最佳评级)

总结:HTTPS通过加密和身份验证构建安全传输通道,是现代Web应用的必备基础,所有新建网站都应默认启用HTTPS

前端浏览器安全如何注意?

为了保障前端浏览器的安全性,需要从代码防护、数据传输、用户输入处理等多方面入手。以下是系统化的安全防护方案及具体实施方法:


一、基础防护体系

1. 启用HTTPS强制加密
# Nginx配置(强制跳转HTTPS)
server {listen 80;server_name example.com;return 301 https://$host$request_uri;
}

附加措施

  • 使用HSTS头(强制浏览器使用HTTPS)

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
2. 安全头配置
# 安全响应头示例
add_header X-Frame-Options "SAMEORIGIN";               # 防点击劫持
add_header X-Content-Type-Options "nosniff";          # 禁止MIME嗅探
add_header Referrer-Policy "strict-origin-when-cross-origin"; # 控制Referer泄露
add_header Permissions-Policy "geolocation=()";       # 禁用不必要权限

二、攻击防御专项

1. XSS(跨站脚本攻击)防御
  • 输入过滤

    // 使用DOMPurify过滤HTML
    import DOMPurify from 'dompurify';
    const cleanHTML = DOMPurify.sanitize(userInput);
  • 输出转义

    <!-- Vue自动转义 -->
    <div>{{ userContent }}</div><!-- 手动转义 -->
    <div v-html="safeHTML"></div>
  • CSP策略

    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'">
2. CSRF(跨站请求伪造)防御
  • Token验证

    // 后端生成Token
    const csrfToken = crypto.randomBytes(32).toString('hex');
    res.cookie('XSRF-TOKEN', csrfToken);// 前端发送请求携带Token
    axios.defaults.headers.common['X-XSRF-TOKEN'] = getCookie('XSRF-TOKEN');
  • SameSite Cookie

    // 设置Cookie属性
    res.cookie('sessionID', '123', { sameSite: 'Strict', secure: true 
    });
3. 点击劫持防御
add_header X-Frame-Options "DENY";  # 完全禁止嵌入
# 或
add_header Content-Security-Policy "frame-ancestors 'self'"; 

三、数据安全防护

1. 敏感数据处理
  • 前端加密

    // 使用Web Crypto API加密
    const encryptedData = await crypto.subtle.encrypt({ name: 'AES-GCM', iv },key,new TextEncoder().encode(data)
    );
  • 安全存储

    // 避免localStorage存储敏感信息
    sessionStorage.setItem('tempData', encryptedData);
2. 第三方资源校验
<!-- 使用SRI校验CDN资源 -->
<script src="https://cdn.example.com/jquery.js" integrity="sha384-...">
</script>

四、用户输入与认证

1. 输入验证
// 邮箱格式校验
const isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);// 防止SQL注入
const sanitizeInput = (input) => input.replace(/['"\\;]/g, '');
2. 认证安全
  • 密码策略

    // 前端密码强度校验
    const isStrongPassword = (pwd) => pwd.length >= 8 && /[A-Z]/.test(pwd) && /[0-9]/.test(pwd);
  • 双因素认证

    // 集成Google Authenticator
    import { authenticator } from 'otplib';
    const secret = authenticator.generateSecret();
    const token = authenticator.generate(secret);

五、持续监控与更新

1. 依赖安全扫描
# 使用npm audit检查漏洞
npm audit# 使用Snyk深度检测
npx snyk test
2. 实时监控
  • 错误追踪:接入Sentry监控XSS等异常

  • 入侵检测:部署WAF(Web应用防火墙)


六、安全等级对照表

安全等级适用场景防护措施
基础级小型展示网站HTTPS + CSP + XSS过滤
标准级企业级应用基础级 + CSRF Token + 输入验证 + 安全头
高级级金融/政务系统标准级 + 双因素认证 + 实时监控 + 前端加密 + 人工渗透测试

七、应急响应方案

  1. 漏洞响应流程

    • 发现漏洞 → 评估影响 → 热修复 → 通知用户

  2. 数据泄露处理

    • 立即重置相关凭证

    • 启用日志审计追溯攻击路径

    • 根据法律要求通知受影响用户


通过以上综合措施,可构建多层次的前端安全防护体系。关键点在于:默认安全原则 + 纵深防御 + 持续监控,同时需结合具体业务场景调整防护策略。


PC端开发大文件如何上传?卡住了怎么办?失败了后如何继续上传?

在前端PC端实现大文件上传并处理中断和续传的问题,可以采用分块上传与断点续传的策略。以下是详细的解决方案:


1. 分块上传(Chunked Upload)

将大文件分割为多个小块(如1MB/块),分别上传,降低单次请求压力,便于失败后重试。

实现步骤:
  1. 前端分块处理:

    const CHUNK_SIZE = 1 * 1024 * 1024; // 1MB
    const file = document.getElementById('file-input').files[0];
    const chunks = [];
    let start = 0;while (start < file.size) {const chunk = file.slice(start, start + CHUNK_SIZE);chunks.push(chunk);start += CHUNK_SIZE;
    }
  2. 生成文件唯一标识:
    使用文件内容的哈希(如SHA-256)作为唯一标识,避免同名文件冲突。

    async function computeFileHash(file) {const buffer = await file.arrayBuffer();const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
    }
  3. 上传单个块:

    async function uploadChunk(chunk, chunkIndex, fileHash) {const formData = new FormData();formData.append('chunk', chunk);formData.append('chunkIndex', chunkIndex);formData.append('fileHash', fileHash);formData.append('totalChunks', totalChunks);await fetch('/upload-chunk', {method: 'POST',body: formData,});
    }

2. 断点续传(Resumable Upload)

记录已上传的块,失败后仅上传缺失部分。

实现步骤:
  1. 查询服务器已上传的块:

    async function getUploadedChunks(fileHash) {const response = await fetch(`/uploaded-chunks?fileHash=${fileHash}`);return await response.json(); // 返回已上传的块索引数组,如[0,1,2]
    }
  2. 过滤未上传的块并继续上传:

    const uploadedChunks = await getUploadedChunks(fileHash);
    const chunksToUpload = chunks.filter((_, index) => !uploadedChunks.includes(index));// 控制并发上传(如最多5个并行)
    const MAX_CONCURRENT = 5;
    const queue = chunksToUpload.map((chunk, index) => () => uploadChunk(chunk, index, fileHash));// 使用p-limit库控制并发
    import pLimit from 'p-limit';
    const limit = pLimit(MAX_CONCURRENT);
    await Promise.all(queue.map(task => limit(task)));

3. 失败处理与重试

  • 网络错误重试: 为每个块的上传添加重试机制。

    async function uploadWithRetry(chunk, chunkIndex, fileHash, retries = 3) {try {await uploadChunk(chunk, chunkIndex, fileHash);} catch (error) {if (retries > 0) {await uploadWithRetry(chunk, chunkIndex, fileHash, retries - 1);} else {throw error;}}
    }

  • 服务端错误处理: 返回明确的错误状态码,前端根据状态码决定重试或报错。


4. 服务器端实现

关键接口:
  1. 上传块接口(/upload-chunk):

    • 接收块文件、块索引、文件哈希。

    • 将块保存到临时目录(按文件哈希组织)。

  2. 查询已上传块接口(/uploaded-chunks):

    • 根据文件哈希返回已上传的块索引列表。

  3. 合并文件接口(/merge-file):

    • 所有块上传完成后,按顺序合并成完整文件。

示例伪代码(Node.js):
// 保存块
app.post('/upload-chunk', (req, res) => {const { chunk, chunkIndex, fileHash } = req.body;const chunkDir = `./temp/${fileHash}`;fs.mkdirSync(chunkDir, { recursive: true });fs.writeFileSync(`${chunkDir}/${chunkIndex}`, chunk.buffer);res.status(200).send('Chunk uploaded');
});// 合并文件
app.post('/merge-file', (req, res) => {const { fileHash, fileName } = req.body;const chunkDir = `./temp/${fileHash}`;const chunks = fs.readdirSync(chunkDir).sort((a, b) => a - b);const filePath = `./uploads/${fileName}`;chunks.forEach(chunk => {fs.appendFileSync(filePath, fs.readFileSync(`${chunkDir}/${chunk}`));});fs.rmdirSync(chunkDir, { recursive: true }); // 清理临时文件res.status(200).send('File merged');
});

5. 用户体验优化

  • 进度显示: 监听每个块的上传进度,计算总进度。

    let uploadedSize = 0;
    chunks.forEach((chunk, index) => {uploadChunk(chunk, index).then(() => {uploadedSize += chunk.size;const progress = (uploadedSize / file.size) * 100;updateProgressBar(progress);});
    });
  • 暂停/恢复: 使用AbortController取消请求,保存已上传状态。

    const controllers = new Map();function uploadChunk(chunk, index) {const controller = new AbortController();controllers.set(index, controller);return fetch(url, {signal: controller.signal,// ...});
    }// 暂停上传
    function pauseUpload() {controllers.forEach(controller => controller.abort());
    }

6. 注意事项

  • 文件一致性校验: 合并后对比服务器端文件的哈希与前端计算的哈希。

  • 清理临时文件: 设置定时任务清理未完成的过期上传。

  • 分块大小调整: 根据网络情况动态调整块大小(如1MB-5MB)。

通过上述方案,可有效解决大文件上传中的中断、续传和失败重试问题,提升用户体验。


如何记录接口报错并且展示?

在前端中记录接口报错并展示错误信息,是提升用户体验和排查问题的重要手段。以下是分步骤的实现方案:


一、错误捕获与记录

1. 使用请求拦截器(以 Axios 为例)
// 创建 axios 实例
const instance = axios.create();// 响应拦截器
instance.interceptors.response.use((response) => response,(error) => {const { config, response } = error;const errorInfo = {time: new Date(),url: config?.url,method: config?.method,status: response?.status,message: response?.data?.message || error.message,};// 记录错误(可扩展为上报服务器)logError(errorInfo);// 展示错误(可选,部分错误可能不需要立即展示)showErrorUI(errorInfo);return Promise.reject(error);}
);
2. 错误日志记录方式
  • 本地存储(临时记录)

    function logError(error) {const MAX_LOG_SIZE = 50;const logs = JSON.parse(localStorage.getItem('api_errors') || []);logs.push(error);if (logs.length > MAX_LOG_SIZE) logs.shift();localStorage.setItem('api_errors', JSON.stringify(logs));
    }
  • 上报到服务器(推荐生产环境使用)

    function reportErrorToServer(error) {navigator.sendBeacon('/api/logs', JSON.stringify(error));
    }

二、错误展示策略

1. 通用错误提示组件(React 示例)
import { Toast } from 'antd-mobile';function showErrorUI(error) {let message = '请求失败,请稍后重试';// 根据错误类型定制提示if (error.status === 401) {message = '登录已过期,请重新登录';redirectToLogin();} else if (error.status >= 500) {message = '服务器开小差了,请联系管理员';}Toast.show({content: message,duration: 3000,icon: 'fail',});
}
2. 专用错误信息面板
function ErrorPanel() {const [errors, setErrors] = useState([]);useEffect(() => {const errors = JSON.parse(localStorage.getItem('api_errors')) || [];setErrors(errors);}, []);return (<div className="error-panel"><h3>最近接口错误 ({errors.length})</h3>{errors.map((err, i) => (<div key={i} className="error-item"><p>[{err.time}] {err.method} {err.url}</p><p>状态码: {err.status} | 信息: {err.message}</p></div>))}</div>);
}

三、高级优化方案

  1. 错误分类处理

    function handleErrorByType(error) {if (!navigator.onLine) {showNetworkError();} else if (error.code === 'ECONNABORTED') {showTimeoutError();} else {showGenericError();}
    }
  2. 错误频率限制

    let lastToastTime = 0;
    function showError(message) {if (Date.now() - lastToastTime > 5000) {Toast.show(message);lastToastTime = Date.now();}
    }
  3. 敏感信息过滤

    function sanitizeError(error) {const sanitized = { ...error };delete sanitized.headers.Authorization;delete sanitized.request.body.password;return sanitized;
    }

四、技术栈扩展建议

  • 错误监控平台集成

    • 使用 Sentry/Bugsnag 进行专业错误监控

    import * as Sentry from '@sentry/browser';
    Sentry.init({ dsn: 'your_dsn' });function logError(error) {Sentry.captureException(new Error(error.message), {extra: error.context});
    }
  • 性能监控结合

    const startTime = Date.now();
    axios.get('/api/data').then(() => {logApiPerformance(Date.now() - startTime);});

五、注意事项

  1. 生产环境应避免显示原始错误堆栈

  2. 401 错误需要特殊处理(清除登录态)

  3. 重要接口可加入自动重试机制

    function retryRequest(config, retries = 3) {return axios(config).catch(err => {return retries > 0 ? retryRequest(config, retries - 1): Promise.reject(err);});
    }

通过以上方案,可以实现完整的接口错误处理流程,平衡用户体验与开发调试需求。建议根据具体业务场景选择适合的优化点进行扩展。
 

前端输入url后浏览器会先做什么?

以下是前端输入 URL 后浏览器的主要处理流程,按顺序分阶段说明:


一、URL 解析阶段(URL Parsing

  1. 协议补全
    自动补全协议头(如输入 google.com → 补全为 https://google.com

  2. 格式校验
    检查 URL 合法性(如特殊字符转换 空格→%20


二、缓存检查阶段(Cache Check

缓存类型检查顺序典型场景
Service Worker最先检查PWA 离线缓存
Memory Cache内存缓存(短期)前进后退页面
Disk Cache磁盘缓存(长期)CSS/JS 文件缓存
Push CacheHTTP/2 推送缓存(会话级)服务器推送资源

*触发强制刷新(Ctrl+F5)时会跳过所有缓存*


三、DNS 解析阶段(DNS Lookup

  • 优化手段

    <!-- 预解析特定域名 -->
    <link rel="dns-prefetch" href="//cdn.example.com">

四、建立连接阶段(TCP Handshake

  1. 三次握手建立 TCP 连接

    Client->Server: SYN
    Server->Client: SYN-ACK
    Client->Server: ACK
  2. TLS 握手(HTTPS)

    • 协商加密协议版本

    • 验证证书有效性

    • 交换对称加密密钥


五、发送请求阶段(HTTP Request

GET /index.html HTTP/1.1
Host: www.example.com
Accept: text/html
Cookie: session_id=abc123
  • 关键过程

    • 携带 Cookie 等身份信息

    • 检查 Connection: keep-alive 复用连接

    • 处理 Content-Encoding 压缩格式


六、响应处理阶段(Response Processing

  1. 状态码处理

    // 常见状态码处理逻辑
    switch(statusCode) {case 301:handleRedirect(response.headers.Location);break;case 404:show404Page();break;case 500:logServerError();break;
    }
  2. 解压响应体

    • 自动处理 gzip/deflate 压缩


七、解析渲染阶段(Rendering

  • 关键阻塞点

    • <script> 标签会阻塞 DOM 构建(除非添加 async/defer

    • CSS 文件会阻塞渲染树合成(CSSOM 构建)


八、持续通信阶段(Keep-Alive

  • TCP 连接复用

    // HTTP/1.1 默认开启 keep-alive
    // 同一域名最多维持 6 个 TCP 连接(浏览器差异)
  • HTTP/2 多路复用

    • 单个连接并行传输多个请求

    • 头部压缩优化


关键性能优化点

  1. 减少 DNS 查询(使用 dns-prefetch)

  2. 复用 TCP 连接(合理配置 keep-alive)

  3. 压缩资源体积(Gzip/Brotli)

  4. 避免渲染阻塞(CSS 内联/JS 异步加载)

  5. 利用 CDN 加速(减少网络延迟)

理解整个流程可以帮助前端开发者针对性优化关键路径,提升页面加载性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/905310.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab基于SSA-MVMD麻雀算法优化多元变分模态分解

Matlab基于SSA-MVMD麻雀算法优化多元变分模态分解 目录 Matlab基于SSA-MVMD麻雀算法优化多元变分模态分解效果一览基本介绍程序设计参考资料效果一览 基本介绍 Matlab基于SSA-MVMD麻雀算法优化多元变分模态分解 可直接运行 分解效果好 适合作为创新点(Matlab完整源码和数据),…

Gatsby知识框架

一、Gatsby 基础概念 1. 核心特性 基于React的静态站点生成器&#xff1a;使用React构建&#xff0c;输出静态HTML/CSS/JS GraphQL数据层&#xff1a;统一的数据查询接口 丰富的插件系统&#xff1a;超过2000个官方和社区插件 高性能优化&#xff1a;自动代码分割、预加载、…

【论信息系统项目的资源管理】

论信息系统项目的资源管理 前言一、规划好资源管理&#xff0c;为保证项目完成做好人员规划二、估算活动资源&#xff0c;为制订项目进度计划提供资源需求三、获取项目资源&#xff0c;组建一个完备的项目团队四、建设项目团队&#xff0c;提高工作能力&#xff0c;促进团队成员…

idea Maven 打包SpringBoot可执行的jar包

背景&#xff1a;当我们需要坐联调测试的时候&#xff0c;需要对接前端同事&#xff0c;则需要打包成jar包直接运行启动服务 需要将项目中的pom文件增加如下代码配置&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</gr…

VScode 的插件本地更改后怎么生效

首先 vscode 的插件安装地址为 C:\Users\%USERNAME%\.vscode\extensions 找到你的插件包进行更改 想要打印日志&#xff0c;用下面方法 vscode.window.showErrorMessage(console.log "${name}" exists.); 打印结果 找到插件&#xff0c;点击卸载 然后点击重新启动 …

Python训练营打卡——DAY24(2025.5.13)

目录 一、元组 1. 通俗解释 2. 元组的特点 3. 元组的创建 4. 元组的常见用法 二、可迭代对象 1. 定义 2. 示例 3. 通俗解释 三、OS 模块 1. 通俗解释 2. 目录树 四、作业 1. 准备工作 2. 实战代码示例​ 3. 重要概念解析 一、元组 是什么​​&#xff1a;一种…

初入OpenCV

OpenCV简介 OpenCV是一个开源的跨平台计算机视觉库&#xff0c;它实现了图像处理和计算机视觉方面的很多通用算法。 应用场景&#xff1a; 目标识别&#xff1a;人脸、车辆、车牌、动物&#xff1b; 自动驾驶&#xff1b;医学影像分析&#xff1b; 视频内容理解分析&#xff…

讯联云库项目开发日志(一)

1、设计数据库 2、写基本框架 entity、controller、service、exception、utils、mapper mapper层&#xff1a; 生成了一系列的CRUD方法 工具类&#xff1a;线程安全的日期工具类、 ​​参数校验工具类​ 线程安全的日期工具类​​&#xff1a;主要用于 ​​日期格式化&…

langchain学习

无门槛免费申请OpenAI ChatGPT API搭建自己的ChatGPT聊天工具 https://nuowa.net/872 基本概念 LangChain 能解决大模型的两个痛点&#xff0c;包括模型接口复杂、输入长度受限离不开自己精心设计的模块。根据LangChain 的最新文档&#xff0c;目前在 LangChain 中一共有六大…

Protobuf工具

#region 知识点一 什么是 Protobuf //Protobuf 全称是 protocol - buffers&#xff08;协议缓冲区&#xff09; // 是谷歌提供给开发者的一个开源的协议生成工具 // 它的主要工作原理和我们之前做的自定义协议工具类似 // 只不过它更加的完善&…

zst-2001 上午题-历年真题 软件工程(38个内容)

CMM 软件工程 - 第1题 b 软件工程 - 第2题 c 软件工程 - 第3题 c 软件工程 - 第4题 b 软件工程 - 第5题 b CMMI 软件工程 - 第6题 0.未完成&#xff1a;未执行未得到目标。1.已执行&#xff1a;输入-输出实现支持2.已管理&#xff1a;过程制度化&#x…

软考架构师考试-UML图总结

考点 选择题 2-4分 案例分析0~1题和面向对象结合考察&#xff0c;前几年固定一题。近3次考试没有出现。但还是有可能考。 UML图概述 1.用例图&#xff1a;描述系统功能需求和用户&#xff08;参与者&#xff09;与系统之间的交互关系&#xff0c;聚焦于“做什么”。 2.类图&…

数据结构(七)——图

一、图的定义与基本术语 1.图的定义 图G由顶点集V和边集E组成&#xff0c;记为G(V,E)&#xff0c;其中V(G)表示图G中顶点的有限非空集&#xff1b;E(G)表示图G中顶点之间的关系&#xff08;边&#xff09;的集合 注意&#xff1a;线性表可以是空表&#xff0c;树可以是空树&…

Android7 Input(六)InputChannel

概述: 本文讲述Android Input输入框架中 InputChannel的功能。从前面的讲述&#xff0c;我们知道input系统服务最终将输入事件写入了InputChannel&#xff0c;而input属于system_server进程&#xff0c;App属于另外一个进程&#xff0c;当Input系统服务想要把事件传递给App进行…

【 Redis | 实战篇 秒杀实现 】

目录 前言&#xff1a; 1.全局ID生成器 2.秒杀优惠券 2.1.秒杀优惠券的基本实现 2.2.超卖问题 2.3.解决超卖问题的方案 2.4.基于乐观锁来解决超卖问题 3.秒杀一人一单 3.1.秒杀一人一单的基本实现 3.2.单机模式下的线程安全问题 3.3.集群模式下的线程安全问题 前言&…

如何用URDF文件构建机械手模型并与MoveIt集成

机械手URDF文件的编写 我们用urdf文件来描述我们的机械手的外观以及物理性能。这里为了简便&#xff0c;就只用了基本的圆柱、立方体了。追求美观的朋友&#xff0c;还可以用dae文件来描述机械手的外形。 import re def remove_comments(text):pattern r<!--(.*?)-->…

《构建社交应用的安全结界:双框架对接审核API的底层逻辑与实践》

用户生成内容如潮水般涌来。从日常的生活分享&#xff0c;到激烈的观点碰撞&#xff0c;这些内容赋予社交应用活力&#xff0c;也带来管理难题。虚假信息、暴力言论、侵权内容等不良信息&#xff0c;如同潜藏的暗礁&#xff0c;威胁着社交平台的健康生态。内容审核机制&#xf…

39:分类器流程

第一步 创建支持向量机分类器 create_class_svm (7, rbf, KernelParam, Nu, |ClassNames|, one-versus-one, principal_components, 5, SVMHandle) 第二步 添加样本到分类器里 for ClassNumber : 0 to |ClassNames| - 1 by 1 *列出目录下的所有文件 list_files (ReadPath…

LangChain对话链:打造智能多轮对话机器人

LangChain对话链:打造智能多轮对话机器人 目录 LangChain对话链:打造智能多轮对话机器人ConversationChain 是什么核心功能与特点基本用法示例内存机制自定义提示词应用场景与其他链的结合`SequentialChain` 是什么![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0…

el-select 结合 el-tree:树形下拉数据

一、单选 <template><div class"selectTree-wapper"><el-selectv-model"selectValue"placeholder"请选择"popper-class"custom-el-select-class"ref"selectRef"clearableclear"clearHandle">&…