1、工程化与架构设计(考察项目管理和架构能力)
1.1 你负责的可视化编排项目中,如何设计组件的数据结构来支持"拖拉拽"功能?如何处理组件间的联动关系?
{
components : [
{
id : 'comp1' ,
type : 'input' ,
position : { x : 100 , y : 100 } ,
props : { } ,
connections : [
{ target : 'comp2' , type : 'data' }
]
}
] ,
eventBus : new EventEmitter ( )
}
1.2 你提到使用 Vue 的 render 函数实现可视化编排,能详细讲讲这个实现思路吗?与使用 template 的方案相比有什么优势?
{
render ( h ) {
return h ( 'div' , {
class : 'editor' ,
on : {
drop : this . handleDrop
}
} , this . components. map ( comp => {
return h ( comp. type, {
props : comp. props,
style : {
position : 'absolute' ,
left : ` ${ comp. position. x} px ` ,
top : ` ${ comp. position. y} px `
} ,
on : this . createComponentEvents ( comp)
} )
} ) )
}
}
1.3 在3D展厅项目中,你们是如何解决大型3D模型加载性能问题的?如何平衡展示效果和加载性能?
const loadModel = async ( url, level ) => {
const loader = new THREE. GLTFLoader ( ) ;
const modelUrl = level === 'high' ? url : url. replace ( '.glb' , '_low.glb' ) ;
return await loader. loadAsync ( modelUrl) ;
} ;
const lod = new THREE. LOD ( ) ;
lod. addLevel ( highDetailModel, 0 ) ;
lod. addLevel ( mediumDetailModel, 50 ) ;
lod. addLevel ( lowDetailModel, 100 ) ;
2、技术深度(考察核心技术掌握程度)
2.1 Vue 相关
const app = new Vue ( {
data : {
count : 1
} ,
mounted ( ) {
this . count = 2 ;
this . $nextTick ( ( ) => {
console. log ( this . $el. textContent) ;
} ) ;
this . count = 3 ;
}
} ) ;
2.2 性能优化:
function handleScroll ( ) {
const scrollTop = document. documentElement. scrollTop;
this . items. forEach ( item => {
if ( item. offsetTop < scrollTop + window. innerHeight) {
item. visible = true ;
}
} ) ;
}
window. addEventListener ( 'scroll' , handleScroll) ;
function handleScroll ( ) {
if ( this . scrollTimer) clearTimeout ( this . scrollTimer) ;
this . scrollTimer = setTimeout ( ( ) => {
requestAnimationFrame ( ( ) => {
const scrollTop = document. documentElement. scrollTop;
const viewportHeight = window. innerHeight;
this . items. forEach ( item => {
const rect = item. getBoundingClientRect ( ) ;
if ( rect. top < viewportHeight) {
item. visible = true ;
}
} ) ;
} ) ;
} , 16 ) ;
}
window. addEventListener ( 'scroll' , handleScroll, { passive : true } ) ;
2.3 算法设计
function arrayToTree ( items ) {
const result = [ ] ;
const itemMap = { } ;
items. forEach ( item => {
itemMap[ item. id] = { ... item, children : [ ] } ;
} ) ;
items. forEach ( item => {
const parent = itemMap[ item. parentId] ;
if ( parent) {
parent. children. push ( itemMap[ item. id] ) ;
} else {
result. push ( itemMap[ item. id] ) ;
}
} ) ;
return result;
}
3. 工程实践(考察实际问题解决能力)
3.1 在你的项目中,如何处理前端权限控制?包括路由权限和按钮权限。
const router = new VueRouter ( {
routes : [
{
path : '/admin' ,
component : Admin,
meta : {
requiresAuth : true ,
permissions : [ 'admin' ]
}
}
]
} ) ;
router. beforeEach ( ( to, from, next ) => {
if ( to. meta. requiresAuth) {
const hasPermission = checkPermissions ( to. meta. permissions) ;
if ( ! hasPermission) {
next ( '/403' ) ;
}
}
next ( ) ;
} ) ;
Vue. directive ( 'permission' , {
inserted ( el, binding ) {
const permission = binding. value;
if ( ! hasPermission ( permission) ) {
el. parentNode. removeChild ( el) ;
}
}
} ) ;
3.2 你们的3D项目是如何做异常监控和性能监控的?
const stats = new Stats ( ) ;
document. body. appendChild ( stats. dom) ;
window. addEventListener ( 'error' , ( event ) => {
if ( event. target instanceof HTMLImageElement ) {
handleResourceError ( event) ;
} else {
handleRuntimeError ( event) ;
}
} ) ;
canvas. addEventListener ( 'webglcontextlost' , handleContextLost) ;
canvas. addEventListener ( 'webglcontextrestored' , handleContextRestored) ;
3.3 在多人协作的项目中,你们是如何确保代码质量的?具体的工程化措施有哪些?
4. 技术视野(考察技术广度和思维方式)
4.1 Vue2 到 Vue3 的升级中,你认为最重要的变化是什么?这些变化解决了什么问题?
4.2 对比 Webpack 和 Vite,你认为它们各自的优势是什么?在什么场景下选择使用?
4.3 前端微服务架构中,你认为最关键的技术挑战是什么?如何解决?
5.项目管理(考察管理能力)
5.1 作为项目经理,你是如何评估项目风险的?能举个具体的例子吗?
5.2 在带领团队时,你是如何进行技术选型和技术架构决策的?
5.3 如何平衡项目进度和代码质量?
6.实战题目(考察实际编码能力)
6.1 手写题
class EventEmitter {
on ( event, callback ) { }
emit ( event, ... args ) { }
off ( event, callback ) { }
once ( event, callback ) { }
}
class EventEmitter {
constructor ( ) {
this . events = new Map ( ) ;
}
on ( event, callback ) {
if ( ! this . events. has ( event) ) {
this . events. set ( event, [ ] ) ;
}
this . events. get ( event) . push ( callback) ;
}
emit ( event, ... args ) {
if ( this . events. has ( event) ) {
this . events. get ( event) . forEach ( callback => {
callback . apply ( this , args) ;
} ) ;
}
}
off ( event, callback ) {
if ( this . events. has ( event) ) {
const callbacks = this . events. get ( event) ;
const index = callbacks. indexOf ( callback) ;
if ( index !== - 1 ) {
callbacks. splice ( index, 1 ) ;
}
}
}
once ( event, callback ) {
const wrapper = ( ... args) => {
callback . apply ( this , args) ;
this . off ( event, wrapper) ;
} ;
this . on ( event, wrapper) ;
}
}
6.2 设计题
class Cache {
constructor ( options = { } ) {
this . storage = options. storage || new MemoryStorage ( ) ;
this . maxSize = options. maxSize || 1000 ;
this . cleanupInterval = options. cleanupInterval || 60000 ;
this . startCleanup ( ) ;
}
async set ( key, value, options = { } ) {
const item = {
value,
priority : options. priority || 0 ,
expires : options. expires ? Date. now ( ) + options. expires : null ,
size : this . getSize ( value)
} ;
await this . ensureSpace ( item. size) ;
await this . storage. set ( key, item) ;
}
async get ( key) {
const item = await this . storage. get ( key) ;
if ( ! item) return null ;
if ( item. expires && item. expires < Date. now ( ) ) {
await this . storage. delete ( key) ;
return null ;
}
return item. value;
}
private async ensureSpace ( requiredSize ) {
const currentSize = await this . getCurrentSize ( ) ;
if ( currentSize + requiredSize <= this . maxSize) return ;
const items = await this . getAllItems ( ) ;
items. sort ( ( a, b ) => {
if ( a. priority !== b. priority) return a. priority - b. priority;
return ( a. expires || Infinity ) - ( b. expires || Infinity ) ;
} ) ;
let freedSpace = 0 ;
for ( const item of items) {
if ( currentSize - freedSpace + requiredSize <= this . maxSize) break ;
await this . storage. delete ( item. key) ;
freedSpace += item. size;
}
}
private startCleanup ( ) {
setInterval ( async ( ) => {
const items = await this . getAllItems ( ) ;
const now = Date. now ( ) ;
for ( const item of items) {
if ( item. expires && item. expires < now) {
await this . storage. delete ( item. key) ;
}
}
} , this . cleanupInterval) ;
}
}