# 面试宝典 **Repository Path**: HZIF/interview-guide ## Basic Information - **Project Name**: 面试宝典 - **Description**: 前端的面试宝典 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-09-16 - **Last Updated**: 2022-09-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 面试宝典接口地址 - 面试题板块接口地址 - 最新面试题接口地址 https://offer.qfh5.cn/api/iq?sort=addtime&total=false - 最新回答接口地址 https://offer.qfh5.cn/api/answer?size=5&total=false - 热门面试题接口地址 https://offer.qfh5.cn/api/iq?sort=hot&total=false - 重难点面试题接口地址 https://offer.qfh5.cn/api/iq?sort=difficulty&total=false - 排行榜板块接口地址 - 添加排行接口地址 https://offer.qfh5.cn/api/user?size=7&sort=iq&total=false - 回答排行接口地址 https://offer.qfh5.cn/api/user?size=7&sort=answer&total=false - 面试题更多接口地址 - 最新面试题更多接口地址 https://offer.qfh5.cn/api/iq?sort=addtime&page=1&size=15 - 最新问答更多接口地址 https://offer.qfh5.cn/api/answer?answer=1&page=1&size=15 - 热门面试题更多接口地址 https://offer.qfh5.cn/api/iq?sort=hot&page=1&size=15 - 重点难点面试题更多接口地址 https://offer.qfh5.cn/api/iq?sort=difficulty&page=1&size=15 - 面试题详情接口地址 - 详情接口地址 https://offer.qfh5.cn/api/iq/问题id - 面试题答案接口地址 - 答案接口地址 https://offer.qfh5.cn/api/answer?userid=用户id&answer=1&page=1&size=15 - 登录注册接口地址 - 检查用户名接口地址 https://offer.qfh5.cn/api/user/check?username=用户名 - 用户注册接口地址 https://offer.qfh5.cn/api/user/reg - 用户登录接口地址 https://offer.qfh5.cn/api/user/login?username=用户名&password=用户密码 - 个人中心接口地址 - 我的面试题接口地址 https://offer.qfh5.cn/api/user/verify - 我的回答接口地址 https://offer.qfh5.cn/api/answer?userid=用户id&getiqname=1&size=5 - 用户题目概览 - 用户题目概览 https://offer.qfh5.cn/api/iq?userid=用户id&page=页数&size=数目 ## 前端工作 ### 写页面(功能概述) #### 面试宝典主页 (index.html) ##### ajax发送请求拉取数据渲染主页 ```js // 渲染面试题 function renderEle(data,pageIndex) { let res = data.data.result ? data.data.result : data.data; let result = res.map(item => { let time = item.addtime.substring(0, 10); let type = item.question ? item.question : item.content; let hot = item.hot ? `${item.hot}浏览 · ${item.answer}回答` : `@${item.iq.question}`; return `
  • ${++pageIndex}

    ${type} ${hot}
    ${time}
  • ` }).join(''); return {result,pageIndex} } ``` ##### 点击问题跳转到对应问题详情页 ```js // 点击面试题跳转详情页 quesLeft.onclick = async function (e) { if(e.target.classList.contains("question")||e.target.classList.contains("hotAnswer")){ let id = e.target.getAttribute("ques_id"); let data = await Pajax({ url: `/api/iq/${id}` }) localStorage.setItem('quesInfo',JSON.stringify(data.data)); location.href = "./detail.html"; } } ``` ##### 点击用户姓名跳转到对应用户发布题目概览页 ```js // 点击用户名跳转到用户题目概览页 addRanking.onclick = function (e) { if(e.target.classList.contains("username")){ let username = e.target.innerText; let userid = e.target.getAttribute("user_id"); goQues(username,userid,"userQues"); } } answerRanking.onclick = function (e) { if(e.target.classList.contains("username")){ let username = e.target.innerText; let userid = e.target.getAttribute("user_id") goQues(username,userid,"userAnswer"); } } ``` #### 题目详情页 (detail.html) ##### 显示发布该题目的发布者信息、浏览数以及难度 ```js let glyphiconstar = ` ` detailUserInfo.innerHTML = `
    ${username}${quesInfo.hot}浏览难度 :
    ${glyphiconstar}
    ` let star = document.querySelectorAll(".glyphicon-star"); // 根据问题的难度点亮星星 star.forEach((item, index) => { if (index < quesInfo.difficulty) { item.style.color = "yellow"; } }) ``` ##### 如有问题补充则显示问题补充,无则显示暂无问题补充 ```js // 如果问题补充不为空 if (quesInfo.detail) { detailContent.classList.add('haveques'); let nodes = detail.document.nodes; let nodeslength = nodes.length; if (nodes[1]) { nodeslength = nodeslength + nodes[1].nodes.length; } for (let i = 0; i < nodeslength; i++) { detailContent.innerHTML = detailContent.innerHTML + `` } let code = document.querySelectorAll(".code"); nodes.forEach((item,index) => { item.nodes.forEach((item2,index2) => { if (item2.nodes) { code[index2].innerText = item2.nodes[0].leaves[0].text; } else if (item2.leaves[0].text != '') { code[index].innerText = item2.leaves[0].text; } else { code[index].innerText = '请输入内容'; } }) }) } else { detailContent.innerHTML = detail; } ``` ##### 显示用户评论信息 ```js if (quesInfo.answer.length == 0) { answerContainer.classList.add("noAnswer"); answerContainer.innerHTML = ''; } else { let res = quesInfo.answer.map(item => { let imgurl = item.user.avatar ? `https://offer.qfh5.cn/${item.user.avatar}` : '../img/userAvatar.png'; let username = item.user.nickname ? item.user.nickname : item.user.username; let addtime = item.addtime.substring(0, 10); return `
    ${item.like.length}
    ${username} ${addtime}
    ${item.content}
    ` }).join(''); answerContainer.innerHTML = res; } ``` ##### 点击发布者名字跳转到发布者面试题概览 ```js detailUserInfo.onclick = (e) => { if(e.target.classList.contains("username")){ let username = e.target.innerText; let userid = e.target.getAttribute("user_id") goQues(username,userid,"userQues"); } } ``` ##### 点击题目跳转到对应题目详情页 ```js // 右侧问题区域点击跳转问题详情 detailRight.onclick = async function (e) { if (e.target.classList.contains("question")) { let id = e.target.getAttribute("ques_id"); let data = await Pajax({ url: `/api/iq/${id}` }) localStorage.setItem('quesInfo', JSON.stringify(data.data)); location.href = "./detail.html"; } } ``` ##### 显示右侧最新面试题及热门面试题 ```js async function render() { // 最新面试渲染 let meetData = await Pajax({ url: '/api/iq?sort=addtime&total=false' }); let meetres = renderEle(meetData); meet.innerHTML = meet.innerHTML + meetres; // 热门面试渲染 let hotData = await Pajax({ url: '/api/iq?sort=hot&total=false' }); let hotres = renderEle(hotData) hot.innerHTML = hot.innerHTML + hotres; } function renderEle(data) { let res = data.data.map((item, index) => { let time = item.addtime.substring(0, 10); let type = item.question ? item.question : item.content; return `
  • ${index + 1}

    ${type} ${item.hot ? `${item.hot}浏览 · ${item.answer}回答` : `@${item.iq.question}`}
  • ` }).join(''); return res } ``` ##### 解决返回上一个题目详情页直接回退回首页的思路 - 因为是用localStorage的方法存储点击面试题的详情,到详情页后再进行渲染 所以便会导致在详情页时点击另外的面试题会替换掉当前面试题的详情数据。 - 所以可以用一个数组保存当前面试题详情与点击另外面试题时的详情数据,然后再次存入localStorage中 - 当下一次跳转详情页时渲染的就为localStorage存入的数组中的最后一个面试题详情数据 - 当返回时就渲染当前面试题的上一个面试题详情数据 - 如当前返回的已经是数组的第一个面试题详情数据,那再返回时就直接返回首页 #### 登录页 (login.html) #### 注册页 (reg.html) #### 个人中心页 (userCenter.html) #### 用户题目或回答概览页 (userQues.html) ##### 通过存入localStorage中的type判断是哪一类型 ```js function goQues(username,userid,type){ localStorage.setItem('userInfo',JSON.stringify({"username":username,"userid":userid,"type": type})); location.href = "./userQues.html"; } ``` ##### 通过拉取localStorage中存储的该次点击的类型发送ajax请求拉取该类型的面试题或面试题答案 ```js // 渲染更多面试题或答案 async function renderMore(userid, page , type , pageIndex) { if (type == 'userQues') { let quesData = await Pajax({ url: `/api/iq?userid=${userid}&page=${page}&size=15` }); let res = renderEle(quesData,pageIndex).result; ques.innerHTML = ques.innerHTML + res; }else if(type == 'userAnswer'){ let quesData = await Pajax({ url: `/api/answer?userid=${userid}&answer=1&page=${page}&size=15` }); let res = renderEle(quesData,pageIndex).result; ques.innerHTML = ques.innerHTML + res; }else if(type != 'answer') { let quesData = await Pajax({ url: `/api/iq?sort=${type}&page=${page}&size=15` }); let res = renderEle(quesData,pageIndex).result; ques.innerHTML = ques.innerHTML + res; } else { let quesData = await Pajax({ url: `/api/answer?${type}=1&page=${page}&size=15` }); let res = renderEle(quesData,pageIndex).result; ques.innerHTML = ques.innerHTML + res; } } ``` ##### 渲染题目或回答概览 ```js function renderEle(data) { let res = data.data.map((item, index) => { let time = item.addtime.substring(0, 10); let type = item.question ? item.question : item.content; let hot = item.hot ? `${item.hot}浏览 · ${item.answer}回答` : `@${item.iq.question}`; return `
  • ${index + 1}

    ${type} ${hot}
    ${time}
  • ` }).join(''); return res } ``` ##### 如滚动条到底部则继续加载下一页的题目或回答概览 ```js window.onscroll = async function () { let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; let windowHeight = document.documentElement.clientHeight || document.body.clientHeight; let scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; //考虑到滚动的位置一般可能会大于一点可滚动的高度,所以这里不能用等于 if (scrollTop + windowHeight >= scrollHeight) { ++page; pageIndex+=15; let pages = renderMore(userid, page, type , pageIndex); } } ``` #### 发送ajax请求 ```js let meetData = await Pajax({ url: '/api/iq?sort=addtime&total=false' }); ``` #### 解决跨域问题 - 在调用接口的过程中遇到跨域问题,需要配置前端代理解决跨域 - 首先用express和path开启前端静态资源服务器 ```js let express = require('express'); let path = require('path'); let { createProxyMiddleware: proxy } = require('http-proxy-middleware'); let app = express(); app.use(express.static(path.join(__dirname + '/src'))); ``` - ##### 配置前端代理 - 安装代理 依赖 npm i http-proxy-middleware - 引入依赖 ```js let { createProxyMiddleware: proxy } = require('http-proxy-middleware'); ``` - 配置代理 ```js let qfh5 = { target: 'https://offer.qfh5.cn', changeOrigin: true, ws: true, } app.use('/api', proxy(qfh5)) ```