08-项目八股文

6/28/2022

# 项目八股文(码路教育)

# 1,介绍一下你最近做的项目?介绍一下这个项目?

如何高水平地介绍一个管理系统的项目?

  • 项目介绍(解决什么问题的、什么行业、开发团队是怎样的、前端多少人)
  • 技术栈(精确到各个技术的版本号)
  • 有哪些功能(权限管理、国际化、地图可视化、哪些图表、WebSocket、特殊需求、业务组件)
  • 难点(权限复杂、接口多、表单表格交互复杂、需求特殊)
  • 思考(工程架构的稳定性、权限路由的合理设计、状态管理、组件化形成文档、MD记录需求细节、代码规范与统一)

如何介绍一个ToC 的Web产品(webapp、官网、小程序)?

  • 项目介绍(功能性、资讯类、营销类。。。,行业、几个人)
  • 技术栈:比较旧一点的技术、样式布局
  • 值得一说的东西:用户体验(健壮性、兼容性、媒体查询与响应式、参与C端交互设计);性能优化(图片优化、静态文件、首页服务端渲染、代码层面);SEO优化策略(参考QF官网);CSS、JS、jQuery,非常考虑前端基本功。
  • 项目力:你在推动产品更好发展的方面做了哪些努力和付出?

如何优雅地介绍一个uniapp项目?

  • 项目介绍(什么行业的产品、解决什么问题?前端几个人?)
  • 技术栈(uniapp)做了哪些功能:支付?定位?分享?地图?用到了哪些组件和API。
  • 用到哪些功能:地理定位、地图距离计算、用户登录、下拉刷新、触底加载等。
  • 总结性地评价一下uniapp的特点和优势
  • 建设性评价一下 uniapp 的缺点(3个点左右)
  • 概括性表达一下自己的 uniapp 开发心得,工作态度和改善行动。

如何高水平地介绍一个 RN 项目?

  • 项目背景(什么行业、为什么选择RN、几个人、做了多久)
  • 有哪些功能,用到了哪些RN插件?(3~5条技术)
  • 评价:描述恶劣的开发环境,遇到哪些困难,最后是如何解决的。

# 2,详细说一下你这个项目用到了哪些技术栈?

# 3,说一下你项目中有什么亮点?

可以从:首屏优化、工具、性能、效率、规范、获得了什么成果、代码重构重构切入。
1

# 4,说一下你项目中遇到过一些什么难点?你是怎么解决的?

可以从:记录页面滚动位置、项目历史遗留问题(重构)、系统埋点、大文件上传、在线阅览office
1

# 5,你封装过哪些有代表性的组件?举两个例子。

# 6,你做过哪些项目优化?

# 7,ToC vs ToB?

- 从开发角度:ToC产品一般都有UI,有明确的原型文档、很难找到匹配的组件库、样式代码多。
- 从用户角度:ToC性能优化、用户体验、交互设计。
- 从功能角度:ToC产品的功能繁多,不确定。

- 从开发角度:ToB基本上都是增删改查、表单多、表格多、接口多、数据准确性要求、没有UI、但有原型、样式代码少、有现成的组件库可用。
- 从用户角度:ToB产品只要保证数据准备就行,对用户体验、性能没有那么高要求。
- 从功能角度:ToB增删改查、图表、地图、文件上传与下载、表单、websocket。
1
2
3
4
5
6
7

# 8,你是怎么部署上线的?上线有哪些注意的?

# 9,你这个项目的鉴权是怎么做?

# 10,你这个管理系统的权限是怎么做的?(前端做法、后端做法)

# 11,你项目的难点?亮点?(从业务的角度说难点和亮点,切忌说技术层面的难点)

# 12,你这个项目的国际化怎么做?

# 13,项目经验方面的问题(如何知道你是否有项目经验)

  • 你知道的 Web 性能优化方案有哪些?

  • 什么是服务端渲染?SSR、BSR各有什么优势和劣势?有哪些SEO策略?

  • 构建工具

    • Webpack 和 Gulp 的区别?
    • Webpack 常用的 loaders 和 plugins 有哪些?
    • 简述 Webpack 热更新的工作原理
    • 什么是vue-loader?它有什么用?
  • 常用的Git命令有哪些?

  • 常用的npm命令有哪些?

  • 常用的yarn命令有哪些?

  • 常用的Linux命令有哪些?

  • 管理系统的权限是怎么设计的?

  • 前端大文件上传怎么实现?什么是断点续传、分片上传?

  • 当后端一次性丢给你10万条数据, 作为前端工程师的你, 要怎么处理?

  • 什么是TS?TS中新增了哪些新语法?常用的数据类型有哪些?tsconfig.json配置文件?声明文件有什么用(@types/*)?

  • JS水印怎么实现?

    • Word / PDF水印,不用从技术角度
    • 网站(防止拍照)document.appendChild()
    • 图片水印(后端实现)node.js 中 images 水印

# 14,你的管理系统中有没有用过websocket?(socket.io)

# 15,单点登录(SSO)

  • 常见登录鉴权方案:https://zhuanlan.zhihu.com/p/271768645
  • 什么是单点登录?
  • 为什么要使用单点登录?
  • 除了单点登录外,前端还有哪些常用的鉴权方案?并对比它们之间的优势、劣势?

# 16,VUE项目中的优化

1.不要在模板里面写过多表达式
2.循环调用子组件时添加key
3.频繁切换的使用v-show,不频繁切换的使用v-if
4.尽量少用float,可以用flex
5.按需加载,可以用require或者import()按需加载需要的组件
6.路由懒加载
7. 对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户体验。我们在项目中使用 Vue 的 vue-lazyload 插件
8. Vue 会通过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 Vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,那如何禁止 Vue 劫持我们的数据呢?可以通过 Object.freeze 方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了。
1
2
3
4
5
6
7
8

# 17, 移动端开发都遇到过哪些问题?

1,一些情况下对非可点击元素如(label,span)监听click事件,ios下不会触发,css增加cursor:pointer就搞定了。
2,input 的placeholder会出现文本位置偏上的情况
    input 的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决是设置line-height:normal
3,zepto点击穿透问题,引入fastclick解决;event.preventDefault
4,当输入框在最底部的时候,弹起的虚拟键盘会把输入框挡住。 Element.scrollIntoViewIfNeeded(opt_center)
1
2
3
4
5

# 18, 描述一下你的React项目

1). 此项目为一个前后台分离的招聘的SPA, 包括前端应用和后端应用
2). 包括用户注册/登陆, 大神/老板列表, 实时聊天等模块
3). 前端应用: 使用React全家桶+ES6+Webpack等技术
4). 后端应用: 使用Node + express + mongodb + socketIO等技术
5). 采用模块化、组件化、工程化的模式开发
1
2
3
4
5

# 19, 项目中fastClick的300ms延迟解决方案

问题剖析:
1.移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟
2.原因: 移动端的双击会缩放导致click判断延迟

解决方案: fastclick库

实现原理: 在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后真正的click事件阻止掉
1
2
3
4
5
6
7

# 20, 项目上线了,外链样式页面刷新页面样式丢失问题

问题剖析: 
项目通常需要一份重置样式文件reset.css, 而该文件通常放在static中通过link引入,
<link rel="stylesheet" href="./static/css/reset.css" />, 但在子路由组件中刷新页面会发现重	置样式文件失效,原因是加载路径错误

解决方案:
去掉点, 将相对路径改成绝对路径
1
2
3
4
5
6

# 21, scoped下修改第三方样式数据(深度选择器)

问题剖析: 
在Vue组件化开发中为了避免组件之间样式冲突问题,可在style标签中加上scoped属性,等同于设置样式作用域,只在当前的组件生效,其原理就是给当前的选择器后添加一个随机生成的唯一的属性字段(swiper-container[data-v-7c66a6a2]),但如果需要在有scoped的组件中修改外部组件的样式(想修改swiper库的样式),因为scoped的限制问题就无法修改

解决方案:
1.使用深度选择器: 原生css样式使用  >>>,  在stylus,sass,less中使用 /deep/
2.语法示例: 外层选择器 /deep/ 修改样式的选择器
1
2
3
4
5
6

# 22, 项目中 params传参刷新参数丢失问题

问题剖析: 
1.vue-router进行路由跳转的时候可通过params传参
2.如果在注册路由的时候没有使用占位符进行注册: ‘/home/:id’,首次路由跳转可以获取params参数,再次刷新页面params数据丢失

解决方案:
注册路由的时候写好占位符
1
2
3
4
5
6
export default [
{
path: '/home/:id',
component: Home,
name: 'home',
meta: {
isShow: true
}
}
]
<router-link :to="{name: 'home', params: {id: 1}}">home</router-link>
<router-link :to="/home/1">home</router-link>
1
2
3
4
5
6
7
8
9
10
11
12

# 23, 项目打包,map文件过大问题怎么解决?

问题剖析: 
1.打包生成的dist文件中的文件是压缩文件,如果发生错误不能很好的提示是哪里出了问题
2. .map文件就是为了提示用户哪里出了问题

解决方案
实际项目上线文件是不需要.map文件的
1
2
3
4
5
6

# 24, 生产环境 & 开发环境解决跨域问题

问题剖析: 
1.跨域: 浏览器为了安全起见推出了同源策略(协议,域名,端口号三者完全一样就是同源,否则就是跨域)
2.因为现在开发的项目都是前后端完全分离(前端有自己的服务器,如:vue脚手架服务器,同时还有服务器端服务器)的项目,必然存在跨域问题

解决方案之开发环境跨域:
1.配置正向代理

解决方案之生产环境跨域:
1.后台使用CORS解决跨域,存在风险,容易被人恶意攻击
2.使用nginx反向代理
3.思路: 页面请求发送给nginx服务器,nginx根据配置动态匹配要请求的服务器地址,最终的请求由nginx服务器发出解决跨域
1
2
3
4
5
6
7
8
9
10
11

# 25, 使用swiper & better-scroll生成多个实例只有一个生效

问题剖析: 
1.使用swiper或者better-scroll的时候需要实例化,一下以swiper为例说明,在new Swiper的时候通常传递一个class类名,其目的是为了让swiper找到页面中对应的DOM对象从而在该DOM对象上产生作用
2.当一个页面中同时new多个swiper或者better-scroll的时候,使用的class类名一样的话则最先new的那个swiper生效,其他的无效
3.场景: 当封住一个swiper或者better-scroll组件的时候在一个页面复用,最先使用的那个swiper组件能够使用,其他的失效

解决方案:
将class换成ref
1
2
3
4
5
6
7

# 26, swiper或者better-scroll在页面加载后不生效

问题剖析
new的时机太早,在实例化对象的时候页面的数据还没有到达或者没有渲染完成

解决方案
1.目标: 想办法在列表数据更新显示之后才去创建swiper
2.方式一: 使用watch+$nextTick()
3.方式二: 使用回调+$nextTick()
1
2
3
4
5
6
7

# 27, Vue实例的响应式属性 VS 非响应式属性

问题剖析
1.响应式式属性
    (1)Vue实例初始化之前定义在data中的属性
    (2)修改响应式属性之后,会触发视图更新	
2.非响应式属性
    (1)直接通过this.xxx = value添加的属性是非响应式属性

解决方案
1.使用Vue.set() 或this.$set(target, propertyName, value)
2.示例:  this.obj.age = 30 -- this.$set(this.obj, 'age', 30)
1
2
3
4
5
6
7
8
9
10
data() {
    this.age = 3 // age不是响应式的
    return {
        obj: { // obj是响应式属性
            name: 'kobe' //  name也是响应式属性
        }
    }
},
1
2
3
4
5
6
7
8

# 28, 项目中路由组件再次被切换回来的时候如何停留在之前页面滚动的位置

问题剖析:
想要保留路由组件之前页面滚动的位置就要保留之前的状态

解决方案	
1.使用keep-alive缓存路由组件
2.说明: keep-alive会缓存动态组件,而不是销毁,也就是意味着下次加载缓存组件的时候不会去new新的实例组件,同时状态也会用缓存之前的状态,即使再次加载组件的时候里边的状态有更新
1
2
3
4
5
6

# 29, 追问:如果在keep-alive缓存的动态路由组件中有一个组件需要加载的时候即使更新状态怎么办,因为keep-alive的特性是缓存组件之前的状态

解决方案: 使用keep-alive的include或者exclude属性,将需要及时刷新的路由组件排除
1

# 30, 项目性能优化之UI库按需加载(打包)问题

问题剖析: 
当开发的项目需要引入第三方的UI组件库(antd/mint-ui/element-ui)的时, 需要会打包所有组件的js和css, 而项目中只使用了其中少部分组件. 使用按需打包实现只打包使用的组件, 从而减小打包文件大小

解决方案:
配置按需加载
1
2
3
4
5

# 31, 项目性能优化之路由组件懒加载

问题剖析: 
1.Vue开发中使用路由跳转页面时,通常会注册多个路由,对应的有多个路由组件
2.在Vue打包后文件非常之大,如果没有路由懒加载的话,一上来加载所有页面的文件
3.如果同时加载所有页面的文件内容的话会导致首屏加载显示过慢,甚至白屏,导致用户体验差

解决方案:
路由组件懒加载
1
2
3
4
5
6
7

# 32, 项目性能优化之图片懒加载

问题剖析:
当一个项目图片过多的时候如果一次性加载渲染代价较大,导致用户看到的效果时间延迟

解决方案:
1.npm install vue-lazyload
2.声明使用: Vue.use(VueLazyLoad, {loading: loading图片})
3.组件使用: &lt;img v-lazy="item.primaryPicUrl"  alt="新品">
1
2
3
4
5
6
7

# 33, 项目性能优化之HTML性能优化

1.HTML标签有始终。 减少浏览器的判断时间

2.把script标签移到HTML文件末尾,因为JS会阻塞后面的页面的显示。

3.减少iframe的使用,因为iframe会增加一条http请求,阻止页面加载,即使内容为空,加载也需要时间

4.id和class,在能看明白的基础上,简化命名,在含有关键字的连接词中连接符号用'-',不要用'_'

5.保持统一大小写,统一大小写有利于浏览器缓存,虽然浏览器不区分大小写,但是w3c标准为小写

6.清除空格,虽然空格有助于我们查看代码,但是每个空格相当于一个字符,空格越多,页面体积越大,像google、baidu等搜索引擎的首页去掉了所有可以去掉的空格、回车等字符,这样可以加快web页面的传输。可以借助于DW软件进行批量删除 html内标签之间空格,sublime text中ctrl+a,然后长按shift+tab全部左对齐,清除行开头的空格

7.减少不必要的嵌套,尽量扁平化,因为当浏览器编译器遇到一个标签时就开始寻找它的结束标签,直到它匹配上才能显示它的内容,所以当嵌套很多时打开页面就会特别慢。

8.减少注释,因为过多注释不光占用空间,如果里面有大量关键词会影响搜索引擎的搜索

9.使用css+div代替table布局,去掉格式化控制标签如:strong,b,i等,使用css控制

10.代码要结构化、语义化

11.css和javascript尽量全部分离到单独的文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 34, 项目性能优化之css性能优化

多利用继承,多个子元素公用的样式,如果该样式能继承的话就写在父元素身上

尽量减少重绘重排的次数

选择器命名规范,通过id寻找更快

动画区域开启独立的图层
定位: position: absolute/relative
Will-change: xxx;

合并、压缩你的css文件,减少http请求,可以借助工具或者自动化构建。

使用CSS sprite来处理你的图片
1
2
3
4
5
6
7
8
9
10
11
12
13

# 35, 项目性能优化之JS性能优化

1.合并压缩js
2.减少对DOM的操作,避免重绘重排
3.减少请求的个数,节省网络资源
4.封装功能函数实现复用
5.循环语句中避免定义变量
6.慎用闭包
7.函数节流,函数防抖
1
2
3
4
5
6
7

# 36, 项目性能优化之封装组件

问题剖析
1.一个大型项目中内容足够复杂,在很多页面中部分内容是重复的
2.如果不做任何处理导致代码冗余,不利于提高性能

解决方案
1.抽取封装组件
2.封装组件思想: 
    a)组件内部保留相同的内容
    b)不同的内容抽取出来由使用者传递进组件内部,提供组件的复用性
    c)组件内部可提前声明规定用户传递的参数的必要性和数据类型
    d)通过标签属性的形式传递,在组件内部通过props接收
1
2
3
4
5
6
7
8
9
10
11

# 37, 两个独立html页面怎么通信?

问题描述:
如:淘宝A,B页面,A为商品页,B为购物车页,两个页面同时打开,在A页面点击商品添加至购物车,切换到B页面购物车怎么显示该商品信息

解决方案
1.利用localStroage,A页面将数据存入localStroage,B页面读取localStorage中的数据
2.关键点: B页面如何知道A页面什么时候存数据到localStorage
3.localStorage中有个‘storage’事件
4.window.addEventListener(‘storage’, callback),A页面存数据,B页面监听事件
1
2
3
4
5
6
7
8

# 38, 开发环境和生产环境都想用同一套代码,怎么办,是每个环境负责要配,还是有什么办法可以合并,怎么合并?

我们公司之前是把代码发包到公司自己的服务器,通过npm发包,用的时候,直接npm i安装使用。
1

# 39, 团队开发流程是什么?

# 40, bug管理工具用什么?

bug管理工具非常多,我们公司使用的是Gitlab。

Gitlab:
Gitlab管理bug也是最近才接触到。跟项目绑定,特别方便管理bug,随时assign给相关开发,也可以看到开发提交bug时的Commits,每次发版可以对照相关提交,既方便测试,也可以在出现问题时找到对应开发。
1
2
3
4

# 41, 一个页面编辑没有保存退出,你是怎么告诉用户,编辑了没有退出的,弹窗,你怎么做

页面存在编辑框,当用户进入编辑状态时,如果没有点击保存就离开页面,需弹窗提示。如:

实现原理:
使用路由守卫beforeRouteLeave进行控制,当路由守卫监听到页面路由发生改变时触发弹窗。
1
2

实现代码:

// 使用路由守卫判断是否离开当前页面
beforeRouteLeave(to, form, next) {
    if (this.editingRowId !== '') { // 此处为个人项目条件判断,当条件成立时才执行路由守卫
        this.$confirm('当前信息未保存,离开页面将会放弃所有修改数据,', '提示', {
            closeOnClickModal: false,
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            // 点击确定则往下执行
            next()
        }).catch(() => {
            // 取消则关闭弹窗不执行
        })
    } else {
        // 条件不成立则继续往下执行
        next()
    }
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 42, 公司有没有公共(项目)模板,拉过来就可以用

公司有自己的私服服务器,管理系统模板,都是直接拉过来使用。平常封装的一些功能模块,也是直接通过npm扔到服务器上。
1

# 43, 你们项目文件嵌套层级是几级

具体没有数过,应该有二级,三级,四级了吧,最多。
1

# 44, 在一个页面中,我想要引入其他的组件,应该怎么做,有没有批量引入的方法

使用require.context。

参考: https: //www.cnblogs.com/webhmy/p/15965661.html
1
2
3

# 45, v-show算不算重排

v-show指令算是重排的。因为v-show本质是基于css中的display属性来控制条件块的显示/隐藏;而重排的定义是 渲染树中的节点信息发生大小、距离等改变,需重新计算各个节点和css具体的大小和位置。当display属性控制条件块显示/隐藏时,会改变节点的大小和渲染树的布局,从而导致重排。
1

# 46, 项目中token过期是怎么取消后面的请求的

参考:https://juejin.cn/post/6844904186794999815
1

# 47,项目有用过TypeScript吗?

1)TypeScript我之前是有专门学习过,之前也有向项目负责人提议过将TypeScript加入到项目中去来。
2)经过领导综合的考虑(包括项目进度、成本、人员配置等考虑),最终说暂时不考虑不加入这么快。
3)如果贵公司项目能用TypeScript,我也很想挑战一下。
1
2
3
Last Updated: 1/12/2023, 6:49:17 PM