一、Vue篇
1、route和router区别?
$router用来操作路由,$route用来获取路由信息
$router是VueRouter的一个实例对象,他包含了所有的路由,包括路由的跳转方法,钩子函数,子对象(例如history)
$route是一个路由信息对象,每一个路由都会有一个$route对象,是一个局部的对象。
2、vue自定义指令?
Vue中的核心内置指令不能够满足我们的需求时,我们定制自定义的指令用来满足开发的需求。
1、全局自定义指令
2、私有自定义指令(组件内定义指令)
主要目的是在Vue的模板中直接操作DOM。
3、vue优化Vue项目的性能?
1、代码分割:使用Webpack的代码分割功能,按需加载组件
2、懒加载:对路由组件进行懒加载,减少初始加载时间
3、虚拟滚动:使用虚拟滚动技术,仅渲染可见区域的DOM节点(虚拟滚动其核心原理是只渲染用户当前可见区域的数据,而不是一次性渲染整个列表或数据集。这样做可以显著提高渲染效率,尤其是在数据量巨大时,能够避免性能下降和页面卡顿的问题)
4、减少重绘重排:合理使用CSS,避免频繁的DOM操作。(如:减少DOM节点,使用documentFragment,
使用CSS的transform
和opacity
属性等等)
5、使用keep-alive:对频繁切换的组件使用keep-alive,缓存组件状态
4、vue模板如何编译?
1、解析
将模板字符串解析成抽象语法树(AST)。这一步是通过一个解析器完成的,它会识别模板中的指令、插值、模板标签等,并构建出一个AST。
优化
2、优化
对AST进行静态分析和优化。例如,标记所有静态节点,以便在虚拟DOM的diff算法中可以快速跳过它们,减少不必要的DOM操作。
代码生成
3、代码生成
将优化后的AST转换成可执行的JavaScript代码。这一步会生成一个render函数,这个函数能够生成虚拟DOM树。
5、Vue2响应式原理?
Vue2的响应式原理主要通过Object.defineProperty方法来实现。Vue2使用Object.defineProperty对组件的data对象的属性进行劫持(或称为拦截)。当读取data中的属性时触发get,当修改data中的属性时触发set,从而实现对数据的监控和响应式更新。
6、Vue3响应式原理?
Vue3的响应式原理主要基于JavaScript的Proxy对象,通过数据代理和动态劫持来实现数据的响应式更新。在Vue3中,响应式系统通过Proxy对象来监视数据的变化,并在数据变化时自动更新视图,无需手动操作DOM。
7、刷新浏览器后,Vuex的数据是否存在?如何解决?
刷新浏览器后,Vuex的数据会丢失,因为Vuex的状态是保存在运行内存中的,当页面刷新时,内存中的数据会被清除。页面刷新会重载vue实例,导致store里的数据丢失。
解决方法1:使用vuex-along
解决方法2:localStorage 或者 sessionStroage
8、vue双向数据绑定原理?
vue的双向绑定,即数据与视图的响应式设计。具体表现为:View 的改变能实时让Model发生变化,而 Model 的变化也能实时更新 View。
初始化:
Vue 在初始化组件时,会遍历数据对象,使用 Object.defineProperty 将每个属性转换为 getter/setter。
依赖收集:
当组件渲染时,Vue 会追踪哪些数据被用到了,即收集依赖。
依赖变更通知:
当数据变化时,setter 会被触发,Vue 会通知所有依赖于这个数据的组件。
视图更新:
组件收到通知后,会重新渲染,生成新的虚拟DOM,并与旧的虚拟DOM进行比较,更新实际的DOM。
事件处理:
对于表单输入,Vue 会监听 input 事件,并在事件处理函数中更新数据,实现双向绑定。
9、computed和watch区别?
1、computed是计算属性;watch是监听,监听data中的数据变化。
2、computed支持缓存,当其依赖的属性值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值;watch不支持缓存,当对应属性发生变化的时候,响应执行。
3、computed不支持异步,有异步操作时无法监听数据变化;watch支持异步操作。
4、computed第一次加载时就监听;watch默认第一次加载时不监听。
10、vue中mixin?
Mixin是面向对象程序设计语言中的类,提供了方法的实现。
本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等。
11、Vue中给对象添加新属性时,界面不刷新怎么办?
vue2是用过Object.defineProperty实现数据响应式, 当我们访问foo属性或者设置foo值的时候都能够触发setter与getter。
但是我们为obj添加新属性的时候,却无法触发事件属性的拦截
原因是一开始obj的foo属性被设成了响应式数据,而bar是后面新增的属性,并没有通过Object.defineProperty设置成响应式数据。
const obj = {}
Object.defineProperty(obj, 'foo', {
get() {
console.log(`get foo:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
console.log(`set foo:${newVal}`);
val = newVal
}
}
})
}
解决方法:
Object.assign()
直接使用Object.assign()添加到对象的新属性不会触发更新。应创建一个新的对象,合并原对象和混入对象的属性。
12、vue组件通讯方式?
1、通过props传递:父组件通过props向子组件传递数据。子组件通过props接收父组件传递的数据。这种方式适用于父子组件之间的通信。
2、通过emit触发自定义事件:子组件通过emit触发一个事件,父组件监听这个事件来接收数据。这种方式适用于子组件向父组件传递数据。
3、使用ref:父组件可以通过$refs直接访问子组件的实例,从而调用子组件的方法或访问其数据。这种方式适用于父子组件之间的直接交互。
4、EventBus(全局事件总线):通过创建一个事件总线,实现非父子关系的组件之间的通信。这种方式适用于兄弟组件或跨多级的组件通信。
5、Vuex:Vuex是一个状态管理库,适用于大型应用中组件间的状态管理。通过改变状态来通知其他组件更新。
6、provide/inject:provide和inject可以实现跨级组件的数据传递。provide在祖先组件中提供数据,inject在后代组件中注入数据。
7、attrs/listeners:attrs用于父传子,子传孙的情况;listeners用于孙传子的反向通信。这种方式适用于祖先与后代组件之间的数据传递。
8、插槽(Slots):插槽用于父组件向子组件插入内容,也可以用于子组件向父组件传递数据。
9、路由传参:通过路由的params和query参数进行组件间的数据传递。这种方式适用于通过路由进行的数据传递。
二、HTML、CSS篇
1、行内元素有哪些?块级元素有哪些?空元素有那些?行内元素和块级元素有什么区别?
行内元素:
<span>、<a>、<img>、<br>、<strong> 、<b>、<em> 、<i>、<input>、<label>、<select> 、 <option>
块级元素:
<div>、<p>、<hr> 、<h1> 到 <h6> 、<ul>、<ol> 、<li> 、<table>、<thead>、<tbody>、<tfoot>、<tr>、<th> 、<td>
空元素:
<br>、<img>、<input>、<meta>、<link>、<hr>
区别:
行内元素不可以设置宽高,不独占一行
块级元素可以设置宽高,独占一行
2、简述一下你对HTML语义化的理解?
语义化是指 根据内容的结构(内容语义化),选择合适的标签(代码语义化)
语义化的好处:
1、语义化使代码结构清晰,语义明确。更具可读性,便于个人和团队开发和维护
2、屏幕阅读器和其他辅助技术可以更好地传达语义化的 HTML,从而帮助视障用户等残障人士更好地访问网页内容。
3、语义化有利于SEO,有助于提高网站的搜索引擎排名。
3、标签上 title 与 alt 属性的区别是什么?
alt 是给搜索引擎识别,在图像无法显示时的替代文本;
title 是关于元素的注释信息,主要是给用户解读。当鼠标放到文字或是图片上时有 title 文字显示。
4、什么是优雅降级渐进增强?
是Web设计和开发中常用的两种策略,
渐进增强:从最基本的功能开始构建应用,然后逐步添加更高级的功能和效果,以提供更好的用户体验。这种策略首先确保所有用户都能访问基本的内容和功能,然后为使用更高级浏览器或设备的用户提供增强的体验。
优雅降级:是从完整的功能开始构建应用,然后针对低版本浏览器进行兼容,确保即使在旧版浏览器或设备中也能提供基本的可用性。这种策略意味着在高级浏览器中实现丰富的功能,而在低版本环境中逐步减少功能,以确保核心内容和功能始终可用。