基于Vite2+Vue3的项目复盘总结,CSS块元素

  • husky:触发Git Hooks,执行脚本

  • lint-staged:检测文件,只对暂存区中有改动的文件进行检测,可以在提交前进行Lint操作

  • commitizen:使用规范化的message提交

  • commitlint: 检查message是否符合规范

  • cz-conventional-changelog:适配器。提供conventional-changelog标准(约定式提交标准)。基于不同需求,也可以使用不同适配器(比如: cz-customizable)。

yarn add husky lint-staged commitizen @commitlint/config-conventional @commitlint/cli  -D

复制代码

先配置适配器:

# yarn

npx commitizen init cz-conventional-changelog --yarn --dev --exact

# npm

npx commitizen init cz-conventional-changelog --save-dev --save-exact

复制代码

它会在本地项目中配置适配器,然后去安装cz-conventional-changelog这个包,最后在package.json文件中生成下面代码:

“config”: {

“commitizen”: {

“path”: “cz-conventional-changelog”

}

}

复制代码

现在我们可以添加一个脚本就可以编写规范化的提交:

“scripts”: {

“cz”: “git cz”

}

复制代码

接下来你可以执行yarn cz命令来编写一些约定好的提交规范:

image.png

此时我们已经根据约定规范提交了消息,但是我们怎么知道提交的消息是不是正确的呢,那么接下来就需要配置刚刚介绍到的commitlint,只需要一句命令即可完成配置,它会在项目根目录下面创建一个commitlint.config.js配置文件:

echo “module.exports = {extends: [‘@commitlint/config-conventional’]};” > commitlint.config.js

复制代码

它会使用@commitlint/config-conventional这个包里面提供的校验规则进行校验,你可以理解为ESLint的规则。

有了这个校验工具,怎么才可以触发校验呢,我们希望在提交代码的时候就进行校验,这时候husky就可以出场了,他可以触发Git Hook来执行相应的脚本,而我们只需要把刚刚的校验工具加入脚本就可以了,我们使用的是6.0的新版本,下面是具体使用方法:

我们需要定义触发hook时要执行的Npm脚本:

  • 提交前对暂存区的文件进行代码风格语法校验

  • 对提交的信息进行规范化校验

“scripts”: {

“lint-staged”: “lint-staged”,

“commitlint”: “commitlint --config commitlint.config.js -e -V”

},

“lint-staged”: {

“src/**/*.{js,vue,md,json}”: [

“eslint --fix”,

“prettier --write”

]

}

复制代码

接下来就是配置husky通过触发Git Hook执行脚本:

# 设置脚本prepare并且立马执行来安装,此时在根目录下会创建一个.husky目录

npm set-script prepare “husky install” && npm run prepare

# 设置pre-commit钩子,提交前执行校验

npx husky add .husky/pre-commit “yarn lint-staged”

# 设置pre-commit钩子,提交message执行校验

npx husky add .husky/commit-msg “yarn commitlint”

复制代码

此时已经完成配置了,现在团队里面任何成员的提交必须按照严格的规范进行了。

2.1.3 IDE环境约束

除此之外,我们还统一了VSCode编码环境,通过Setting Sync插件使用Public Gist进行同步。

有人会说小团队做这个有必要吗?我实践了几个月后,我个人还是觉得很有必要的,虽然刚开始配置起来很麻烦,也踩了不少坑,但实际去执行这套流程其实不需要花太多时间,至少可以在开发阶段避免除了代码逻辑以外的错误。

2.2 持续集成(CI)

持续集成是自动化流程中一个十分重要的部分,我们的前端应用在传统部署模式下需要自己打包然后上传服务器,这样很麻烦也很浪费时间。而持续集成就帮我们解决了这个问题,我们只要开发一个功能,它就能上传到线上的制品库,再配合持续部署(CD)就能够提高我们的效率,让我们专注开发。这一套流程需要有以下技术或平台支撑:

  • Docker(容器化技术)

  • Linux

  • Nginx:高性能Web服务器

  • Jenkins:持续构建平台

  • GitLab(本地部署的仓库)

  • Nexus3:用来部署Npm、Docker私有仓库,提供镜像制品库

由于篇幅原因,上述平台的搭建我不会给大家演示了。主要是给大家说一下这个CI流程:

  • 开发功能

  • Git提交到本地GitLab

  • GitLab触发Webhook

  • Jenkins开发执行脚本构建成Docker镜像

  • 上传Nexus私有仓库

image.png

现在有了制品仓库就需要持续部署(CI),但是我技术能力不够,只能借助Jenkins执行脚本来实现,但是原则上来说在Docker容器里面部署Docker容器这样的做法并不好,很容易出现一些问题,我想学习完Kubernetes后再来对这个流程进行优化。

搭建完流程后,我们只需要在项目中写好DockerfileNginx的配置文件就可以了,下面是我项目中的一个案例:

Dockerfile

# build stage

FROM node:lts-alpine as build-stage

WORKDIR /app

COPY . .

RUN yarn && yarn build

# production stage

FROM nginx:stable-alpine as production-stage

COPY --from=build-stage /app/dist/ /usr/share/nginx/html/

COPY --from=build-stage /app/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD [“nginx”, “-g”, “daemon off;”]

复制代码

nginx.conf

server {

listen 80;

server_name localhost;

#charset koi8-r;

access_log /var/log/nginx/host.access.log main;

error_log  /var/log/nginx/error.log  error;

location / {

root /usr/share/nginx/html;

try_files  u r i   uri  uri uri/ @router;

index index.html;

expires -1;

}

location @router {

rewrite ^.*$ /index.html last;

}

# SPA应用的history模式路由需要在前端配置500、400错误

}

复制代码

这里涉及到很多知识,篇幅有限,就不详细说了。

2.3 CSS样式管理

由于 Vite 的目标仅为现代浏览器,因此建议使用原生 CSS 变量和实现 CSSWG 草案的 PostCSS 插件(例如 postcss-nesting)来编写简单的、符合未来标准的 CSS。

官方其实是建议使用CSS变量来编写CSS,但是考虑到现阶段大家用得不是很熟练,所以还是采用了Sass,而且脚手架已经内置了对Sass的支持,我们只需要安装即可,不用像Webpack那样需要先安装Loader

yarn add sass -D

复制代码

这样我们在模板里面的只要给<style>标签加上lang就可以了:

复制代码

我是按照下面的文件组织来对CSS进行统一管理的:

src/assets/styles:

  • variables.scss(存放全局Sass变量)

  • mixins.scss(mixin)

  • common.scss(公共样式)

  • transition.scss(过渡动画样式)

  • index.scss(导出上面三个样式)

index.scss

@import ‘./variables.scss’;

@import ‘./mixins.scss’;

@import ‘./common.scss’;

@import ‘./transition.scss’;

复制代码

然后在main.js导入index.scss就可以使用了:

import ‘/src/assets/styles/index.scss’

复制代码

但是这里会有一个坑,那就是我在variables.scss中定义的变量、在mixins.scss定义的mixin全部失效了,而且控制台也报错:

image.png

如果不使用这个变量,我在Chrome是可以看到其他样式已经被编译好的,所以我采取了第二种方式导入index.scss。我们需要在vite的配置文件给css的预处理器进行配置,它的使用方式和Vue CLI中的配置差不多:

vite.config.js

export default defineConfig({

plugins: [vue()],

css: {

preprocessorOptions: {

scss: {

additionalData: @import "src/assets/styles/index.scss";

}

}

}

})

复制代码

这样就完成了CSS的管理啦,当然我这种比较简单,现在还有一种比较新的用法就是使用CSS Module,希望将来能用上吧。

Sass的编写指南,大家可以参考一下:Sass Guidelines

2.4 接口管理

2.4.1 基于Axios二次封装

基于Axios二次封装已经是一种常规操作了,下面来看看项目中我是如何对API进行管理的:

  • 抽象一个HttpRequest类,主要有请求拦截/取消、REST请求(GET、POST、PUT、Delete)、统一错误处理等功能

  • 实例化这个类,然后分模块编写API请求函数,URL这种常量单独放一个文件,接口请求参数和请求体由使用者决定,最后导出一个对象出口

  • 在组件引入对应的模块即可使用

Vue3.0中最推荐的使用方式是Composition API,组件中this不推荐使用,所以如果想全局引入,需要这么做:

import { createApp } from ‘vue’

import App from ‘./App.vue’

import http from ‘@/api’

const app = createApp(App)

app.config.globalProperties.http = http

app.mount(‘#app’)

复制代码

在组件中使用:

import { getCurrentInstance } from ‘vue’

const {

proxy: { http }

} = getCurrentInstance()

// demo…

async fetchData() {

await http.getData(…)

}

复制代码

而之前在Vue2中我们只需要在Vue.prototype上定义属性,然后在组件中使用this引入就可以了。但是全局引入会导致Vue原型很臃肿,每个组件的实例都会有这个属性,会造成一定的性能开销。

Vue3这种全局引入的做法我觉得也很麻烦,所以我的做法是在使用的组件中导入对应的API模块。

打个小广告:详细的Axios封装可以参考我的另外一篇文章在Vue项目中对Axios进行二次封装。

2.4.2 载入不同模式下全局变量

此外,我们也可以通过使用.env文件来载入不同环境下的全局变量,Vite中也使用了 dotenv来加载额外的环境变量,设置的全局变量必须以VITE_为前缀才可以正常被加载,使用方式如下:

.env.development

# 以下变量在development被载入

VITE_APP_BASE_API = ‘/api/v1’

复制代码

.env.production

# 以下变量在production被载入

VITE_APP_BASE_API = ‘http://192.168.12.116:8888/api/v1’

复制代码

全局变量使用方式:

import.meta.env.VITE_APP_BASE_API

复制代码

2.4.3 跨域问题

Vite是基于Node服务器开发的,所以它也提供了一些配置来实现本地代理,使用方式大家应该很熟悉,这里直接上一个例子:

vite.config.js

server: {

open: true,

proxy: {

‘/api/v1/chart’: {

target: ‘http://192.168.12.116:8887’,

changeOrigin: true

},

‘/api/v1’: {

target: ‘http://192.168.12.116:8888’,

changeOrigin: true,

rewrite: (path) => path.replace(/^/api/v1, ‘’)

}

}

}

复制代码

如果线上的服务器后端服务器不是同源部署也会有跨域问题,那么需要在Ngnix中配置反向代理,好在后端实现了CORS规范,那我们不需要操心线上的跨域问题了。当然解决跨域的方式有很多,下面要介绍的WebSocket就没有这个问题。

到这里接口管理相关问题也差不多说完了,项目接口数量并不是特别多,就20多个吧,所以并没有把全部接口全部交给Vuex接管,只有一少部分组件依赖的全局状态才放到Vuex中。

2.4.4 WebSocket+Vuex状态管理方案

大屏项目有将近20多个图表都是实时数据,包括设备健康度状态、设备运行指标等等,必须使用WebSocket。但是我们项目是SPA应用,每个组件都需要发消息,并且需要共享一个WebSocket实例,跨组件通信很麻烦,所以需要对这一块进行封装。

网上找了很多方案都没有解决我的问题,但是偶然却翻到了一个大佬的文章(websocket长连接和公共状态管理方案),他的文章里提到了基于WebSocket+Vuex实现“发布-订阅”模式对全局组件状态进行统一管理。我看完后受益匪浅,我这才知道如果把设计模式用于开发中能有如此“功效”。

我基于大佬的封装又优化了一些:

  • 对一些代码细节进行了修改和优化

  • 使用Class语法糖增强代码可读性

  • 增加了数据分发的功能

下面是一个简单的图:

image.png

组件通过emit方法来发送消息,消息里面标识了任务名,后端返回的数据里面也会返回这个任务名,这就形成了一个“管道”。Vuex通过订阅所有消息,然后根据任务名commit对应的mutation来完成状态变更,最后组件通过Vuex的store或者getter就能拿到数据了。

下面是一个完整的例子:

首先封装一个VueSocket类,它有发布、订阅、断线重连、心跳检测、错误调度等功能。组件只需要通过emit方法来发布消息,通过subscribe方法订阅服务端消息,然后通过Vuex的mutation来分发消息。

我们目前只需要关注emitsubscribe两个方法,当然handleData这个函数也很重要,主要是对来自不同任务的数据进行分发。

src/utils/VueSocket.js

class VueSocket {

/**

* VueSocket构造器

* @param {string} url socket服务器URL

* @param {function} commit Vuex中的commit函数,提交mutation触发全局状态变更

* @param {function} handleData 数据分发处理函数,根据订阅将数据分发给不同的任务处理

*/

constructor(url, commit, handleData = null) {

this.url = url // socket连接地址

this.commit = commit

this.distributeData = handleData

this.ws = null // 原生WebSocket对象

this.heartbeatTimer = null

this.errorResetTimer = null // 错误重连轮询器

this.disconnectSource = ‘’ // 断开来源: ‘close’ 由close事件触发断开, 'error’由error事件触发断开

this.reconnectNumber = 0 // 重连次数

this.errorDispatchOpen = true // 开启错误调度

this.closeSocket = false // 是否关闭socket

this.init()

}

/**

* 错误调度

* @param {string} type 断开来源=> ‘close’ | ‘error’

* @returns {function}

*/

static errorDispatch(type) {

return () => {

if (this.disconnectSource === ‘’ && this.errorDispatchOpen) {

this.disconnectSource = type

}

console.log([Disconnected] WebSocket disconnected from ${type} event)

// socket断开处理(排除手动断开的可能)

if (this.disconnectSource === type && !this.closeSocket) {

this.errorResetTimer && clearTimeout(this.errorResetTimer)

VueSocket.handleDisconnect()

}

}

}

/**

* 断开处理

* @returns {undefined}

*/

static handleDisconnect() {

// 重连超过4次宣布失败

if (this.reconnectNumber >= 4) {

this.reconnectNumber = 0

this.disconnectSource = ‘’

this.errorResetTimer = null

this.errorDispatchOpen = false

this.ws = null

console.log(‘[failed] WebSocket connect failed’)

return

}

// 重连尝试

this.errorResetTimer = setTimeout(() => {

this.init()

this.reconnectNumber++

console.log([socket reconnecting ${this.reconnectNumber} times...])

}, this.reconnectNumber * 1000)

}

/**

* 事件轮询器

* @param {function} event 事件

* @param {number|string} outerConditon 停止条件

* @param {number} time

* @param {function} callback

*/

static eventPoll(event, outerConditon, time, callback) {

let timer

let currentCondition

timer = clearInterval(() => {

if (currentCondition === outerConditon) {

clearInterval(timer)

callback && callback()

}

currentCondition = event()

}, time)

}

/**

* 初始化连接,开始订阅消息

* @param {function} callback

*/

init(callback) {

// 如果已经手动关闭socket,则不允许初始化

if (this.closeSocket) {

throw new Error(‘[Error] WebSocket has been closed.’)

}

// 清除心跳检测计时器

this.heartbeatTimer && clearTimeout(this.heartbeatTimer)

this.ws = new WebSocket(this.url)

this.ws.onopen = () => {

callback && callback()

this.reconnectNumber = 0

this.disconnectSource = ‘’

this.errorResetTimer = null

this.errorDispatchOpen = true

// 订阅消息

this.subscribe()

// 开启心跳侦测

this.heartbeatDetect()

console.log(‘[Open] Connected’)

}

this.ws.onclose = VueSocket.errorDispatch(‘close’)

this.ws.onerror = VueSocket.errorDispatch(‘error’)

}

/**

* 订阅器

*/

subscribe() {

this.ws.onmessage = (res) => {

if (res.data) {

const data = JSON.parse(res.data)

// 根据任务类型,分发数据

try {

this.distributeData && this.distributeData(data, this.commit)

} catch (e) {

console.log(e)

}

}

// 收到消息关闭上一个心跳定时器并启动新的定时器

this.heartbeatDetect()

}

}

/**

* 发布器(组件发消息的)

* @param {String} data

* @param {Function} callback

*/

emit(data, callback) {

const state = this.getSocketState()

if (state === this.ws.OPEN) {

this.ws.send(JSON.stringify(data))

callback && callback()

this.heartbeatDetect()

} else if (state === this.ws.CONNECTING) {

// 连接中轮询

VueSocket.eventPoll(state, this.ws.OPEN, 500, () => {

this.ws.send(JSON.stringify(data))

callback && callback()

this.heartbeatDetect()

})

} else {

this.init(() => {

this.emit(data, callback)

})

}

}

/**

* 心跳侦测

*/

heartbeatDetect() {

this.heartbeatTimer && clearTimeout(this.heartbeatTimer)

this.heartbeatTimer = setTimeout(() => {

const state = this.getSocketState()

if (state === WebSocket.OPEN || state === WebSocket.CONNECTING) {

// 发送心跳

this.ws.send(‘ping’)

} else {

this.init()

}

}, 50000)

}

/**

* 手动关闭连接

*/

close() {

this.heartbeatTimer && clearTimeout(this.heartbeatTimer)

this.errorResetTimer && clearTimeout(this.errorResetTimer)

this.closeSocket = true

this.ws.close()

}

/**

* 手动连接

*/

open() {

if (!this.closeSocket) {

throw new Error(‘[Error] WebSocket is connected’)

}

this.heartbeatTimer = null

this.reconnectNumber = 0

this.disconnectSource = 0

this.errorResetTimer = null

this.errorDispatchOpen = true

this.closeSocket = false

this.init()

}

/**

* 获取当前socket状态

*/

getSocketState() {

return this.ws.readyState

}

}

export default VueSocket

复制代码

在Vuex中定义初始化WebSocket连接的actionmutation

import { createStore, createLogger } from ‘vuex’

import VueSocket from ‘@/utils/VueSocket’

import { round } from ‘@/use/useToolFunction’

import {

handleData

} from ‘@/utils/handleSocketData’ // 分发任务的关键函数

import { WEBSOCKET } from ‘@/config’ // 导出一个常量

const debug = import.meta.env.MODE.startsWith(‘dev’)

const store = createStore({

state: {

ws: null // websorket实例

},

mutations: {

// 初始化socket连接

createSocket(state, { commit }) {

const baseURL = ` i m p o r t . m e t a . e n v . V I T E A P P S O C K E T ? p o r t N a m e = {import.meta.env.VITE_APP_SOCKET}?portName= import.meta.env.VITEAPPSOCKET?portName={

WEBSOCKET.TARGET

}`

state.ws = new VueSocket(baseURL, commit, handleData)

},

},

actions: {

// 创建实例

socketInit({ commit }) {

commit(‘createSocket’, { commit })

}

}

// debug console

// plugins: debug ? [createLogger()] : [],

})

export default store

复制代码

重点说一下这个handleData方法吧,VueSocket实例调用subscribe方法后就会订阅服务器所有的消息,而这个方法就是根据消息里面的任务名把消息送达各个组件。

比如现在有一个场景:有很多设备的子设备健康度需要实时展示:

const handleData = (data, commit) => {

// 当前任务

const [task] = Object.keys(data)

// 任务执行器

const taskRunner = {

healthRunner() {

const {

message: { dataContent }

} = data[task]

// 更新状态

dataContent &&

commit(‘updateHealthDegree’, {

prop: task,

healthDegree: dataContent[0].health

})

},

defaultRunner(mutation) {

const {

message: { dataContent }

} = data[task]

// 更新状态

dataContent && commit(mutation, dataContent)

}

}

// 任务映射委托

const taskMap = {

// 健康度

completeMachineHealthDegree() {

taskRunner.healthRunner()

},

pressureHealthDegree() {

taskRunner.healthRunner()

},

axletreeHealthDegree() {

taskRunner.healthRunner()

},

gearboxHealthDegree() {

taskRunner.healthRunner()

}

}

// 执行任务

if (task in taskMap) {

taskMaptask

}

}

复制代码

这个方法十分关键,所有的任务其实只是一个对象中的属性,然后映射的值是一个函数,只要判断这个任务在这个对象里面就会执行对应的函数。而最后任务的执行器其实就是调用了传进来的commit函数,触发mutation变更状态。我最开始是使用if/else或者switch/case来处理这个逻辑,但是随着任务越来越多(20多个),代码可读性也变得糟糕起来,所以想了这个办法处理。

下面是Vuex的定义,store/getters必须与任务名对应:

state: {

completeMachineHealthDegree: 1, // 整机健康度

pressureHealthDegree: 1,        // 液压系统健康度

axletreeHealthDegree: 1,        // 泵健康度

gearboxHealthDegree: 1          // 齿轮箱健康度

},

getters: {

pressureHealthDegree(state) {

return round(state.pressureHealthDegree, 2)

},

axletreeHealthDegree(state) {

return round(state.axletreeHealthDegree, 2)

},

gearboxHealthDegree(state) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

)

},

gearboxHealthDegree(state) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-1R7F48DY-1712328611965)]

[外链图片转存中…(img-ctahD94V-1712328611966)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-9cxs0G4a-1712328611966)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值