1.v-if 和 v-show 的区别?
都可以控制元素的显示和隐藏
- v-show 时控制元素的 display 值来让元素显示和隐藏;v-if 显示隐藏时把 DOM 元素整个添加和删除
- v-if 有一个局部编译/卸载的过程,切换这个过程中会适当的销毁和重建内部的事件监听和子组件;v-show 只是简单的 css 切换
- v-if 才是真正的条件渲染;v-show 从 false 变成 true 的时候不会触发组件的声明周期,v-if 会触发声明周期
- v-if 的切换效率比较低 v-show 的效率比较高
2.MVC 和 MVVM
MVC(Model-View-Controller)
- Model:负责管理应用程序的核心数据和业务逻辑。
- View:负责展示数据并与用户交互。
- Controller:作为 Model 和 View 之间的桥梁,处理用户输入并更新 Model,同时通知 View 更新。
特点:
- 单向通信:Controller 更新 Model 后,View 需要从 Model 中获取数据来刷新。
- 职责分离:Model、View 和 Controller 各自独立,便于维护。
- 适用于:传统 Web 应用和桌面应用。
MVVM(Model-View-ViewModel)
- Model:与 MVC 中的 Model 类似,负责管理数据。
- View:负责展示数据并与用户交互。
- ViewModel:作为 View 和 Model 之间的中介,负责处理 View 的展示逻辑和状态管理。
特点:
- 双向绑定:View 和 ViewModel 之间自动同步数据,View 变化时 ViewModel 更新,反之亦然。
- 职责分离:View 专注于展示,ViewModel 处理逻辑,Model 管理数据。
- 适用于:现代前端框架(如 Angular、Vue.js、React)和需要复杂交互的应用。
主要区别
- 数据绑定:MVVM 支持双向绑定,MVC 通常为单向。
- Controller vs ViewModel:MVC 的 Controller 处理用户输入并更新 Model,MVVM 的 ViewModel 负责 View 的展示逻辑和状态管理。
- 适用场景:MVC 适合传统 Web 应用,MVVM 适合需要复杂交互的现代前端应用。
3.v-for 中的 key 值的作用是什么?
key 属性是 DOM 元素的唯一标识 作用:
- 提高虚拟 DOM 的更新
- 若不设置 key,可能会触发一些 bug
- 为了触发过度效果
4.说一下你对 vue 生命周期的理解。
组件从创建到销毁的过程就是它的生命周期
创建
beforeCreat 在这个阶段属性和方法都不能使用
created 这里时实例创建完成之后,在这里完成了数据监测,可以使用数据,修改数据,不会触发 updated,也不会更新视图
挂载
- beforeMount 完成了模板的编译,虚拟 DOM 也完成创建,即将渲染,修改数据,不会触发 updated
- Mounted 把编译好的模板挂载到页面,这里可以发送异步请求也可以访问 DOM 节点
更新
- beforeUpdate 组件数据更新之前使用,数据是新的,页面上的数据时旧的,组件即将更新,准备渲染,可以改数据
- updated render 重新做了渲染,这时数据和页面都是新的,避免在此更新数据
销毁
- beforeDestroy 实例销毁前,在这里实例还可以用,可以清楚定时器等等
- destroyed 组件已经被销毁了,全部都销毁
使用了 keep-alive 时多出两个周期
- activited 组件激活时
- deactivited 组件被销毁时
5.在 created 和 mounted 去请求数据,有什么区别?
created:在渲染前调用,通常先初始化属性,然后做渲染
mounted:在模板渲染完成后,一般都是初始化页面后,在对元素节点进行操作 在这里请求数据可能会出现闪屏的问题,created 里不会 一般用 created 比较多
请求的数据对 DOM 有影响,那么使用 created
如果请求的数据对 DOM 无关,可以放在 mounted
6.vue 中的修饰符有哪些?
事件修饰符
- .stop 组织冒泡
- .prevent 组织默认行为
- .capture 内部元素触发的事件先在次处理
- .self 只有在 event.target 是当前元素时触发
- .once 事件只会触发一次
- .passive 立即触发默认行为
- .native 把当前元素作为原生标签看待
按键修饰符
- .keyup 键盘抬起
- .keydown 键盘按下
系统修饰符
- .ctrl
- .alt
- .meta
鼠标修饰符
- .left 鼠标左键
- .right 鼠标右键
- .middle 鼠标中键
表单修饰符
- .lazy 等输入完之后再显示
- .trim 删除内容前后的空格
- .number 输入是数字或转为数字
7.elementui 是怎么做表单验证的?
- 在表单中加 rules 属性,然后再 data 里写校验规则
- 内部添加规则
- 自定义函数校验
8.vue 如何进行组件通信?
父传子 props 父组件使用自定义属性,然后子组件使用 props 引用信息会注册在父组件的$refs 对象上
子传父 $emit 子组件绑定自定义事件,触发执行后,传给父组件,父组件需要用事件监听来接收参数
兄弟传 new 一个新的 vue 实例,用 on 和 emit 来对数据进行传输
vuex 传值
9.keep-alive 是什么?怎么使用?
Vue 的一个内置组件,包裹组件的时候,会缓存不活跃的组件实例,并不是销毁他们 作用:把组件切换的状态保存在内存里,防止重复渲染 DOM 节点,减少加载时间和性能消耗,提高用户体验
10.axios 是怎么做封装的?
下载 创建实例 接着封装请求响应拦截器 抛出 最后封装接口
11.vue 路由时怎么传参的
- params 传参
参数不会显示在 URL 中,适用于传递一些不需要暴露给用户或搜索引擎的参数
this.$router.push({name:'index',params:{id:item.id}})
this.$route.params.id
- 动态路由匹配
更灵活的参数传递,适用于路径中包含动态部分的场景
{
path: '/user/:id',
component: UserComponent
}
this.$router.push({ path: `/user/${userId}` });
- query 传参(可以解决页面刷新参数丢失的问题)
参数会显示在 URL 中,类似于 GET 请求的查询参数,适用于需要保留历史记录或分享链接的场景
this.$router.push({
name:'index',
query:{id:item.id}
})
12.vue 路由的 hash 模式和 history 模式有什么区别?
hash 的路由地址上有#号,history 模式没有
在做回车刷新的时候,hash 模式会加载对应页面,history 会报错 404
hash 模式支持低版本浏览器,history 不支持,因为是 H5 新增的 API
hash 不会重新加载页面,单页面应用必备
history 有历史记录,H5 新增了 pushState 和 replaceState()去修改历史记录,并不会立刻发送请求
history 需要后台配置nginx
13.路由拦截是怎么实现的?
路由拦截 axios 拦截 需要在路由配置中添加一个字段,它是用于判断路由是否需要拦截
{
name:'index',
path:'/index',
component:Index,
meta:{
requirtAuth:true
}
}
router.beforeEach((to,from,next) => {
if(to.meta.requirtAuth){
if( store.satte.token ){
next()
}else{
}
}
})
14.说一下 vue 的动态路由。
- 定义基础路由
- 定义动态路由或路由配置在数据库表中
- 添加路由导航守卫 再守卫中根据权限获取到指定的路由 并添加动态路由
15.如何解决刷新后二次加载路由?
window.location.reload()
matcher const router = createRouter() export function resetRouter(){ const newRouter = creatRouter() router.matcher = newRouter.matcher }
16.vuex 刷新数据会丢失吗?怎么解决?
vuex 肯定会重新获取数据,页面也会丢失数据
- 把数据直接保存在浏览器缓存里 vuex数据变化时实时更新缓存中的值 给vuex初始值
- 监听浏览器的刷新事件,在刷新前把数据保存到sessionstorage中,刷新后请求数据,请求到则用Vuex的数据,如果没有那就用sessionstorage中的数据
17.computed 和 watch 的区别?
computed 是计算属性,watch 是监听,监听的是 data 中数据的变化
computed 是支持缓存,依赖的属性值发生变化,计算属性才会重新计算,否则用缓存;watch 不支持缓存
computed 不支持异步,watch 是可以异步操作
computed 是第一次加载就监听,watch 是不监听
computed 函数中必须有 return watch 不用
18.vuex 在什么场景会去使用?属性有 些?
state 存储变量
getters state 的计算属性
mutations 提交更新数据的方法
actions 和 mutations 差不多,他是提交 mutations 来修改数据,可以包括异步操作
modules 模块化 vuex
使用场景: 用户的个人信息、购物车模块、订单模块、需要共享数据的业务都可以
19.vue 的双向数据绑定原理是什么?
vue2
通过数据劫持和发布订阅者模式来实现
- Object.defineProperty
使用 Object.defineProperty
来实现数据劫持。Object.defineProperty
可以拦截对象属性的读取和设置操作 2. 依赖收集
在组件渲染过程中,会触发数据的 get
操作,此时会收集依赖(即 Watcher)。每个响应式数据都有一个 dep
实例,用于管理所有依赖该数据的 Watcher。 3. 派发更新
当数据发生变化时,会触发 set
操作,此时会通知所有依赖该数据的 Watcher,这些 Watcher 会重新执行更新操作,从而更新视图
vue3
Proxy Vue 3 使用
Proxy
对象来实现数据劫持。Proxy
可以拦截对象的所有操作,包括属性的添加、删除、读取和设置等依赖收集
在组件渲染过程中,会触发数据的 get
操作,此时会收集依赖(即 Effect)。每个响应式数据都有一个 ReactiveEffect
实例,用于管理所有依赖该数据的 Effect。
- 派发更新
当数据发生变化时,会触发 set
操作,此时会通知所有依赖该数据的 Effect,这些 Effect 会重新执行更新操作,从而更新视图。
特性 | Vue 2 | Vue 3 |
---|---|---|
数据劫持 | Object.defineProperty | Proxy |
支持的操作 | 仅支持对象属性的读取和设置 | 支持所有操作(包括数组方法) |
动态属性 | 需要使用 Vue.set 或 Vue.delete | 自动检测属性的添加或删除 |
性能 | 对于大量数据或深层嵌套的对象性能较差 | 提供更好的性能 |
兼容性 | 支持所有现代浏览器,包括 IE | 不支持 IE,但提供兼容性支持 |
20.了解 diff 算法和虚拟 DOM 吗?
虚拟 DOM,描述元素和元素之间的关系,创建一个 JS 对象 如果组件内有响应的数据,数据发生改变的时候,render 函数会生成一个新的虚拟 DOM,这个新的虚拟 DOM 会和旧的虚拟 DOM 进行比对,找到需要修改的虚拟 DOM 内容,然后去对应的真实 DOM 中修改 diff 算法就是虚拟 DOM 的比对时用的,返回一个 patch 对象,这个对象的作用就是存储两个节点不同的地方,最后用 patch 里记录的信息进行更新真实 DOM
步骤:
- JS 对象表示真实的 DOM 结构,要生成一个虚拟 DOM,再用虚拟 DOM 构建一个真实 DOM 树,渲染到页面
- 状态改变生成新的虚拟 DOM,跟就得虚拟 DOM 进行比对,这个比对的过程就是 DIFF 算法,利用 patch 记录差异
- 把记录的差异用在第一个虚拟 DOM 生成的真实 DOM 上,视图就更新了。
21.vue 和 jquery 的区别是什么?
原理不同
vue 就是数据绑定;jq 是先获取 dom 再处理
着重点不同
vue 是数据驱动,jq 是着重于页面
操作不同
未来发展不同
22.vuex 的响应式处理。
vuex 是 vue 的状态管理工具 vue 中可以直接触发 methods 中的方法,vuex 是不可以的。未来处理异步,当触发事件的时候,会通过 dispatch 来访问 actions 中的方法,actions 中的 commit 会触发 mutations 中的方法从而修改 state 里的值,通过 getter 把数据更新到视图 Vue.use(vuex),调用 install 方法,通过 applyMixin(vue)在任意组件内执行 this.$store 就可以访问到 store 对象。 vuex 的 state 是响应式的,借助的就是 vue 的 data,把 state 存到 vue 实例组件的 data 中
23.vue 中遍历全局的方法有哪些?
forEach
map
filter
findindex
24.vue2 data为什么是函数
- 根的实例对象 data 可以是对象也可以是函数 (根实例是单例), 不会产生数据污染。
- 组件实例对象 data 必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象,有效规避多实例之间状态污染问题
25.如何封装一个组件?
使用 Vue.extend()创建一个组件
使用 Vue.components()方法注册组件
如果子组件需要数据,可以在 props 中接收定义
子组件修改好数据,要把数据传递给父组件,可以用 emit()方法
原则: 把功能拆开 尽量让组件原子化,一个组件做一件事情 容器组件管数据,展示组件管视图
26.封装一个可复用的组件,需要满足什么条件?
低耦合,组件之间的依赖越小越好
最好从父级传入信息,不要在公共组件中请求数据
传入的数据要进行校验
处理事件的方法写在父组件中
27.vue 的过滤器怎么使用?
vue 的特性,用来对文本进行格式化处理 使用它的两个地方,一个是插值表达式,一个是 v-bind 使用
<div>{{33 | add}}</div>
全局过滤器
Vue.filter('add',function(v){
return v < 10 ? '0' + v : v
})
组件过滤器
和 methods 同级
filter:{
add:function(v){
return v < 10 ? '0' + v : v
}
}
28.vue 中如何做强制刷新?
localtion.reload()
this.$router.go(0)
29.vue3 和 vue2 有哪些区别?
- 双向数据绑定的原理不同
- 是否支持碎片
- API 不同
- 定义数据变量方法不同
- 生命周期的不同
- 传值不同
- 指令和插槽不同
- main.js 不同
30.vue 的性能优化怎么做?
- 编码优化 不要把所有数据都放在 data 中 v-for 时给每个元素绑定事件用事件代理 keep-alive 缓存组件 尽可能拆分组件,提高复用性、维护性 key 值要保证唯一 合理使用路由懒加载,异步组件 数据持久化存储的使用尽量用防抖、节流优化
- 加载优化 按需加载 内容懒加载 图片懒加载
- 用户体验 骨架屏
- SEO 优化 预渲染 服务端渲染 ssr
- 打包优化 CDN 形式加载第三方模块 多线程打包 抽离公共文件
- 缓存和压缩 客户端缓存、服务端缓存 服务端 Gzip 压缩
31.首屏优化该如何去做?
- 使用路由懒加载
- 非首屏组件使用异步组件
- 首屏不中要的组件延迟加载
- 静态资源放在 CDN 上
- 减少首屏上 JS、CSS 等资源文件的大小
- 使用服务端渲染
- 简历减少 DOM 的数量和层级
- 使用精灵图请求
- 做一些 loading
- 开启 Gzip 压缩
- 图片懒加载
32.vue3 的性能为什么比 vue2 好?
- diff 算法的优化
- 静态提升
- 事件侦听缓存
33.vue3 为什么使用 proxy?
- proxy 可以代理整个对象,defineproperty 只代理对象上的某个属性
- proxy 对代理对象的监听更加丰富
- proxy 代理对象会生成新的对象,不会修改被代理对象本身
- proxy 补兼容 ie 浏览器
34.说一下你对组件的理解。
- 可以重复使用的 vue 实例,独一无二的组件名称
- 可以抽离单独的公共模块
- 提高代码的复用率
35.你是如何规划项目文件的?
public 图标、index.html、img src api assets components 按分类再次划分子目录 plugins router static styles utils