八股文篇
一、css
1、移动端如何实现自适应
- 媒体查询:使用CSS3的媒体查询功能,根据不同的屏幕尺寸和方向应用不同的样式规则。这种方法可以根据设备屏幕尺寸的不同,灵活调整页面的布局和样式,以适应不同的移动设备
- 弹性盒子布局:利用CSS3弹性盒子布局模型,通过设置弹性容器和弹性项目的属性,实现灵活的布局。弹性盒子布局可以根据容器的尺寸和内容的大小,自动调整项目的布局和排列
- rpx单位配合动态的font-size调整:使用rpx(根元素字体大小的倍数)作为单位来设置元素的尺寸,通过动态调整根元素的字体大小,可以控制整个页面的缩放比例,从而实现不同设备的适配。
- Viewport单位:使用viewport单位(如vw、vh、vmin、vmax)来设置元素的尺寸,这些单位是相对于视口(浏览器窗口)的尺寸来计算的,可以根据视口的大小进行自适应布局。Viewport单位提供了一种直观且响应式的方式来设置元素尺寸
2、标准盒模型和怪异盒模型
- 标准盒模型
默认情况下,浏览器使用标准盒模型。如果你希望明确指定使用标准盒模型,可以设置box-sizing: content-box
标准盒模型是 CSS 的默认盒模型,遵循 W3C 的规范。在这种模型中,元素的总宽度和总高度由以下部分组成:
总宽度=内容宽度+内边距宽度+边框宽度+外边距宽度,
总高度=内容高度+内边距高度+边框高度+外边距高度
- 怪异盒模型
如果你想使用怪异盒模型,可以通过设置
box-sizing
属性为border-box
异盒模型是早期浏览器(如 IE6)中使用的盒模型。元素的宽度和高度计算方式包括内容(content)、内边距(padding)和边框(border),但不包括外边距(margin)
总宽度=内容宽度+内边距宽度+边框宽度
总高度=内容高度+内边距高度+边框高度
3、页面实现居中
利用flex弹性布局:
/* html 实现son居中*/
<div class="box">
<div class="son">111</div>
</div>
/* style */
.box {
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center
}
利用position定位(需要宽高):
/* html 实现son居中*/
<div class="box">
<div class="son">111</div>
</div>
/* style */
.box {
position: relative;
.son {
width: 100px;
height: 100px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
}
/* html 实现son居中*/
<div class="box">
<div class="son">111</div>
</div>
/* style */
.box {
position: relative;
width: 500px;
height: 500px;
.son {
width: 100px;
height: 100px;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
}
}
二、js
1、原型和原型链
- 原型:js给每个函数分配的公共空间,减少内存占用
- 原型链:多个原型的集合,当调用对象的属性或方法时,先自身找,找不到去原型链上找,一直找到Object构造函数得原型链
2、闭包是什么,在哪使用过
一个函数包含着另一个函数,这个函数能访问另一个函数里面的变量
3、谈谈深拷贝和浅拷贝
- 浅拷贝:变量赋值,新值和旧值都指向同一个地址,改变新值旧值也会改变
- 深拷贝:变量赋值,开辟新的地址,新数据赋值不会影响旧数据
- 实现浅拷贝的方法:
const originalObj = {name: "gao", age: 20}
Object.assign({}, originalObj);
Array.concat() 方法:使用 Array.concat() 方法也可以在数组中创建一个浅拷贝
Array.slice() 方法:对于数组,可以使用 Array.slice() 方法来创建一个浅拷贝的副本。
- 实现深拷贝的方法:
JSON.parse和JSON.stringify实现
JSON.parse(JSON.stringify())
递归实现
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let result;
if (Array.isArray(obj)) {
result = [];
for (let i = 0; i < obj.length; i++) {
result[i] = deepCopy(obj[i]);
}
} else {
result = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepCopy(obj[key]);
}
}
}
return result;
}
4、你对promise的理解
解决回调地狱问题
5、什么是节流防抖,一般项目上哪里使用过
- 防抖:一段时间可以执行多次,但是会清除前面的保留最后一次执行(相当于王者里的回城)
示例:滚动条滚动加载,搜索框搜索输入,用户名、手机号、邮箱输入验证
/**
* 函数防抖:一段实现执行多次,只执行最后一次
* @param {void} fn 回调函数
* @param {number} t 节流时间
* @returns {void}
* @constructor
*/
function debounce(fn, t?) {
const delay = t || 500;
let timer: any;
let that = this;
return function () {
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
timer = null;
fn.apply(that, args);
}, delay);
};
}
- 节流:一段时间只能执行一次,相当于王者技能
示例:提交表单按钮
let timer;
let flag: boolean | undefined;
/**
* 函数节流: 一段时间执行一次
* @param {void} fn 回调函数
* @param {number} wait 节流等待时间
* @param {boolean} immediate 是否立马执行
* @returns {void}
* @constructor
*/
const throttle = (
fn,
wait = 500,
immediate = true,
): void => {
if (immediate) {
if (!flag) {
flag = true;
// 如果是立即执行,则在wait毫秒内开始时执行
typeof fn === "function" && fn();
timer = setTimeout(() => {
flag = false;
}, wait);
}
} else if (!flag) {
flag = true;
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false;
typeof fn === "function" && fn();
}, wait);
}
};
6、实现数组去重办法
- 简单数组去重
function() {
const arr = [1,2,3,2,3];
let newArr = [];
arr.forEach(item => {
if(!newArr.inclouds(item)) {
newArr.push(item)
}
})
}
- 对象数组去重
function uniqueArray(arr, keyOrComparator) {
if (!Array.isArray(arr)) {
throw new Error('The first argument must be an array.');
}
if (typeof keyOrComparator === 'function') {
// 使用自定义比较函数去重
return arr.filter((item, index, self) => {
return self.findIndex(t => keyOrComparator(item, t)) === index;
});
} else if (typeof keyOrComparator === 'string') {
// 使用唯一键去重
const seen = new Set();
return arr.filter(item => {
const key = item[keyOrComparator];
if (seen.has(key)) {
return false;
} else {
seen.add(key);
return true;
}
});
} else {
// 默认行为:使用 JSON 字符串化去重
const seen = new Set();
return arr.filter(item => {
const key = JSON.stringify(item);
if (seen.has(key)) {
return false;
} else {
seen.add(key);
return true;
}
});
}
}
项目篇
一、项目难点
1、切片上传文件
参考方案:
先计算文件md5值,通过MD5值判断文件是否上传,避免重复上传,然后把文件切片处理,并发送传给服务器,通知服务器端进行切片的合并
2、websocket双向通信和SSE单选通信
参考方案:
SSE技术和WebSocket技术实现即时通讯-CSDN博客
3、移动端端适配
- h5、App、ios、小程序适配不同端的适配
- 不同大小手机css的适配大小
4、前端代码容易受到XSS(跨站脚本攻击)、CSRF(跨站请求伪造)等安全威胁。
-
XSS解决方案:
在用户输入时,我会使用正则表达式进行输入验证,确保输入内容符合预期格式。同时,我会对用户输入的内容进行HTML实体编码,防止恶意脚本被浏览器解析执行。此外,我还会在服务器端设置内容安全策略(CSP),进一步限制恶意脚本的执行。 -
CSRF解决方案:
我会在服务器端生成一个唯一的CSRF令牌,并将其作为隐藏字段添加到表单中。在处理表单提交时,我会验证令牌是否有效。同时,我还会结合用户IP地址和Referer头进行双重验证,确保请求的合法性。
二、项目功能
1、权限菜单
首先用户登录后我们会把权限和用户信息存到会话里,然后跳转到首页时候根据用户权限判断,需要展示的哪些菜单栏,并且在路由拦截里面进行权限跳转拦截,防止用户手动输入地址跳转
2、商品列表页面
原因:在商品列表数据有很多的时候,滚动加载会导致页面卡顿,内存溢出
解决方案:
- 图片懒加载
- 虚拟滚动(减少dom操作)
三、项目问题
1、在写react项目中遇到.ts文件无法使用const userStore = useUserStore();
项目中有个需求是要在ts文件使用store,因为它是在创建store之前引入,所有导致报错
原因:store创建之前使用了store
解决方案:
- 创建createPinia实例,导出文件,在组件外部ts导入使用
- 官方文档推荐在组件内部使用
2、在使用app端写renderjs从renderjs里面把数据传给逻辑层是,一直接受不到数据
原因:我是在使用vue3的写法写的,当时接受的方法写在setup里面,数据就是打印出来,目前不清楚原因是为什么
解决方案:
- 于是我使用vue2的写法拿到了从视图层传过来的数据
3、uniapp在使用u-input是设置只读,点击触发不了外层点击事件
原因:在一般情况下,被只读&禁用的u-input元素会拦截所有的鼠标事件,导致外层的view上写的点击事件不再生效。而加上pointer-events: none;后,u–input就不再拦截鼠标事件,外层的view上的点击事件就能够正常生效了。
解决方案:禁用输入框或者设置只读,然后加上pointer-events: none样式
参考地址:【uniapp】解决在H5谷歌浏览器下 u-input 标签 设置只读后,click事件不生效_uniapp input 只读-CSDN博客
4、uview-plus升级到最新版本3.3.31报错Uncaught TypeError: import_meta.glob is not a function
原因:vite版本过低,我的原来vite版本原来2.9.9
解决方案:升级uview-plus版本但是没有升级vite版本,vite版本升级一下就好了
5、微信小程序设置动态具名插槽无法显示内容
解决方案:不动态写具名插槽
6、微信小程序ts文件里面写const instance = getCurrentInstance();打印出来是undefined
原因:getCurrentInstance()
是一个用于获取当前页面实例的方法,需要在页面setup里面获取,例如 onLoad
、onShow
等。如果在页面的生命周期函数之外调用,可能会导致无法正确获取实例。
解决方案:在vue文件获取const instance = getCurrentInstance();并且传到ts文件,不要在ts文件里面直接写
觉得对你有帮助的可以收藏加关注,后续还会更新更多内容,如有对文章有需要批改的地方欢迎留言,我会尽最大的努力完善最好的总结
欢迎大家使用华玥组件库