前端实践问题

拖拽过程中,如果原本的元素消失了,onDrop还能触发么?具体表现是什么?

即使原始元素在拖拽过程中被移除了,只要拖拽操作未被中断,onDrop 事件仍然可以触发

  1. 拖拽数据独立存储
    拖拽操作一旦开始(dragstart),浏览器会将拖拽数据存储在独立的 DataTransfer 对象中。即使原始元素被移除,已存储的拖拽数据依然有效

  2. 视觉反馈与 DOM 解耦
    拖拽过程中显示的「拖拽预览图像」是浏览器生成的副本,与原始元素的 DOM 状态无关。即使原始元素消失,预览图像通常仍会正常显示。

具体表现

1. onDrop 正常触发

  • 如果拖拽操作成功完成(用户释放鼠标在有效的拖放目标上),onDrop 仍会触发。

  • 可以通过 event.dataTransfer.getData() 正常获取拖拽数据。

  • 示例代码

     
    // 拖拽源元素
    source.addEventListener('dragstart', (e) => {e.dataTransfer.setData('text/plain', 'Hello World');e.target.remove(); // 立即移除原始元素
    });// 放置目标
    target.addEventListener('drop', (e) => {e.preventDefault();console.log(e.dataTransfer.getData('text/plain')); // 输出 "Hello World"
    });

2. dragend 事件可能异常

  • 如果原始元素被移除,其 dragend 事件可能无法触发,或触发时因元素不存在而导致关联逻辑出错。

  • 示例问题

     
    source.addEventListener('dragend', () => {console.log('拖拽结束'); // 可能不会执行
    });

3. 意外中断拖拽操作

  • 如果在 dragstart 中直接移除元素,某些浏览器可能因渲染更新而意外终止拖拽操作,导致 onDrop 无法触发。

  • 解决方案:使用异步移除(如 setTimeout)确保拖拽操作初始化完成:
source.addEventListener('dragstart', (e) => {e.dataTransfer.setData('text/plain', 'Hello World');setTimeout(() => e.target.remove(), 0); // 异步移除
});

总结

  • onDrop 触发条件:仅取决于用户是否在有效的目标上释放鼠标,与原始元素是否存在无关。

  • 风险点dragend 事件可能不可靠,且直接移除元素可能导致浏览器行为不一致。

  • 最佳实践:如需移除原始元素,建议在 dragend 或 drop 事件中处理,而非 dragstart

如何改变拖拽预览图?如何让拖拽预览图有圆角?

一、核心方法:setDragImage()

通过 dragstart 事件的 dataTransfer.setDragImage() 方法,可直接指定拖拽预览图

代码示例

element.addEventListener('dragstart', (e) => {// 1. 创建一个自定义预览元素const preview = document.createElement('div');preview.textContent = "拖拽我";preview.style.cssText = `width: 100px;height: 40px;background: #2196F3;color: white;border-radius: 8px;  // 关键:圆角样式display: flex;align-items: center;justify-content: center;`;// 2. 将元素临时添加到 DOM 中(部分浏览器需要渲染才能捕获图像)document.body.appendChild(preview);// 3. 设置为拖拽预览图,并指定光标偏移位置(居中)e.dataTransfer.setDragImage(preview, preview.offsetWidth / 2, preview.offsetHeight / 2);// 4. 立即移除临时元素(可选)setTimeout(() => document.body.removeChild(preview), 0);
});

二、实现圆角的注意事项

1. 必须确保元素已渲染

  • 部分浏览器(如 Firefox)要求预览元素必须已插入 DOM 并完成渲染,否则无法生成图像。

  • 解决方案:临时添加到 DOM 后立即移除。

2. 使用 Canvas 生成复杂预览

若需要更复杂的图形(如带阴影的圆角矩形),可通过 Canvas 生成图像:

const canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 40;
const ctx = canvas.getContext('2d');// 绘制圆角矩形
ctx.beginPath();
ctx.roundRect(0, 0, 100, 40, 8);  // 圆角半径 8px
ctx.fillStyle = '#2196F3';
ctx.fill();// 设置为拖拽预览
e.dataTransfer.setDragImage(canvas, 50, 20);  // 偏移到中心

三、浏览器兼容性

方法 Chrome Firefox Safari
setDragImage()
Canvas 作为预览图
未渲染元素的 setDragImage

四、完整示例(含圆角和动画)

<style>.drag-item {width: 120px;padding: 12px;background: #4CAF50;color: white;cursor: grab;}
</style><div class="drag-item" draggable="true">拖拽我</div><script>document.querySelector('.drag-item').addEventListener('dragstart', (e) => {// 创建预览元素const preview = document.createElement('div');preview.textContent = "正在拖拽...";preview.style.cssText = `width: 120px;padding: 12px;background: #4CAF50;color: white;border-radius: 8px;box-shadow: 0 2px 8px rgba(0,0,0,0.2);opacity: 0.8;`;// 临时插入 DOMdocument.body.appendChild(preview);e.dataTransfer.setDragImage(preview, 60, 20); // 居中偏移setTimeout(() => preview.remove(), 0);});
</script>

五、高级技巧

1. 动态预览内容

preview.innerHTML = `<div style="display: flex; align-items: center;"><img src="icon.png" width="24"><span>${e.target.textContent}</span></div>
`;

2. 隐藏默认预览

e.dataTransfer.setDragImage(new Image(), 0, 0);  // 设置透明图像

通过 setDragImage() 结合 CSS 或 Canvas,可以完全控制拖拽预览图的样式,包括圆角、阴影等复杂效果。

如何让 echart 的内容跟随容器大小而变化?onResize 的时候要怎么做?如果有可伸缩侧边栏之类的,导致容器因为其他原因发生了改变,应该用什么事件监听? 

核心方法:resize() + 尺寸监听

ECharts 实例通过 resize() 方法重新计算尺寸,需在容器尺寸变化时手动调用。


一、基础场景:窗口缩放

监听浏览器窗口的 resize 事件:

const chart = echarts.init(document.getElementById('chart-container'));// 监听窗口变化
window.addEventListener('resize', () => {chart.resize();
});

二、进阶场景:容器尺寸动态变化(如侧边栏伸缩)

1. 使用 ResizeObserver(推荐)

  • 直接监听容器尺寸变化,无需依赖父级元素事件

  • 代码示例:

    const container = document.getElementById('chart-container');
    const chart = echarts.init(container);const resizeObserver = new ResizeObserver(() => {chart.resize();
    });resizeObserver.observe(container); // 开始监听// 组件卸载时销毁(重要!)
    // Vue: onBeforeUnmount(() => resizeObserver.disconnect())
    // React: useEffect(() => () => resizeObserver.disconnect(), [])
  • 兼容性处理(旧版浏览器):

    npm install resize-observer-polyfill
     
    import ResizeObserver from 'resize-observer-polyfill';

2. 框架特定方案(如侧边栏回调)

  • 若使用 Element UI/ Ant Design 等组件库,在侧边栏展开/折叠的回调中触发:

    // Element UI 侧边栏折叠事件
    <el-menu @collapse="handleCollapse"> → 
    handleCollapse() {this.$nextTick(() => this.chart.resize());
    }

三、性能优化

1. 防抖处理(高频变化场景)

let resizeTimer;
const resizeObserver = new ResizeObserver(() => {clearTimeout(resizeTimer);resizeTimer = setTimeout(() => chart.resize(), 100);
});

2. 容器动画同步

.chart-container {transition: width 0.3s; /* 动画持续期间持续触发 ResizeObserver */
}

四、完整示例(Vue3 + TypeScript)

<template><div ref="chartContainer" class="chart"></div>
</template><script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue';
import * as echarts from 'echarts';
import ResizeObserver from 'resize-observer-polyfill';const chartContainer = ref<HTMLElement>();
let chart: echarts.ECharts;
let resizeObserver: ResizeObserver;onMounted(() => {chart = echarts.init(chartContainer.value!);chart.setOption({ /* 配置项 */ });// 监听容器变化resizeObserver = new ResizeObserver(() => chart.resize());resizeObserver.observe(chartContainer.value!);
});onBeforeUnmount(() => {resizeObserver?.disconnect();chart?.dispose();
});
</script>

五、常见问题排查

现象 解决方案
图表未响应侧边栏变化 确认监听的是图表容器而非父元素
出现空白间隙 检查容器 CSS 是否设置 width: 100%
内存泄漏 确保组件卸载时调用 disconnect()

通过 ResizeObserver + resize() 的组合,可精准响应任意原因导致的容器尺寸变化,无需依赖具体 UI 框架。

如果是 toc 产品,后端为 index.html 设置了 1 h 的 max age,请问从你重新构建代码发布,大概多久之后,所有用户都可以看到新界面?如果用户访问出现了白屏,是什么原因?

问题一:代码发布后用户看到新界面的时间

核心时间范围:最长 1 小时,但存在变量

  1. 理论最长时间
    由于 index.html 设置了 max-age=3600(1小时),未主动刷新页面的用户需等待缓存过期后才会获取新版本

    • 用户首次访问时间点不同:若用户恰好在发布前 5 分钟访问过,需等待 55 分钟才能更新。

  2. 实际可能更短

    • 强制刷新(Ctrl+F5):用户手动刷新会跳过缓存,立即获取新版本。

    • 文件名哈希策略:若 JS/CSS 文件使用哈希指纹(如 app.a1b2c3.js),新版本会触发浏览器重新下载资源,即使 index.html 仍被缓存,也可能部分更新。

    • CDN 缓存行为:若 CDN 配置的缓存时间短于 1 小时,用户可能提前获取新版本。

问题二:用户访问白屏的可能原因

核心原因排查清单

原因分类 具体场景 解决方案
缓存冲突 旧版 index.html 引用了已被删除或重命名的资源文件(如未哈希的 JS/CSS) 使用内容哈希文件名,确保新旧资源共存
资源加载失败 新版本资源未正确部署到服务器,导致 404 错误 检查构建产物是否完整上传,验证 CDN/服务器路径
代码执行错误 新版 JS 中存在语法错误或依赖兼容性问题(如浏览器不支持 ES6+ 语法) 启用 Babel 转译,添加错误监控(如 Sentry)捕获运行时错误
路由配置问题 单页应用(SPA)路由未正确配置,导致空白路由匹配 检查路由兜底设置(如 404 重定向到首页)
Service Worker 旧版 Service Worker 强制缓存了过时资源 更新 Service Worker 版本并触发立即激活(如 self.skipWaiting()

最佳实践建议

  1. 缓存策略优化

    • 对 index.html 设置较短缓存(如 max-age=300),或使用 no-cache 配合 ETag 验证。

    • 静态资源(JS/CSS/图片):设置长期缓存(如 max-age=31536000)并添加哈希指纹。

  2. 部署流程增强

    # 示例:使用 Webpack 生成带哈希的文件名
    output: {filename: '[name].[contenthash].js',chunkFilename: '[name].[contenthash].chunk.js'
    }
    • 先上传新资源,再更新 index.html,避免出现中间状态。

  3. 监控与回滚

    • 部署后实时监控错误率(如通过 APM 工具)。

    • 准备快速回滚方案(如保留前一次构建产物)。

  4. 用户提示机制

     
    // 检测版本更新并提示用户刷新
    if (navigator.serviceWorker) {navigator.serviceWorker.addEventListener('controllerchange', () => {window.location.reload();});
    }

示例:强制缓存失效方案

通过修改 index.html 的 URL 路径(如添加版本号)绕过缓存:

# Nginx 配置示例
location / {if ($request_uri ~* "index\.html$") {add_header Cache-Control "no-cache, must-revalidate";}
}

或使用查询参数(不推荐,部分 CDN 会忽略):

<script src="/app.js?v=20231001"></script>

toc 产品大量使用 cdn,请问 cdn 的定价大概多少?针对这样的定价策略,前端应该进行什么样的优化?前端应用中?上传贵还是下载贵?上传快还是下载快?

一、CDN 定价模型(以主流厂商为例)

CDN 的定价通常由 流量、请求次数、存储 和 增值功能 四部分构成,以下为典型价格范围(以中国大陆和全球主流 CDN 服务商为例):

计费项 价格范围 示例场景
流量费用 中国大陆: 0.1~0.3 元/GB
海外: 0.05~~~~~~~~~~~~~~~~~~~0.2 元/GB
用户下载 1GB JS/CSS/图片资源,约消耗 0.2 元(按国内均价)
HTTP 请求次数 - 0.01~0.1 元/万次 100 万次图片请求 ≈ 5~10 元
存储费用 - 0.1~0.3 元/GB/月 存储 100GB 静态资源 ≈ 10~30 元/月
增值服务 - DDoS 防护: 100~500 元/月
- 全站加速(动态请求): 0.3~~~~~~~~~~~~~~~~~~~~~~1 元/GB
动态 API 加速 100GB ≈ 30~100 元

主流厂商参考

  • 阿里云/腾讯云:流量阶梯计价(用量越大单价越低)

  • Cloudflare:免费套餐含基础防护,Pro 套餐 20 美元/月(不限流量)

  • AWS CloudFront:按区域定价(北美 0.085 美元/GB,亚洲 0.14 美元/GB)


二、前端优化策略(降低成本 + 提升性能)

针对 CDN 定价模型,前端需重点优化 流量消耗 和 请求次数

1. 减少流量消耗

方法 效果 实施示例
资源压缩 减少 50%~70% 体积 使用 Brotli(最高压缩率)替代 Gzip,Webpack 配置 compression-webpack-plugin
图片优化 WebP 比 JPEG 节省 30%+ <picture> 标签兼容性兜底:
<source srcset="img.webp" type="image/webp">
代码拆分(Code Splitting) 按需加载减少初始下载量 Vue/React 使用动态导入:() => import('./Component')
Tree Shaking 移除未使用代码 Webpack/Rollup 默认支持,确保 sideEffects: false

2. 降低请求次数

方法 效果 实施示例
HTTP/2 多路复用 单连接并行传输,减少队头阻塞 Nginx 配置 listen 443 http2
资源合并 减少小文件请求 合并图标为 SVG Sprite(如 icon-sprite.svg#home
合理缓存策略 减少重复请求 静态资源设置 Cache-Control: public, max-age=31536000, immutable
CDN 边缘计算 请求在边缘节点处理(如压缩、重定向) Cloudflare Workers 实现 A/B 测试分流

3. 监控与分析

工具 用途
Google Lighthouse 性能评分 + 优化建议
CDN 自带监控 分析流量热点、异常请求(如 404 资源)
Sentry 捕获前端错误,定位资源加载失败问题

三、上传 vs 下载:成本与速度对比

1. 成本对比

方向 定价逻辑 成本
上传(写入CDN) 通常免费或极低费用(厂商希望吸引内容注入) (接近0)
下载(用户访问) 主要收费项(占 CDN 厂商带宽成本的核心) (主要支出)

2. 速度对比

方向 速度表现
上传 依赖本地网络上行带宽(家用宽带通常 10~50Mbps),但可通过 分片上传 或 CDN 就近接入点 优化
下载 通过 CDN 全球加速节点,用户从最近节点获取资源,速度更快(通常 100Mbps+)

四、完整优化案例

场景:一个全球化的电商网站,图片资源占比 70%,JS/CSS 资源频繁更新。

优化步骤

图片处理

  • 使用 sharp 库批量转换为 WebP 格式

  • 响应式图片:srcset 按设备分辨率分发

<img src="product.jpg" srcset="product-400.webp 400w, product-800.webp 800w"sizes="(max-width: 600px) 400px, 800px">
  1. 代码优化

    • 启用 Brotli 压缩(Nginx 配置 brotli on;

    • 非核心代码动态加载:

      // 点击时加载支付模块
      button.addEventListener('click', () => {import('./payment.js').then(module => module.process());
      });
  2. 缓存策略

    • 静态资源:Cache-Control: public, max-age=31536000, immutable

    • HTML 文件:Cache-Control: no-cache(通过 ETag 验证更新)


五、成本估算(示例)

假设某应用月消耗:

  • 流量:100TB(下载)

  • 请求次数:10 亿次

  • 存储:1TB

费用计算(以阿里云为例)

  • 流量费:100,000 GB × 0.18 元/GB ≈ 18,000 元

  • 请求费:10 亿次 ÷ 10,000 × 0.06 元 ≈ 6,000 元

  • 存储费:1TB × 0.15 元/GB ≈ 150 元

  • 总成本 ≈ 24,150 元/月

优化后(预计节省 40%+)

  • WebP 图片减少 30% 流量 → 流量费降至 12,600 元

  • Brotli 压缩减少 20% 请求量 → 请求费降至 4,800 元

  • 总成本 ≈ 17,550 元/月


通过前端优化可直接降低 CDN 的核心成本项(流量和请求),同时提升用户体验,形成双赢局面。

 图片设置协商缓存后,浏览器会整体缓存,视频能设置协商缓存么?视频的http返回内容与图片有什么区别?如何降低视频展示的成本?

一、视频能否设置协商缓存?

可以,视频与图片的缓存机制原理相同,均可通过 HTTP 缓存头实现协商缓存。

配置示例(Nginx)

location /videos/ {# 设置强缓存(可选)add_header Cache-Control "public, max-age=3600";# 协商缓存:通过 Last-Modified/ETag 验证if_modified_since before;etag on;
}

协商缓存流程

  1. 首次请求:返回 200 OK + Last-Modified/ETag

  2. 再次请求:浏览器携带 If-Modified-Since 或 If-None-Match

  3. 资源未修改:服务器返回 304 Not Modified,浏览器使用本地缓存


二、视频与图片的 HTTP 响应差异

核心区别点

特征 图片(如 JPEG) 视频(如 MP4)
状态码 通常 200 OK 可能 206 Partial Content(范围请求)
Content-Type image/jpeg video/mp4
Accept-Ranges 通常无(小文件不分片) bytes(支持分段加载)
Content-Range bytes 0-999/2000(指示当前传输的字节范围)
缓存行为 完整缓存 可能分片缓存(取决于是否启用范围请求)

示例视频请求响应头

HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Accept-Ranges: bytes
Content-Range: bytes 0-1048575/5242880
Content-Length: 1048576
Cache-Control: public, max-age=3600
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT

三、降低视频展示成本的几种策略

1. 启用 HTTP 范围请求(Range Requests)

  • 原理:允许用户仅加载观看的部分视频片段,减少无效流量消耗。

  • 实现:确保服务器支持 Accept-Ranges: bytes(Nginx 默认开启)。

2. 转码为高效编码格式

  • 推荐格式:H.265(HEVC)比 H.264 节省 50% 带宽,AV1 更优但兼容性差。

  • 工具示例

    ffmpeg -i input.mp4 -c:v libx265 -crf 28 output-hevc.mp4

3. 自适应码率(ABR)

  • 技术方案:使用 HLS 或 DASH 协议,根据网络状况动态切换分辨率。

  • 实现步骤

    1. 将视频切片(如 10s/段)并生成多码率版本

    2. 通过 .m3u8(HLS)或 .mpd(DASH)描述文件管理播放

4. CDN 分层存储

  • 策略

    • 热数据:使用 SSD 边缘节点加速

    • 冷数据:存储到低价对象存储(如 AWS S3 Glacier)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

使用Dify快速搭建AI Agent智能助手应用

1 定义 智能助手(Agent Assistant),利用LLM的推理能力,自主对复杂的人类任务进行目标规划、任务拆解、工具调用、过程迭代,在无人类干预的情况下完成任务。 2 咋用智能助手? “探索”中找到Agent的应用模板,添加到工作区或在此基础自定义。在工作室也可从0编排一个Agent…

第二课 信用卡欺诈预测

目录数据预处理导包查看数据特征工程目标变量特征衍生特征选择信用卡正常消费和盗刷对比交易金额和交易次数信用卡消费时间分析交易金额和交易时间的关系特征分布(非常重要,帮助筛选特征) 数据预处理 导包 除了常规的导包,这里还有一行代码如下 pd.set_option(display.floa…

【自动化运维】AIOps的下一步走向哪里?

【摘要】本文从AIOps的演进谈起,提出了AIOps的挑战症结所在,重点分析AIOps是怎样的运维工作模式,其智能运维场景如何构建,以及大模型和AI Agent给场景带来的新思路。本文对AIOps的发展趋势有较深入的思考,值得同行学习借鉴。 【作者】彭华盛,广发证券数字化运维研发团队负…

动手学大模型应用开发,第4天:向量数据库的使用

第一章、知识库文档处理 本项目是一个个人知识库助手项目,旨在帮助用户根据个人知识库内容,回答用户问题。个人知识库应当能够支持各种类型的数据,支持用户便捷地导入导出、进行管理。在我们的项目中,我们以 Datawhale 的一些经典开源课程作为示例,设计了多种文件类型,介…

部署 M-lag 的设备只有单台可以ping通下联设备的原因分析

问题描述 如下图所示,两台 CE12808 设备部署 M-LAG, 在 VLANIF 接口上配置相同的 IP 地址和相同的虚拟 MAC 地址作为下联服务器的双活网关,服务器通过二层交换机双上联至部署了 M-LAG 的一组CE12808设备。 在此场景下, 从服务器可以 ping 通网关,但从两台 CE12808 设备向服…

现代CPU调优1简介

1 简介 性能为王:十年前如此,现在当然也是如此。根据domo.com-2017的数据,2017 年全球每天产生 2.5 万亿字节的数据。statista.com-2024预测,这一数字将在 2024 年达到每天 400 万亿字节。在我们这个日益以数据为中心的世界里,信息交换的增长需要更快的软件和更快的硬件。…

寒假第十二天

实验流程编写独立应用程序实现数据去重创建 Scala 项目,配置 sbt 构建工具。编写 Spark 独立应用程序,读取输入文件 A 和 B,创建两个 RDD。使用 union 操作合并两个 RDD,并通过 distinct 操作去重。将去重后的结果保存到新文件 C 中。使用 spark-submit 提交应用程序,验证…

IIC的时序解析

IIC(Inter-Integrated Circuit)即集成电路总线,是一种多主从的串行总线,属于半双工同步传输类型总线,仅使用两条线,一条SCL时钟线,一条双向数据线SDA。以下是对IIC通信波形图的详细解读: 信号状态空闲状态:SDA和SCL两条信号线同时处于高电平时,为总线的空闲状态。此时…

数据库安全实战:访问控制与行级权限管理

title: 数据库安全实战:访问控制与行级权限管理 date: 2025/2/16 updated: 2025/2/16 author: cmdragon excerpt: 在数据泄露事件频发的今天,数据库访问控制是保护企业核心资产的最后一道防线。数据库安全体系的三大核心组件——用户角色管理、权限授权机制和行列级安全控制…

一款直流电机的拆解

未拆卸前:将减速器部分(涡轮部分)拿下来可以注意到,这是两个电刷。 之后, 是电机的核心部分,以及蜗杆部分、外壳部分。 然后再把电机的外壳拿走,可以看到露出绕组和电机输出轴。这个外壳上有两个永磁体:底端是编码器,是两个霍尔原件(磁编码器),可以测速。

ConcurrentHashMap扩容过程

一、ConcurrentHashMap扩容过程 1、ConcurrentHashMap扩容时新建数组 1.1 每个线程负责的数据迁移区域的长度:stride 1.2 关于transferIndex的说明 2、ConcurrentHashMap扩容时获取迁移数据区域 2.1 总结 3、判断数据迁移是否结束 3.1 每个线程完成自己区域内的数据迁移的判断…