八股只问vue,代码题考js🫣「Momenta一面」
这是我目前见过给面试效率最高的公司,下午投的boss,没一会打电话问我五点钟能不能面试,后面选了七点钟。一面是个姐姐,声音很好听,人也很nice,辛苦她加班面我这个菜鸡了😂。下面是题目和笔者整理的答案,如有疏漏,烦请指正:
八股文
不知道宽高的块级元素如何垂直水平居中?
1.使用 flex 布局
.parent {
display: flex;
justify-content: center;
align-items: center;
}
2.使用 transform 属性
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
computed和watch的区别?
Vue中的computed
和watch
都是用于观察和响应Vue实例上的数据变化的。它们在使用场景和工作方式上有一些不同:
-
computed(计算属性) :
computed
是计算属性,主要用于当一个属性依赖于一个或多个其他属性时。当依赖的数据变化时,计算属性会重新计算。computed
支持缓存。只有当其依赖的属性值发生变化时,计算属性才会重新计算。如果依赖的数据没有变化,那么多次访问计算属性会直接返回之前的计算结果,而不需要重新进行计算。- 当多个属性影响一个属性时,或者一个数据需要经过复杂的计算时,建议使用
computed
。
-
watch(侦听器) :
watch
主要用于观察Vue实例上某个特定数据的变化,从而执行特定的操作。watch
不支持缓存,数据每次变化都会执行对应的函数。- 当一个值发生变化后,会引起一系列操作(例如,改变其他属性值),或者在数据变化时需要执行异步或开销较大的操作时,适合使用
watch
。
vue首屏优化?
编码阶段:
- 尽量减少 data 中的数据,因为 data 中的数据会增加 getter 和 setter 的数量,从而增加了对应的 watcher 的数量。
- 避免在同一个元素上同时使用 v-if 和 v-for,因为 v-for 的优先级比 v-if 高,同时使用它们会造成性能浪费。
- 如果需要给每个元素绑定事件,请使用事件代理而不是在每个元素上使用事件监听器。
- 对于需要频繁切换显示和隐藏的元素,请使用 v-show 替代 v-if。
- 使用唯一的 key 值来确保组件的唯一性。
- 使用路由懒加载和异步组件来减少首次加载的代码量。
- 使用防抖和节流来优化用户输入等频繁触发的操作。
- 按需导入第三方模块以减小打包体积。
- 对于长列表,只加载可视区域内的内容,同样的还有图片懒加载。
SEO 优化:
- 预渲染:通过预渲染技术生成静态 HTML 页面,以提高搜索引擎爬取效率。
- 服务端渲染 (SSR):将 Vue 应用程序在服务器端渲染成 HTML,并将其发送到客户端。这样可以加快首屏加载速度并提供更好的 SEO。
打包优化:
- 压缩代码:使用压缩工具(如 UglifyJS)来减小代码体积。
- Tree Shaking/Scope Hoisting:通过消除未使用的代码来减小打包体积。
- 使用 CDN 加载第三方模块:将第三方库放到 CDN 上以提高加载速度。
- 多线程打包:使用多线程构建工具(如 happypack)来加快打包速度。
- 抽离公共文件:将公共代码抽离成单独的文件以提高缓存效果。
- 优化 Source Map:在开发环境中使用合适的 Source Map 类型以提高调试效率。
用户体验:
- 骨架屏:在页面加载过程中显示骨架屏以提高用户体验。
- PWA(Progressive Web App):将 Web 应用程序转变为 PWA 以提供离线访问和更好的用户体验。
vuex如何实现持久化?
-
手动持久化:
- 将
state
中的数据存储到localStorage
中,以便在页面刷新后仍然可以访问。 - 通过监听
window
对象的beforeunload
事件,将state
中的数据存储到localStorage
中。
- 将
-
使用插件:
- 使用
vuex-persistedstate
插件来实现持久化。 vuex-persistedstate
插件会将store
中的数据映射到本地环境中,从而实现持久化。- 它支持多种存储引擎,如
localStorage
、sessionStorage
、cookie
等。
- 使用
-
原理:
- Vuex 的状态是响应式的,当状态发生变化时,所有依赖于它的组件都会重新渲染。
- Vuex 的状态是保存在内存中的,因此在页面刷新后,状态会被重置。
- 为了解决这个问题,我们需要将状态保存到本地存储中。这样,在页面刷新后,我们可以从本地存储中恢复状态。
自定义组件中的v-model?
v-model 是 Vue 中的一个指令,用于在自定义组件中实现双向数据绑定。它是 Vue 的语法糖,本质上是通过自定义标签的属性传递和接收数据。
// 父组件
<template>
<div>
<custom-component v-model="data"></custom-component>
<p>父组件中的数据:{{ data }}</p>
</div>
</template>
<script>
export default {
data() {
return {
data: ''
}
},
components: {
CustomComponent
}
}
</script>
// 子组件
<template>
<div>
<input :value="value" @input="$emit('update:value', $event.target.value)">
</div>
</template>
<script>
export default {
model: {
prop: 'value',
event: 'update:value'
},
props: {
value: String
}
}
</script>
vue获取event对象的方式?
方法一: 默认获取
在方法中不填写参数时,默认第一个参数就是 event 对象。
<template>
<div>
<button @click="onClick">点击</button>
</div>
</template>
<script>
export default {
methods: {
onClick(e) {
console.log(e);
}
}
}
</script>
方法二: 特殊变量 $event
<template>
<div>
<button @click="onClick('hello', $event)">点击</button>
</div>
</template>
<script>
export default {
methods: {
onClick(str, e) {
console.log(str, e);
}
}
}
</script>
vue父子组件的通信方式?ref的弊端?如何使依赖注入传递的数据保持响应式?
props
/$emit
provide
/inject
$attrs
/$listeners
ref
/$ref
$parent
/$children
vuex
/pinia
ref
的缺点主要是破坏了单向数据流,但它拿到的数据是响应式的;$parent
/ $children
不仅破坏了单向数据流,而且还不是响应式的。
使依赖注入传递的数据保持响应式的方法:
- 直接传入整个父组件的实例:vue2的
this
就是个响应式数据。如果我们直接在父元素中提供依赖this
,那么后代组件就能获得响应式。 - 以函数/对象式的方式传入:比方说
provide
传递的是父组件的name
这个变量,那么可以parentName: () => this.name
,或者parentName: {name: this.name}
. - Vue-observable,使用API来创建一个响应式数据然后传递,类似的Vue3可以通过ref/reactive创建的数据传递下去就是响应式的。
vue父子组件的生命周期执行顺序?
加载渲染过程:
- 父组件 beforeCreate
- 父组件 created
- 父组件 beforeMount
- 子组件 beforeCreate
- 子组件 created
- 子组件 beforeMount
- 子组件 mounted
- 父组件 mounted
更新过程:
- 父组件 beforeUpdate
- 子组件 beforeUpdate
- 子组件 updated
- 父组件 updated
销毁过程:
- 父组件 beforeDestroy
- 子组件 beforeDestroy
- 子组件 destroyed
- 父组件 destoryed
vue中的修饰符有哪些?有没有使用过sync修饰符?
vue实现登录的逻辑?
- 登录表单校验
- 人类行为验证(简历上项目用的开源的
SliderCaptcha
) - 调用
pinia
的登录action
进行登录,所有用户登录行为将被放入到pinia
中。 - 第一次登录时,前端调用后端的登录接口,发送用户名和密码,密码通过
md5
加密。 - 前端拿到 token 后,将其存储到
localStorage
和pinia
中,并跳转路由页面。 - 此后前端每次跳转路由时,就判断
localStorage
中有无 token,没有则跳转到登录页面,有则跳转到对应的路由页面。 - 前端每次调用后端接口时,都要在请求头中携带 token。
- 后端判断请求头中有无 token:
- header 中存在 token:验证 token 的合法性,成功则返回前端请求的数据;失败(如 token 过期)就返回 401 状态码(401 Unauthorized)
- header 中不存在 token:同样返回 401 状态码
- 如果有请求返回了 401 状态码,则清除 token 信息并跳转到登陆页面。
vue的菜单权限和按钮权限?
推荐一篇整理的很好的文章:
面试官:Vue要做权限管理该怎么做?控制到按钮级别的权限怎么做?
代码题
js实现版本号排序
// 示例
var versions = ['2.1.0.1', '0.402.1', '10.2.1', '5.1.2', '1.0.4.5']
输出: ['10.2.1', '5.1.2', '2.1.0.1', '1.0.4.5', '0.402.1']
const versions = ['2.1.0.1', '0.402.1', '10.2.1', '5.1.2', '1.0.4.5'];
versions.sort((a, b) => {
const partsA = a.split('.').map(Number);
const partsB = b.split('.').map(Number);
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const partA = partsA[i] || 0;
const partB = partsB[i] || 0;
if (partA !== partB) {
return partB - partA;
}
}
return 0;
});
使用js补全代码
function add(){
}
add(1)(1)(1)() //3
add(1)(2)(3)(4) //10
add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)() //10
这道题我不确定是不是题目中 add(1)(2)(3)(4)
这个地方最后少打了个括号?当时没意识到跟面试官提出疑惑,想了半天没想明白。
function add(num) {
let sum = num;
function addNext(nextNum) {
if (nextNum === undefined) {
return sum;
} else {
sum += nextNum;
return addNext;
}
}
return addNext;
}
console.log(add(1)(1)(1)()); // 输出 3
console.log(add(1)(2)(3)(4)); // 输出 10
console.log(add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)()); // 输出 10
转载自:https://juejin.cn/post/7282691800858853413