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

聊城做网站的公司平台怎样做百度网站推广

聊城做网站的公司平台,怎样做百度网站推广,十堰新闻,淮北矿业工程建设有限公司网站Promise 前端应用场景与实战题目 Promise 作为 JavaScript 异步编程的核心解决方案,在前端开发中有非常广泛的应用。以下是常见的应用场景及对应的实战题目: 1. 并行请求数据并处理结果 场景描述 同时需要从多个接口并行请求数据,待所有数据都…

在这里插入图片描述

Promise 前端应用场景与实战题目

Promise 作为 JavaScript 异步编程的核心解决方案,在前端开发中有非常广泛的应用。以下是常见的应用场景及对应的实战题目:

1. 并行请求数据并处理结果

场景描述

同时需要从多个接口并行请求数据,待所有数据都返回后进行汇总处理。

题目:实现并行请求并合并结果

// 模拟接口请求函数
function fetchData(url) {return new Promise((resolve) => {// 模拟网络延迟setTimeout(() => {const data = {'user': { id: 1, name: '张三' },'posts': [{ id: 1, title: '文章1' }, { id: 2, title: '文章2' }],'comments': [{ id: 1, content: '评论1' }]};resolve(data[url]);}, Math.random() * 1000);});
}// 并行请求多个接口并处理结果
async function loadAndCombineData() {try {// 并行发起请求const [user, posts, comments] = await Promise.all([fetchData('user'),fetchData('posts'),fetchData('comments')]);// 合并结果return {user,posts: posts.map(post => ({...post,// 为每篇文章添加评论(实际场景可能根据ID关联)comments: comments.filter(comment => comment.postId === post.id)}))};} catch (error) {console.error('请求失败:', error);// 返回默认数据或重新抛出错误return { user: null, posts: [] };}
}// 使用
loadAndCombineData().then(result => {console.log('合并后的数据:', result);
});

关键点解析

  • 使用 Promise.all() 实现并行请求,效率高于串行请求
  • 所有请求都成功才会进入 then,任何一个失败都会触发 catch
  • 适合需要多个接口数据才能完成的业务场景(如页面初始化加载)

2. 带重试机制的请求

场景描述

网络请求可能偶尔失败,需要实现带重试机制的请求函数,失败后自动重试指定次数。

题目:实现带重试机制的请求函数

/*** 带重试机制的请求函数* @param {Function} requestFn - 返回Promise的请求函数* @param {number} maxRetries - 最大重试次数* @param {number} delay - 重试延迟时间(ms)* @returns {Promise}*/
function requestWithRetry(requestFn, maxRetries = 3, delay = 1000) {return new Promise((resolve, reject) => {// 执行请求的递归函数function attempt(retriesLeft) {requestFn().then(resolve).catch(error => {// 如果还有重试次数,延迟后重试if (retriesLeft > 0) {console.log(`请求失败,将在${delay}ms后重试,剩余次数: ${retriesLeft}`);setTimeout(() => {attempt(retriesLeft - 1);}, delay);} else {// 重试次数用尽,返回失败reject(new Error(`超过最大重试次数(${maxRetries}),请求失败: ${error.message}`));}});}// 开始第一次尝试attempt(maxRetries);});
}// 使用示例
// 模拟一个有20%概率成功的请求
function unstableRequest() {return new Promise((resolve, reject) => {setTimeout(() => {if (Math.random() < 0.2) {resolve('请求成功的数据');} else {reject(new Error('网络错误'));}}, 500);});
}// 使用带重试的请求
requestWithRetry(unstableRequest, 3, 1000).then(data => console.log('最终结果:', data)).catch(error => console.error('最终失败:', error.message));

关键点解析

  • 通过递归实现重试逻辑,每次失败后检查剩余重试次数
  • 加入延迟避免频繁重试给服务器造成压力
  • 适用于网络不稳定环境下的关键请求

3. 限制并发请求数量

场景描述

当需要发送大量请求时(如下载多个文件),无限制的并发会导致性能问题或被服务器限制,需要控制同时发起的请求数量。

题目:实现限制并发数的请求调度器

/*** 并发请求调度器* @param {Array<Function>} tasks - 返回Promise的任务数组* @param {number} limit - 最大并发数* @returns {Promise}*/
function scheduleTasks(tasks, limit) {return new Promise((resolve) => {if (tasks.length === 0) {resolve([]);return;}const results = []; // 存储所有结果let index = 0; // 当前要执行的任务索引let completed = 0; // 已完成的任务数量// 执行一个任务function runTask() {// 如果所有任务都已开始执行,直接返回if (index >= tasks.length) return;const taskIndex = index++;const task = tasks[taskIndex];task().then(result => {results[taskIndex] = result; // 按原顺序存储结果completed++;// 继续执行下一个任务runTask();// 所有任务都完成时,返回结果if (completed === tasks.length) {resolve(results);}}).catch(error => {results[taskIndex] = { error: error.message };completed++;runTask();if (completed === tasks.length) {resolve(results);}});}// 启动初始的limit个任务for (let i = 0; i < limit && i < tasks.length; i++) {runTask();}});
}// 使用示例
// 创建模拟任务
function createTask(id) {return () => new Promise((resolve) => {console.log(`开始执行任务 ${id}`);setTimeout(() => {console.log(`完成任务 ${id}`);resolve(`任务${id}的结果`);}, Math.random() * 1000);});
}// 创建10个任务
const tasks = Array.from({ length: 10 }, (_, i) => createTask(i + 1));// 限制最大并发数为3
scheduleTasks(tasks, 3).then(results => {console.log('所有任务完成,结果:', results);
});

关键点解析

  • 维护任务索引和完成计数,精确控制并发数量
  • 保证结果数组顺序与原任务顺序一致
  • 适用于批量操作场景(如批量上传、批量下载)

4. 图片懒加载实现

场景描述

在长列表中,为了提高页面加载速度,通常会实现图片懒加载:当图片滚动到视口附近时才加载图片。

题目:使用Promise实现图片懒加载

/*** 预加载图片* @param {string} url - 图片URL* @returns {Promise}*/
function loadImage(url) {return new Promise((resolve, reject) => {const img = new Image();img.src = url;img.onload = () => {resolve(img);};img.onerror = () => {reject(new Error(`无法加载图片: ${url}`));};});
}/*** 检查元素是否在视口内* @param {HTMLElement} el - 元素* @param {number} offset - 偏移量* @returns {boolean}*/
function isInViewport(el, offset = 200) {const rect = el.getBoundingClientRect();return (rect.top <= (window.innerHeight || document.documentElement.clientHeight) + offset &&rect.bottom >= -offset &&rect.left <= (window.innerWidth || document.documentElement.clientWidth) + offset &&rect.right >= -offset);
}/*** 图片懒加载初始化*/
function initLazyLoad() {// 获取所有懒加载图片const lazyImages = document.querySelectorAll('img.lazy');const imagePromises = new Map(); // 存储正在加载的图片Promise// 加载可见的图片function loadVisibleImages() {lazyImages.forEach(img => {// 如果已经加载或正在加载,跳过if (img.dataset.loaded === 'true' || imagePromises.has(img)) return;// 检查是否在视口内if (isInViewport(img)) {const src = img.dataset.src;if (src) {// 开始加载图片const promise = loadImage(src).then(loadedImg => {// 加载成功,更新图片img.src = src;img.dataset.loaded = 'true';img.classList.add('loaded');imagePromises.delete(img);}).catch(error => {console.error(error);img.dataset.loaded = 'error';imagePromises.delete(img);});imagePromises.set(img, promise);}}});}// 初始加载一次loadVisibleImages();// 滚动和resize时检查const handleScroll = () => {// 使用requestAnimationFrame优化性能requestAnimationFrame(loadVisibleImages);};window.addEventListener('scroll', handleScroll);window.addEventListener('resize', handleScroll);// 返回清理函数return () => {window.removeEventListener('scroll', handleScroll);window.removeEventListener('resize', handleScroll);};
}// 使用示例
// 在DOM加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {const cleanup = initLazyLoad();// 页面卸载时清理window.addEventListener('unload', cleanup);
});

关键点解析

  • 使用 Promise 封装图片加载过程,便于处理成功/失败状态
  • 结合滚动事件检测图片是否进入视口
  • 使用 Map 跟踪正在加载的图片,避免重复加载
  • 适用于图片较多的页面(如电商列表、相册等)

5. 实现请求缓存

场景描述

对于重复的请求(如用户信息、配置数据),可以缓存结果避免重复请求,提高性能并减少服务器压力。

题目:实现带缓存的请求函数

/*** 创建带缓存的请求函数* @param {Function} requestFn - 原始请求函数,返回Promise* @param {number} ttl - 缓存过期时间(ms),默认300000ms(5分钟)* @returns {Function} 带缓存的请求函数*/
function createCachedRequest(requestFn, ttl = 300000) {// 缓存存储:key -> { data, timestamp }const cache = new Map();// 正在进行的请求:key -> Promise,避免重复请求const pendingRequests = new Map();return async function cachedRequest(...args) {// 将参数序列化为缓存键const key = JSON.stringify(args);// 检查缓存是否存在且未过期const cached = cache.get(key);if (cached && Date.now() - cached.timestamp < ttl) {console.log('使用缓存数据:', key);return cached.data;}// 检查是否有相同的请求正在进行if (pendingRequests.has(key)) {console.log('等待正在进行的请求:', key);return pendingRequests.get(key);}// 执行新请求console.log('发起新请求:', key);const promise = requestFn(...args).then(data => {// 请求成功,更新缓存cache.set(key, {data,timestamp: Date.now()});return data;}).finally(() => {// 无论成功失败,都移除pending状态pendingRequests.delete(key);});// 记录正在进行的请求pendingRequests.set(key, promise);return promise;};
}// 使用示例
// 模拟API请求
function fetchUserInfo(userId) {return new Promise((resolve) => {console.log(`实际请求用户信息: ${userId}`);setTimeout(() => {resolve({id: userId,name: `用户${userId}`,age: 20 + userId % 10});}, 1000);});
}// 创建带缓存的请求函数,缓存10秒
const cachedFetchUserInfo = createCachedRequest(fetchUserInfo, 10000);// 测试缓存效果
async function test() {// 第一次请求 - 新请求console.log(await cachedFetchUserInfo(1));// 第二次请求 - 使用缓存console.log(await cachedFetchUserInfo(1));// 不同参数 - 新请求console.log(await cachedFetchUserInfo(2));// 3秒后再次请求 - 仍使用缓存setTimeout(async () => {console.log(await cachedFetchUserInfo(1));}, 3000);// 11秒后再次请求 - 缓存过期,新请求setTimeout(async () => {console.log(await cachedFetchUserInfo(1));}, 11000);
}test();

关键点解析

  • 使用 Map 存储缓存数据和过期时间
  • 处理并发请求:相同请求同时发起时,只实际请求一次
  • 支持设置缓存过期时间,避免数据长期不一致
  • 适用于不频繁变化的数据请求(如用户信息、字典数据)

这些场景覆盖了 Promise 在前端开发中的主要应用,包括数据请求、性能优化、资源加载等方面。掌握这些实战技巧不仅能应对面试,更能在实际开发中写出高效、健壮的代码。


前端常见应用场景题目详解

在前端开发中,许多场景具有高度的通用性和实用性,也是面试中的高频考点。以下梳理了最常见的应用场景及具体实现方案:

一、高频事件处理(防抖与节流)

场景描述

在处理滚动、窗口 resize、输入框实时搜索等高频触发的事件时,直接执行回调函数会导致性能问题,需要通过防抖或节流优化。

1. 防抖(Debounce)

核心思想:事件触发后延迟n秒执行,如果n秒内再次触发则重新计时,适用于"输入完成后再处理"的场景(如搜索联想)。

/*** 防抖函数* @param {Function} fn - 需要防抖的函数* @param {number} delay - 延迟时间(ms)* @param {boolean} immediate - 是否立即执行第一次触发* @returns {Function} 防抖处理后的函数*/
function debounce(fn, delay, immediate = false) {let timer = null;let isExecuted = false; // 标记是否已立即执行return function(...args) {const context = this;// 清除现有定时器if (timer) clearTimeout(timer);// 立即执行模式(仅第一次触发时执行)if (immediate && !isExecuted) {fn.apply(context, args);isExecuted = true;} else {// 延迟执行模式timer = setTimeout(() => {fn.apply(context, args);// 重置立即执行标记(下一次序列可重新立即执行)if (immediate) isExecuted = false;timer = null;}, delay);}};
}// 使用示例:搜索框输入联想
const searchInput = document.getElementById('search-input');
const handleSearch = (e) => {console.log('搜索:', e.target.value);// 实际场景:调用搜索接口
};// 输入停止500ms后执行搜索
searchInput.addEventListener('input', debounce(handleSearch, 500));
2. 节流(Throttle)

核心思想:每隔n秒最多执行一次函数,适用于"持续触发但需要定期处理"的场景(如滚动加载、动画帧)。

/*** 节流函数* @param {Function} fn - 需要节流的函数* @param {number} interval - 间隔时间(ms)* @returns {Function} 节流处理后的函数*/
function throttle(fn, interval) {let lastTime = 0; // 上次执行时间let timer = null;return function(...args) {const context = this;const now = Date.now();const remaining = interval - (now - lastTime); // 剩余时间// 清除延迟执行的定时器(避免最后一次触发延迟执行)if (timer) clearTimeout(timer);// 如果间隔时间已到,立即执行if (remaining <= 0) {fn.apply(context, args);lastTime = now;} else {// 否则设置定时器,确保最后一次触发能执行timer = setTimeout(() => {fn.apply(context, args);lastTime = Date.now();timer = null;}, remaining);}};
}// 使用示例:滚动加载
window.addEventListener('scroll', throttle(() => {console.log('滚动位置:', window.scrollY);// 实际场景:判断是否到达底部,加载更多内容
}, 300));

关键点解析

  • 防抖 vs 节流:防抖是"等待最后一次触发后执行",节流是"固定频率执行"
  • 应用场景区分:输入框搜索用防抖,滚动/resize用节流
  • 优化点:通过apply保留函数上下文,处理立即执行需求,避免内存泄漏

二、图片懒加载(Lazy Load)

场景描述

在长列表或图片密集的页面中,优先加载可视区域内的图片,滚动到附近时再加载其他图片,减少初始加载时间和带宽消耗。

/*** 图片懒加载实现* 1. 页面初始化时加载可视区域图片* 2. 滚动时加载进入视口的图片* 3. 使用IntersectionObserver优化性能*/
class ImageLazyLoader {constructor(selector = 'img.lazy') {this.images = document.querySelectorAll(selector);this.observer = null;this.init();}// 初始化观察者init() {// 支持IntersectionObserver的浏览器(现代浏览器)if ('IntersectionObserver' in window) {this.observer = new IntersectionObserver((entries) => {entries.forEach(entry => {if (entry.isIntersecting) {this.loadImage(entry.target);this.observer.unobserve(entry.target); // 加载后停止观察}});}, { rootMargin: '200px 0px' }); // 提前200px开始加载// 观察所有懒加载图片this.images.forEach(img => this.observer.observe(img));} else {// 降级方案:使用滚动监听this.handleScroll = this.throttle(() => this.checkImages(), 100);window.addEventListener('scroll', this.handleScroll);this.checkImages(); // 初始检查}}// 加载图片loadImage(img) {if (img.dataset.src && img.dataset.src !== img.src) {const newImg = new Image();newImg.src = img.dataset.src;// 图片加载成功后更新srcnewImg.onload = () => {img.src = img.dataset.src;img.classList.add('loaded'); // 添加加载完成的样式};// 处理加载失败newImg.onerror = () => {img.src = 'default-error-image.png'; // 占位图};}}// 检查可视区域内的图片(降级方案)checkImages() {this.images.forEach(img => {if (this.isInViewport(img) && !img.classList.contains('loaded')) {this.loadImage(img);}});}// 判断元素是否在视口内(降级方案)isInViewport(el) {const rect = el.getBoundingClientRect();return (rect.top <= window.innerHeight &&rect.bottom >= 0 &&rect.left <= window.innerWidth &&rect.right >= 0);}// 节流函数(用于降级方案)throttle(fn, delay) {let lastTime = 0;return function(...args) {const now = Date.now();if (now - lastTime >= delay) {fn.apply(this, args);lastTime = now;}};}// 销毁资源destroy() {if (this.observer) {this.images.forEach(img => this.observer.unobserve(img));} else {window.removeEventListener('scroll', this.handleScroll);}}
}// 使用示例
// HTML结构:<img class="lazy" data-src="real-image.jpg" src="placeholder.jpg" alt="描述">
document.addEventListener('DOMContentLoaded', () => {const lazyLoader = new ImageLazyLoader();// 页面卸载时清理window.addEventListener('unload', () => lazyLoader.destroy());
});

关键点解析

  • 核心原理:通过data-src存储真实图片地址,进入视口后赋值给src
  • 性能优化:
    • 现代浏览器使用IntersectionObserver(性能优于滚动监听)
    • 提前加载(rootMargin)提升用户体验
    • 加载失败处理(显示占位图)
  • 降级方案:兼容不支持IntersectionObserver的浏览器(如IE)

三、虚拟列表(Virtual List)

场景描述

当列表数据量极大(如10万+条)时,直接渲染所有DOM节点会导致页面卡顿,虚拟列表只渲染可视区域内的元素,大幅提升性能。

/*** 虚拟列表组件* 只渲染可视区域内的列表项,适用于大数据列表*/
class VirtualList {constructor(container, options) {this.container = container; // 容器DOMthis.data = options.data || []; // 完整数据this.itemHeight = options.itemHeight || 50; // 每项固定高度this.buffer = options.buffer || 5; // 可视区域外的缓冲项数量// 容器高度this.containerHeight = container.clientHeight;// 可视区域可显示的项数this.visibleCount = Math.ceil(this.containerHeight / this.itemHeight);// 总高度(用于滚动条)this.totalHeight = this.data.length * this.itemHeight;// 初始化DOM结构this.initDOM();// 绑定事件this.bindEvents();// 初始渲染this.render();}// 初始化DOM结构initDOM() {// 外层容器(固定高度,overflow: auto)this.container.style.overflow = 'auto';this.container.style.position = 'relative';// 滚动内容容器(用于撑开高度,显示滚动条)this.scrollContent = document.createElement('div');this.scrollContent.style.height = `${this.totalHeight}px`;this.scrollContent.style.position = 'relative';// 可视区域容器(绝对定位,只显示可视区域内容)this.visibleContainer = document.createElement('div');this.visibleContainer.style.position = 'absolute';this.visibleContainer.style.top = '0';this.visibleContainer.style.left = '0';this.visibleContainer.style.width = '100%';this.scrollContent.appendChild(this.visibleContainer);this.container.appendChild(this.scrollContent);}// 绑定滚动事件bindEvents() {this.container.addEventListener('scroll', () => {this.render(); // 滚动时重新渲染可视区域});}// 计算需要渲染的项getVisibleRange() {// 滚动距离const scrollTop = this.container.scrollTop;// 起始索引(减去缓冲项)const startIndex = Math.max(0, Math.floor(scrollTop / this.itemHeight) - this.buffer);// 结束索引(加上缓冲项和可视项数)const endIndex = Math.min(this.data.length - 1,startIndex + this.visibleCount + this.buffer * 2);return { startIndex, endIndex };}// 渲染可视区域内容render() {const { startIndex, endIndex } = this.getVisibleRange();// 截取需要渲染的数据const visibleData = this.data.slice(startIndex, endIndex + 1);// 计算可视容器的偏移量(让内容对齐滚动位置)const offsetY = startIndex * this.itemHeight;this.visibleContainer.style.transform = `translateY(${offsetY}px)`;// 渲染列表项this.visibleContainer.innerHTML = visibleData.map((item, index) => {const actualIndex = startIndex + index;return `<div class="virtual-item" style="height: ${this.itemHeight}px; line-height: ${this.itemHeight}px; border-bottom: 1px solid #eee;">第${actualIndex + 1}项: ${item.content}</div>`;}).join('');}// 更新数据updateData(newData) {this.data = newData;this.totalHeight = this.data.length * this.itemHeight;this.scrollContent.style.height = `${this.totalHeight}px`;this.render();}
}// 使用示例
// HTML: <div id="virtual-list-container" style="height: 500px; width: 300px;"></div>
document.addEventListener('DOMContentLoaded', () => {// 生成10万条测试数据const bigData = Array.from({ length: 100000 }, (_, i) => ({content: `这是第${i + 1}条数据`}));const container = document.getElementById('virtual-list-container');const virtualList = new VirtualList(container, {data: bigData,itemHeight: 50, // 每项高度50pxbuffer: 5 // 上下各缓冲5项});// 如需更新数据// virtualList.updateData(newData);
});

关键点解析

  • 核心原理:通过计算滚动位置,只渲染"可视区域+缓冲区域"的元素
  • 关键计算:
    • 起始索引 = 滚动距离 / 项高 - 缓冲项
    • 结束索引 = 起始索引 + 可视项数 + 缓冲项*2
    • 偏移量 = 起始索引 * 项高(让内容对齐滚动位置)
  • 适用场景:大数据表格、长列表(如订单列表、日志列表)

四、表单验证

场景描述

用户输入表单时,需要实时验证输入合法性(如手机号格式、密码强度),并给出友好提示,防止无效提交。

/*** 表单验证工具* 支持同步验证、异步验证、实时验证*/
class FormValidator {constructor(form, rules) {this.form = form; // 表单DOMthis.rules = rules; // 验证规则this.errors = {}; // 错误信息this.init();}// 初始化init() {// 绑定输入事件(实时验证)this.form.querySelectorAll('input, select, textarea').forEach(field => {field.addEventListener('input', () => this.validateField(field.name));field.addEventListener('blur', () => this.validateField(field.name));});// 绑定提交事件this.form.addEventListener('submit', (e) => {e.preventDefault();if (this.validateAll()) {console.log('表单验证通过,提交数据:', this.getFormData());// 实际场景:调用接口提交}});}// 获取表单数据getFormData() {const data = {};new FormData(this.form).forEach((value, key) => {data[key] = value;});return data;}// 验证单个字段async validateField(fieldName) {const field = this.form.querySelector(`[name="${fieldName}"]`);if (!field || !this.rules[fieldName]) return true;const value = field.value;const fieldRules = this.rules[fieldName];let errorMessage = '';// 遍历该字段的所有规则for (const rule of fieldRules) {// 同步验证if (typeof rule.validator === 'function') {const result = rule.validator(value, this.getFormData());if (result !== true) {errorMessage = result || rule.message;break;}}// 异步验证(如验证用户名是否已存在)else if (typeof rule.asyncValidator === 'function') {try {await rule.asyncValidator(value, this.getFormData());} catch (err) {errorMessage = err.message || rule.message;break;}}}// 更新错误信息this.errors[fieldName] = errorMessage;// 更新UI显示this.updateFieldUI(field, errorMessage);return !errorMessage;}// 验证所有字段async validateAll() {const fieldNames = Object.keys(this.rules);let isValid = true;// 先验证所有同步规则,再处理异步规则for (const fieldName of fieldNames) {const result = await this.validateField(fieldName);if (!result) isValid = false;}return isValid;}// 更新字段UI(显示错误信息)updateFieldUI(field, errorMessage) {// 查找或创建错误提示元素let errorEl = field.nextElementSibling;if (!errorEl || !errorEl.classList.contains('error-message')) {errorEl = document.createElement('div');errorEl.className = 'error-message text-red-500 text-sm mt-1';field.parentNode.insertBefore(errorEl, field.nextSibling);}// 更新错误信息和样式errorEl.textContent = errorMessage;field.classList.toggle('border-red-500', !!errorMessage);field.classList.toggle('border-green-500', !errorMessage && field.value);}
}// 使用示例
document.addEventListener('DOMContentLoaded', () => {const form = document.getElementById('user-form');// 定义验证规则const rules = {username: [{validator: (value) => value.trim() !== '' || '用户名不能为空',},{validator: (value) => value.length >= 3 || '用户名至少3个字符',},{// 异步验证:检查用户名是否已存在asyncValidator: async (value) => {// 模拟API请求const isExist = await new Promise(resolve => {setTimeout(() => resolve(['admin', 'root'].includes(value)), 500);});if (isExist) throw new Error('用户名已被占用');},message: '用户名已被占用'}],phone: [{validator: (value) => /^1[3-9]\d{9}$/.test(value) || '请输入正确的手机号',}],password: [{validator: (value) => value.length >= 6 || '密码至少6个字符',},{validator: (value) => /[A-Z]/.test(value) || '密码需包含大写字母',}],confirmPassword: [{validator: (value, data) => value === data.password || '两次密码不一致',}]};// 初始化验证器new FormValidator(form, rules);
});

关键点解析

  • 核心功能:支持同步验证(如格式检查)和异步验证(如用户名唯一性)
  • 实时反馈:输入和失焦时触发验证,及时提示错误
  • 可扩展性:通过规则配置支持不同字段的个性化验证需求
  • 常见验证场景:必填项、格式验证(手机号/邮箱)、密码强度、两次密码一致

五、权限控制

场景描述

根据用户角色(如管理员/普通用户)控制页面元素的显示/隐藏、路由访问权限,确保用户只能操作其权限范围内的功能。

/*** 权限控制工具* 支持路由权限、按钮权限控制*/
class Permission {constructor() {// 初始化权限(实际场景从登录接口获取)this.roles = []; // 用户角色this.permissions = []; // 用户权限列表}// 初始化权限数据init(roles, permissions) {this.roles = roles;this.permissions = permissions;}// 检查是否有指定角色hasRole(role) {return this.roles.includes(role);}// 检查是否有指定权限hasPermission(permission) {// 超级管理员拥有所有权限if (this.roles.includes('admin')) return true;return this.permissions.includes(permission);}// 路由权限守卫(模拟Vue Router导航守卫)routerGuard(to, from, next) {// 公开路由直接放行if (to.meta.public) {return next();}// 检查路由所需权限const requiredPermission = to.meta.permission;if (requiredPermission) {if (this.hasPermission(requiredPermission)) {next(); // 有权限,放行} else {next('/403'); // 无权限,跳转到403页面}} else {// 无权限要求的路由(需登录)if (this.roles.length > 0) {next(); // 已登录,放行} else {next('/login'); // 未登录,跳转到登录页}}}// 渲染带权限的按钮renderPermissionButton(containerId, buttons) {const container = document.getElementById(containerId);if (!container) return;// 只渲染有权限的按钮const html = buttons.filter(btn => this.hasPermission(btn.permission)).map(btn => `<button class="permission-btn ${btn.className}" onclick="${btn.onClick}">${btn.text}</button>`).join('');container.innerHTML = html;}// 指令式权限控制(类似Vue指令v-permission)registerPermissionDirective() {// 查找所有带data-permission属性的元素document.querySelectorAll('[data-permission]').forEach(el => {const requiredPermission = el.getAttribute('data-permission');// 无权限则隐藏元素if (!this.hasPermission(requiredPermission)) {el.style.display = 'none';}});}
}// 使用示例
// 1. 初始化权限(登录后)
const permission = new Permission();
// 假设登录后获取到的用户权限
permission.init(['editor'], // 角色['article:read', 'article:create', 'article:edit'] // 权限
);// 2. 路由权限控制(模拟)
const toRoute = {path: '/article/create',meta: {permission: 'article:create', // 该路由需要的权限public: false}
};
permission.routerGuard(toRoute, null, (path) => {console.log('路由跳转:', path); // 有权限,跳转到目标路由
});// 3. 渲染带权限的按钮
permission.renderPermissionButton('button-container', [{text: '查看文章',permission: 'article:read',className: 'btn-primary',onClick: 'handleView()'},{text: '创建文章',permission: 'article:create',className: 'btn-success',onClick: 'handleCreate()'},{text: '删除文章',permission: 'article:delete', // 当前用户无此权限,不会渲染className: 'btn-danger',onClick: 'handleDelete()'}
]);// 4. 指令式权限控制
// HTML: <div data-permission="article:edit">编辑文章区域</div>
permission.registerPermissionDirective();

关键点解析

  • 权限粒度:角色级(如admin)和权限项级(如article:delete)
  • 控制层面:
    • 路由层面:通过导航守卫限制访问
    • 视图层面:隐藏无权限的按钮/区域
  • 实现方式:
    • 指令式:通过自定义属性标记需要权限控制的元素
    • 函数式:主动检查权限后渲染内容
  • 注意事项:前端权限只是辅助控制,真正的权限校验必须在后端实现

总结

以上场景覆盖了前端开发中性能优化(防抖节流、懒加载、虚拟列表)、用户交互(表单验证)、系统安全(权限控制)等核心领域。每个场景的实现都需要考虑:

  1. 性能:避免不必要的DOM操作和计算
  2. 兼容性:考虑不同浏览器的支持情况
  3. 可扩展性:设计通用方案,便于复用和修改
  4. 用户体验:如懒加载的过渡效果、表单验证的实时反馈

掌握这些场景的实现原理和最佳实践,不仅能应对面试挑战,更能在实际开发中写出高效、健壮的代码。

http://www.dtcms.com/a/451887.html

相关文章:

  • 网站开发费的税率是多少广州白云手机网站建设
  • 网站开发检测用户微信号wordpress首页幻灯片设置
  • 合肥php网站开发钦州网站建设
  • 企业网站设计推广方案广告公司简介模板200字
  • 网站集约化建设进度汇报哪些网站做任务可以赚钱的
  • 自建网站 好处哪个网站做美食视频软件
  • 网站建设分析书引言电子商务说白了就是干什么的
  • 国内的c2c网站有哪些android下载软件app
  • 房屋租赁网站建设管理设计网站评分标准
  • 江苏园博园建设开发有限公司网站免费网站代理
  • 无限站点建站系统小程序二次开发多少钱
  • 网站怎么做参考文献在线修图编辑器
  • 和平区网站制作程序员网站建设
  • 阜阳网站是企业网站建设对网络营销的影响主要表现在( )
  • 推广普通话宣传标语seo教程百度云
  • 温州高端网站建设公司网站名称创意大全
  • 如何做网站截流保健品网站建设背景
  • 网站seo优化皆宣徐州百都网络不错网站开发属于什么大学专业
  • 成都手机模板建站重庆建设工程信息网查询系统
  • 农产品销售网站建设方案外贸营销单页网站
  • 营销网站四大要素wordpress+技术类模板下载
  • 大型网站如何优化免费自建 响应式 网站
  • 霞浦建站公司十二师建设局网站
  • 代做网站排名公司建站系统
  • 建筑投标网站免费制作二维码网站
  • 网站后台管理 ftpseo公司哪家好
  • 网站建设项目如何敏捷太原住房与城乡建设厅网站
  • 梁山专做网站的公司net大规模网站开发视频
  • 网站做镜像的有什么用创建网站的免费软件国内
  • 网站怎么建设高端公司代码演示插件wordpress