web面试题必问的题
1. vue双向数据绑定原理
vue是采用数据劫持结合发布-订阅
的方式,通过object.defineProperty()
来劫持各个属性的setter
,getter
,在数据发生变动时发布消息给订阅者,触发相应的监听回调来渲染视图
第一步:
需要observer
的数据对象进行递归遍历
,包括子属性对象的属性,都加上setter
,getter
,这样的话,给这个对象的某个值赋值
,就会触发setter
,那么就能监听到数据变化简单来说就是实现一个数据监听器Observer,它能够对数据对象的所以属性进行监听,如果有变动就可以拿到最新的值并通知订阅者
第二步:compile
解析模块指令,讲模块中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图简单来说就是实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,替换数据,绑定更新函数
第三步:Watcher
订阅者时Observer
和Compile
之间的通讯桥梁,主要做的事情是:
1.在自身实例化时往属性订阅器(dep
)里面添加自己
2.自身必须有一个update()
方法
3.待属性变动dep.notice()
通知时,能调用自身的update()
方法,并触发Compile
中的绑定回调简单来说就是实现一个Watcher,作为Observer和Compile的桥梁,能够收到每个属性变动的通知,绑定相应的回调函数,从而更新视图
第四步:MVVM
作为数据绑定的入口,整合Observer,Compile和Watcher三者
,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭建起Observer和Compile之间的通信桥梁,达到数据变化->视图更新; 视图交互变化->数据model变更的双向绑定效果
MVVM就是实现Vue双向数据绑定的根本
,MVVM本质上是MVC的改进版,即模型-视图-视图模型
,【模型】
指的是后端传递的数据。【视图】
指的是所看到的页面。【视图模型】
MVVM的核心,他是连接view和model的桥梁
。它有两个方向: 一个是将【模型】转换成【视图】,即后端传递的数据转换成所看到的页面
:实现方式是:数据绑定。第二个是【视图】转化成【模型】,即将所看到的页面转换成后端的数据
:实现方式是:DOM事件监听。这两个方向都实现的话,
我们称之为数据的双向绑定
2.vue虚拟dom,diff算法
虚拟DOM就是为了解决游览器性能问题
而被设计出来的。
就是用对象来模拟dom元素和嵌套关系,指的就是用js对象的形式
,来模拟页面上的DOM嵌套关系
目的:实现页面元素的高效更新,避免大量无谓的计算(若一次操作中有10次更新DOM的动作,虚拟DOM不会立即去操作DOM,而是将10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一个姓attch到DOM树上,再进行后续操作
)
作用:用来比较两次DOM结构
web界面由DOM树(树的意思就是数据结构
)来搭建,当其中一部分发生变化时,其实就时对应某个DOM节点发生了变化
diff算法是作为DOM的加速器
,改进优化了页面渲染的基础和性能保障
用js对象表示dom树结构,用这个树建立一个真正的dom树,插入到文档中,状态更新
,重新构造一棵新树,两树比较差异,把差异应用到真的dom树上,更新视图
3. 组件 通讯
1.父传子父组件是通过props属性给子组件通信的
父组件代码:
<template>
<div>
<h2>{{msg}}</h2>
<Son :faMsg="msg"></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
name:"HelloWorld",
data(){
return{
msg:"父组件"
}
},
components:{Son}
}
</script>
子组件代码:
<template>
<div>
<h2>{{sonMsg}}</h2>
<p>子组件接收到的内容是:{{faMsg}}</p>
</div>
</template>
<script>
export default {
name:"Son",
data(){
return{
sonMsg:"子组件"
}
},
props:['faMsg'], //接收faMsg值
//还可以这样,上面的不是很严谨
props:{
faMsg:{
type:String,
default:"123"
}
}
}
</script>
在父组件中给子组件标签上绑定一个属性, 属性上挂载需要传递的值
在子组件通过props:[“自定义属性名”]来接收数据
子传父:(1) 在父组件中给子组件标签绑定一个自定义事件,给这个事件挂载需要调用的方法
(2) 在子组件的方法通过this.$emit(‘自定义事件名’)来调用这个方法
父组件代码:
<template>
<div>
<h2>{{ msg }}</h2>
<p>父组件接手到的内容:{{ username }}</p>
<son psMsg="我是你爸爸" @transfer="getUser"></son>
<!-- 监听子组件触发的transfer事件,然后调用getUser方法 -->
</div>
</template>
<script>
import son from './Son'
export default {
name: 'HelloWorld',
data () {
return {
msg: '父组件',
username:'',
}
},
components:{son},
methods:{
getUser(msg){
this.username= msg
}
}
}
</script>
子组件代码:
<template>
<div class="son">
<p>{{ sonMsg }}</p>
<p>子组件接收到内容:{{ psMsg }}</p>
<!--<input type="text" v-model="user" @change="setUser">-->
<button @click="setUser">传值</button>
</div>
</template>
<script>
export default {
name: "son",
data(){
return {
sonMsg:'子组件',
user:'子传父的内容'
}
},
props:['psMsg'],
methods:{
setUser:function(){
this.$emit('transfer',this.user)//触发transfer方法,this.user 为向父组件传递的数据
}
}
}
</script>
兄弟通信: 比如说vuex 就可以说是一个兄弟通信
4. vuex
首先我们要知道Vuex是一个专为vue.js应用程序开发的状态管理模式,它由五部分组成:
分别是:state,actions,mutations,getters,modules
vuex的五部分分别是:
- state:存储状态
- actions:可以包含异步操作
- getters:类似vue组件中的计算属性,会对state数据进行计算(会被缓存)
- mutations:唯一可以对state数据修改的场所
- modules:模块化管理仓库,每个模块都拥有自己的 state,actions,mutations,getters,modules
Vuex一般用来存储在vue.js中大量出现的数据,比如说token,我们就可以把token存放在Vuex中,当然购物车也是要用到Vuex的.
数据持久化
问题:存储在vuex中的状态,刷新页面会丢失。
为了解决刷新页面数据丢失,才有了数据持久化。
最简单的做法就是利用插件 vuex-persistedState
1.安装cnpm i vuex-persistedState -S
备注:-S 是 --save的简写,意思是:把插件安装到dependencies(生成环境依赖)中
-D 是 --save-dev的简写,意思是:把插件安装到devDependencies(开发环境依赖)中
2.使用
import createPersistedState from 'vuex-persistedstate'
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
plugins: [createPersistedState({
storage: sessionStorage,
key: "token"
})]//会自动保存创建的状态。刷新还在
})
参数:storage:存储方式。(sessionStorage,localStarage) key:定义本地存储中的key
模块化管理数据(modules)
1.什么时候需要用到模块
管理vuex数据
项目庞大,数据信息量特别大的时候,我们可以考虑分模块形式管理数据,比如user模块管理用户信息数据,cart模块管理购物车数据,shop模块管理商品信息数据
5. vue-router(路由原理,路由守卫,路由传参)
路由实现原理:
概念:
通过改变URL,在不重新请求页面的情况下,更新页面视图。
实现方式:
vue-router通过hash
与History interface
两种方式实现前端路由,更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:
1.hash
---- 利用URL中的hash(’#’);
2.利用History interface
在HTML5中的新增方法
6. vue生命周期
简单粗暴:
答: 总共分为8个阶段。创建前/后 , 挂载前/后 , 更新前/后 , 销毁前/后
。
创建前/后: beforeCreated
创建前,vue实例的挂载元素$el
和数据对象data都是undefined,还未初始化。在created阶段/创建后,vue实例的数据对象data有了,$el还没有。
挂载前/后: beforeMount
挂载前,vue实例的el
和data
都初始化了,但是还没有挂载html 到页面上。在Mounted
阶段/挂载后,模板中的 HTML 渲染到 HTML 页面中,此时一般可以做一些 ajax 操作,mounted 只会执行一次。
更新前/后: 当data变化时,会触发beforeUpdate
和updated
方法
销毁前/后: 在destroy
阶段/销毁前,对data的改变不会再触发周期函数,说明此时vue实列已经解除了事件监听和dom绑定,但是dom结构依然存在。destroyed
阶段,组件销毁
7. 自定义指令,自定义过滤器
8. 自定义组件
9. 常用的指令,修饰符
10. vue2.0和vue3.0的区别
11. keep-alive
概念:
是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现的父组件链中。
作用:
在组件切换的过程中,把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载事件以及性能消耗,提高用户体验性
原理:
在 created
钩子函数调用时将需要缓存的 VNode 节点保存在 this.cache
中/在 render
(页面渲染) 时,如果VNode
的 name
符合缓存条件(可以用 include
以及 exclude
控制),则会从 this.cache
中取出之前缓存的 VNode
实例进行渲染
VNode: 虚拟DOM,其实就是一个JS对象
参数:
- include - 字符串或者正则表达式。只有匹配的组件会被缓存。
- exclude - 字符串或正则表达式。然后匹配的组件都不会缓存。
- max - 数字。最多可以缓存多少组件实例
对生命周期函数变化:
被包含在keep-alive中的组件,会多出来两个生命周期的钩子函数,activated
和 deactiveated
1.activated在keep-alive
组件激活时调用
2.deactivated在keep-alive
组件离开时调用
//正常的生命周期:beforeRouterEnter --> created -->mounted --> updated --> destroyed
//使用keepAlive后生命周期:
//首次进入缓存页面 :beforeRouterEnter --> created -->mounted --> updated --> destroyed
//再次进入缓存页面 :beforeRouteEnter --> activated --> deactivated
//注:
//1、这里的activated非常有用,因为页面被缓存时,created,mounted等生命周期均失效,你若想进行一些操作,那么可以在activated内完成(下面会举个栗子:列表页回到上次浏览位置)
//2、activated keep-alive组件激活时调用,该钩子在服务器端渲染期间不被调用。
//3、deactivated keep-alive组件停用时调用,该钩子在服务端渲染期间不被调用
可以结合Router中的meta,来缓存部分页面
12. 多环境变量
13. 对axios封装,(url统一管理,axios请求拦截,响应拦截,函数封装)
14. element-ui,vant-ui 按需引入
15. sass配置
16. rem , vw/vh 适配
rem适配:
使用vant里面的游览器适配,
Vant 中的样式默认使用 px 作为单位,如果需要使用 rem 单位,推荐使用以下两个工具:
postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem
lib-flexible用于设置 rem 基准值
安装 lib-flexible
和 postcss-plugin-px2rem
cnpm i lib-flexible postcss-plugin-px2rem --save-dev
配置rem: mian.js 导入
import 'lib-flexible/flexible'; //rem 就可以生效了
配置px–> rem:创建vue.config.js
//可以在此配置的基础上根据项目需求进行修改。
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
rootValue:75, //换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
// unitPrecision: 5, //允许REM单位增长到的十进制数字。
//propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。
// propBlackList: [], //黑名单
// exclude: /(page_pc)/i, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
exclude: /node_modules/i,
// selectorBlackList: ['van-'], //要忽略并保留为px的选择器,我们一般不转换vantui中的大小
// ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
// replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
}),
]
}
}
},
}
17. webpack配置(配置跨域,路径别名,打包分析,cdn引入,去掉console.log,单独打包第三方模块,ie兼容,eslint规范,图片压缩)
本文地址:https://blog.csdn.net/GYF_123/article/details/112268866