一:MVC 和 MVVM 区别
-
MVC模式:
- Model:处理数据和业务逻辑,不直接处理视图。
- View:负责界面展示,不包含业务逻辑。
- Controller:接收用户输入,协调Model和View的交互,需手动更新视图。
-
MVVM模式:
- Model:与MVC相同,处理数据和业务逻辑。
- View:仅展示数据,通过数据绑定与ViewModel连接。
- ViewModel:作为桥梁,封装视图逻辑,通过双向数据绑定自动同步Model和View的变化。 优缺点对比
- MVVM优势:代码结构清晰,减少手动同步代码;劣势是数据绑定机制可能增加初学难度,且需框架支持。
- MVC优势:架构成熟,适合小型项目;劣势是Controller易膨胀,维护成本随复杂度上升。 选择时需根据项目需求:MVVM适合复杂前端应用,MVC在传统场景中仍具价值。
二. 为什么 data 是一个函数
组件中data写成一个函数,
①:数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
②:单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果.
三. Vue 组件通讯有哪几种方式
①. 父组件向子组件传数据通prop传递 子组件传递数据给父组件通过 $emit 触发事件做到.
②. children 获取当前组件的父组件和当前组件的子组件.
③. listeners A->B->C。Vue 2.4 开始提供 listeners 解决这个问题.
④. 父组件通过provide提供变量,子组件通过inject注入变量(官方不推荐实际业务中使用,写组件库时常用).
⑤. $refs 获取组件实例.
⑥. eventBus 兄弟组件数据传递 这种情况下可以使用事件总线方式.
⑦. vuex 状态管理.
四. v-if 和 v-show 的区别
v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。
v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)。
使用场景
v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景
v-show 适用于需要非常频繁切换条件的场景
五. 怎样理解 Vue 的单向数据流
①:数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。 ②:如果要改变父组件中的值,可以用$emit 通知父组件去修改。
六. v-if 与 v-for 为什么不建议一起使用
v-for 和 v-if 不要在同一个标签中使用,因为解析时先解析 v-for 再解析 v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。
七. computed 和 watch 的区别和运用的场景
①:computed是计算属性,依赖其他属性计算值,并且computed值有缓存,只有当计算值变化才会返回内容,它可以设置 getter 和 setter。 ②:watch监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
区别: 计算属性一般用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来; 而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑
八.虚拟 DOM 是什么? 有什么优缺点?
虚拟DOM是前端框架(如React、Vue)中用于优化UI渲染的一种技术,它是一个轻量级的JavaScript对象,用以描述真实DOM树的结构、属性和子元素,作为真实DOM的内存中抽象表示。
虚拟DOM的核心优势在于性能优化、开发体验提升和跨平台能力。 具体来说:
- 性能优化:通过在内存中操作虚拟DOM树并使用diff算法计算最小差异,减少对真实DOM的直接操作,从而降低重排和重绘频率,提升渲染效率。
- 开发体验提升:采用声明式编程范式,将UI逻辑与渲染过程分离,使代码更清晰、可维护性更高,并支持组件化开发,增强代码复用性。
- 跨平台能力:作为与平台无关的抽象层,虚拟DOM可适配Web、移动端(如React Native)和服务器等环境,实现代码复用。
然而,虚拟DOM也存在一些缺点。 主要包括:
- 额外内存开销:虚拟DOM树需在内存中维护,会增加应用的内存占用。
- 对简单场景的适用性有限:在静态内容或首屏加载敏感的场景中,虚拟DOM的计算开销可能超过其收益。
- 学习曲线与集成挑战:开发者需理解其工作原理(如Key属性的使用),且与某些依赖直接DOM操作的库(如D3.js)集成时可能存在兼容性问题。
九.#### v-model的实现原理?
v-model 的实现原理是依赖于 Vue 的v-bind指令 和 @input 特性:v-model 实际上是一个语法糖,在 ⼀个组件上使⽤ v-model ,默认会为组件绑定名为 value 的 prop 和名为 input 的事件。
js:中input事件+this.$emit实现数据双向绑定.
十.v-for 为什么要加 key?
①:核心作用是优化虚拟DOM更新和提升性能。 Vue使用diff算法比较新旧虚拟DOM树,key作为节点的唯一标识,帮助算法精确识别元素的增删改,避免就地复用策略导致的不必要的DOM操作。例如,当列表顺序变化时,key能确保DOM元素正确复用,减少重渲染开销。
②:key还能保持组件状态和确保正确渲染。 对于包含临时状态(如表单输入、动画)的组件,key确保状态与特定数据项绑定,防止更新时状态错乱。同时,key避免渲染错误,如列表顺序错乱或元素错位。
③:key应使用稳定且唯一的标识符,避免使用数组索引。 推荐使用数据项的唯一ID等稳定值作为key,因为索引在列表变化时可能失效,导致不必要的DOM重新创建。
④:官方强调key的重要性。 在Vue 2.x中,使用v-for渲染动态子节点或组件时,若未绑定key会触发警告。
十一. 谈一下对 vuex 的个人理解
vuex 是专门为 vue 提供的全局状态管理系统,用于多个组件中数据共享、数据缓存等(无法持久化、内部核心原理是通过创造一个全局实例 new Vue)
主要包括以下几个模块:
- State:里面存放的是响应式的数据。
- Getter:State进行计算操作,在多个组件间复用。
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module:Vuex允许我们将store分隔成模块。
十二. Vuex 页面刷新数据丢失怎么解决
需要做 vuex 数据持久化 一般使用本地存储方案来保存数据 可以自己设计存储方案 也可以使用第三方插件
推荐使用 vuex-persist 插件,它就是为Vuex持久化存储而生的一个插件。不需要手动存取storage ,而是直接将状态保存至cookie 或者 localStorage 中
十三. 使用过 Vue SSR 吗?说说 SSR
SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。
优点: SSR 有着更好的 SEO、并且首屏加载速度更快
缺点: 开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。
服务器会有更大的负载需求
十四. 你都做过哪些 Vue 的性能优化
编码阶段
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连⽤
- 如果需要使⽤v-for给每项元素绑定事件时使⽤事件代理
- SPA ⻚⾯采⽤keep-alive缓存组件
- 在更多的情况下,使⽤v-if替代v-show
- key保证唯⼀
- 使⽤路由懒加载、异步组件
- 防抖、节流
- 第三⽅模块按需导⼊
- ⻓列表滚动到可视区域动态加载
- 图⽚懒加载
SEO优化
- 预渲染
- 服务端渲染SSR
打包优化
- 压缩代码
- Tree Shaking/Scope Hoisting
- 使⽤cdn加载第三⽅模块
- 多线程打包happypack
- splitChunks抽离公共⽂件
- sourceMap优化
⽤户体验
- 骨架屏
- PWA
还可以使⽤缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
十五. 能说下 vue-router 中常用的路由模式实现原理吗?
hash 模式
①: location.hash 的值实际就是 URL 中#后面的东西 它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
②:可以为 hash 的改变添加监听事件
每一次改变hash(window.location.hash)都会在浏览器的访问历史中增加一个记录.
利用hash的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了
特点:兼容性好但是不美观.
history 模式
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。
这两个方法应用于浏览器的历史记录站,在当前已有的back、forward、go 基础之上,提供了对历史记录修改的功能。这两个方法有个共同特点:当调用他们修改浏览器历史记录栈后,虽然当前URL改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。
特点:虽然美观,但是刷新会出现 404 需要后端进行配置
十六.vue生命周期
在VUE中每个组价都是独立的,每个组件都有属于自己的生命周期,从一个组件的创建、数据初始化、挂载、更新、销毁、这就是一个组件所谓的生命周期。
生命周期的8个钩子函数分别为
实例创建之前:beforeCreate(){},把传入的data属性的内容,赋给vue对象。即:把形参中data的属性赋给vue对象,前后分别的钩子函数是:beforeCreate、created
实例创建后:created(){}
初始化之前:beforeMount(),把vue对象中data渲染到dom对象上,前后分别的钩子函数是:beforeMount、mounted
实例初始化:mounted(){}
数据同步前:beforeUpdata(){},当数据发生变化时,会触发组件的更新。
数据同步后:updata(){}
实例销毁前:beforeDestroy(){}
实例销毁后:destoryed(){}
如果组件在缓存的话,那么,组件切换时,会调用的钩子函数是: activated 和 deactivated
十七. 数组去重 ①.利用ES6 Set 去重(ES6中最常用,代码最少)
let arr = [4, 1, 3, 3, 2, '2'];
let uniqueArr = [...new Set(arr)];
console.log(uniqueArr);
十八. 深拷贝和浅拷贝
浅拷贝:只是增加了一个指针指向已存在的内存地址
深拷贝:是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
十九. 数组和字符串常见方法。
数组方法:
join(): 把数组放入字符串,默认逗号隔开,arr数组不变。
concat():连接数组,返回新的数组,arr数组不变。
slice(): 选取数组,返回选取的数组,arr数组不变。(第一个参数从哪里开始,第二个是截取到哪个(返回不包括),如果只有第一个参数0,都取。)
push(): 数组末尾增加元素,返回数组长度,arr为增加后的数组。
unshift()*数组开头增加元素,返回数组长度,arr为增加后的数组。
pop(): 数组末尾删除一个,返回删除的元素,arr为删除后的数组。
shift(): 数组开头删除一个,返回删除的元素,arr为删除后的数组。
splice(): 增、删、改都可以,返回增删改的元素,arr为增删改的元素。(第一个参数从哪里开始,第二个参数是删除的个数,后面的参数是增加的元素)
字符串的方法:(字符串有恒定性,修改字符串不会修改本身)
charAt(): 传入一个数组,返回选中位置的字符串,string字符串不变。
concat(): 传入增加的字符串,返回新的字符串,string字符串不变。
split(): 字符串分割为数组,返回新的数组,string字符串不变。
indexOf():字符串首次出现的位置,返回位置,没有返回-1, string字符串不变。(第一个参数是要检索的字符,第二个参数从哪里开始检索)
lastIndexOf(): 从后向前检索。但是下标还是从左往右算。
replace(): replace(‘b’, ‘B’),替换。
slice(): 跟数组方法类似。截取。
toLowerCase(): 字符串转为小写。
toUpperCase(): 字符串转为大写。