1.你怎么看待理解vuejs
当一个vue实例创建时,vue会便利data事件,通过Object.denfineProperty将data中的数据转为getter/setter(vue3使用的proxy),并且在北部追踪相关的依赖,在属性被访问和修改时通知变化。每个组件都有相应的watcher程序实例,会在组件渲染的过程中把属性记录为以来,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使相关联的组件得以更新。
2.双向数据绑定的原理
vuejs使用的是数据劫持结合发布者订阅者模式的方式。通过object.defineProperty()来劫持每个属性的getter、setter,在数据变动的时候发布给消息给订阅者,触发相对应的回调。过程如下:
(1)observe,对所有的数据对象包括子属性对象的属性进行遍历添加setter和getter,当有值发行变化的时候就会触发setter,监听到数据的变化。
(2)compile:解析模板指令,将模板中的变量替换成数据,然后进行初始页面试图的渲染,把所有指令对应的节点绑定上更新函数,添加监听数据的订阅者,一旦数据有变动收到通知,更新视图。
(3)watcher订阅者是observe和compile之间通信的桥梁,主要做三件事:在自身实例变化的时候给属性订阅器(dep)里面添加自己、自身拥有一个upodate()方法、属性变化时dep.notice()通知时调用自己的update()方法并触发Compile中绑定的回调
(4)MVVM作为数据的入口:整合Observer、compile、watcher三者,通过observer监听自己model数据变化,通过compil解析模板,最终利用wathcer连接observer、compile,达到数据变化到视频更新;数model的变更的双向绑定效果。
3.使用Object.defineProperty的缺陷Vue3为什么使用proxy
1.使用Object.defineProperty()去劫持数据会有一部分数据是无法拦截的,数组中的一些方法不能拦截,vue内部是通过重写函数的方式去实现数组的相关方法,push()、sort()\slice()\split()\resver等。
2.vue3使用proxy是对象进行代理,可以完美监听任何数据改变,但是有兼容性问题。
4.Computed和watch的区别
(1)computed:具有缓存,不支持异步,只有相关依赖的数据改变的时候才会触发进行从新计算。
(2)watch:没有缓存,监听的作用,只要监听的数据发生变化就触发执行函数。
5.slot是什么?有什么作用?原理是什么?
slot是插槽的意思,分为三种如下:
(1)默认插槽:也就是匿名插槽,当slot没有指定name的属性值得时候。
(2)具名插槽:带有具体名字的插槽,给slot指定name的属性值的时候。
(3)作用域插槽:将子组件内部的数据传递个父组件,让父组件根据子组件传递过来的数据来决定如何渲染该插槽。
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信方式,适用于父组件===>子组件
原理:当子组件vm实例化的时候,获取父组件传入的slot标签的内容,存放在vm.
s
l
o
t
中,默认插槽存放在
v
m
.
slot中,默认插槽存放在vm.
slot中,默认插槽存放在vm.slot.default,具名插槽存放在vm.$slot.xxx.当组件执行渲染的时候遇到solt标签。使用slot中的内容进行替换,也可以传递数据,如果有数据就是作用域插槽
6.说说vue的生命周期
说句实话我最常用的就created、mounted,beforeDestroy但是面试其他的还是的熟悉
(1) beforeCreate 实例初始化之后
created 实例化完成之后 (面试题发送请求放在那个地方最好,没错就是这里)
beforeMount 在挂载之前
Mounted 挂载完成(面试题发送请求放在那个地方最好,这个地方有时候会导致白屏)
beforeUpdate 数据发生改变后,DOM被更新之前
Updated 数据更改导致重新熏染和更新完毕之后
当使用keep-alive保存组件状态会多出来两个
activated 组件激活时
deactivated 组件销毁时
就这两个
beforeDestroy 实例销毁之前
destryed 实例销毁后
7.说说vuex
作用:用于全局状态管理
应用场景:用户的登录信息的存储、购物车等
核心:State 数据源,数据的存放地,当需要使用的时候就用this.
s
t
o
r
e
.
s
t
a
t
e
或者使用
m
a
p
S
t
a
t
e
函数
G
e
t
t
e
r
s
:计算属性,就是
s
t
a
t
e
的过滤器,筛选出想要的数据获取
s
t
o
r
e
.
g
e
t
t
e
r
s
.
方法名
m
u
t
a
t
i
o
n
:提交数据,就是提交自己本身到
s
t
a
t
e
中,提交存放数据
‘
t
h
i
s
.
store.state或者使用mapState函数 Getters:计算属性,就是state的过滤器,筛选出想要的数据获取store.getters.方法名 mutation:提交数据,就是提交自己本身到state中,提交存放数据`this.
store.state或者使用mapState函数Getters:计算属性,就是state的过滤器,筛选出想要的数据获取store.getters.方法名mutation:提交数据,就是提交自己本身到state中,提交存放数据‘this.store.commit(‘方法名’,数据) action:可以异步提交mutation,但是不是直接变更状态,提交mutation
this.context.commit(‘方法名’,数据) 分发action使用
this.store.dispatch('方法名)`
Modules:将state中的数据模块化,解决代码臃肿问题
8.组件通信方式
(1)props:父子之间传参
(2)$emit:子父传参,写一个函数把数据单做参数存放在函数中,在父组件中进行调用
(3)EventBus:全局事件总栈,在全局中注册事件,然后再需要的地方调用
(4)provide/inject组合 provide中return出去数据inject:[‘数据名’]
9.说说keep-alive
作用:保持组件的状态,以避免反复重新渲染导致组件性能问题。
属性和用法:用一个动态的数据来判断是否缓存或者v-if和v-else,include有条件的缓存,max最多缓存几个组件
10.说说路由守卫
分为三大类如下所示:
(1)全局守卫
1.前置路由守卫beforeEach一般用在用户登录判断
2.全局解析守卫beforeResolve
3.后置路由守卫afterEach没有next参数
(2)组件内守卫 beforeRouteUpdate组件创建前、beforeRouteEnter路由改变在此调用该组件、 beforeRouteLeave离开路由时调用
(3)独享路由守卫beforeEnter
11.路由跳转传参
(1)params传参
this.$router.push({name:'路由名',query:{id:'1234}})//url上没有?直接就是id/1234
//获取参数this.$route.params.id
(2)路由属性配置传参
this.$router.push({
name:"/admin/${item.id}",
})
//这个组件对应的路由配置
{
//组件路径
path: '/admin:id',
//组件别名
name: 'admin',
//组件名
component: Admin,
}
//获取参数this.$route.params.id
(3)query传参
this.$router.push({path:'路由地址',query:{id:'1234}})//url上会显示?id=12345
//this.$router.id
//这种方式是可以解决页面刷新参数消失问题的
区别:
(1)params传参
只能用 name,不能用 path。
地址栏不显示参数名称 id,但是有参数的值。
(2)query传参
name 和 path 都能用。用 path 的时候,提供的 path 值必须是相对于根路径的相对路径,而不是相对于父路由的相对路径,否则无法成功访问。
12.hash和history常用的两种路由模式(abstract不常用自己去了解)
(1)hash模式使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
(2)history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;
13.vue中动态绑定class
一般使用v-bind指令去绑定、
(1)对象语法
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
isActive: true,
hasError: false
}
(2)数组语法
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
14.说说vue中单向数据流
所有的prop都是从父级的prop到子级的prop但是但反过来不行,目的是为了防止从子组件意外改变父组件,好处是父组件每次发生更新的时候,子组件所有的peop都是刷新为最新的值。如果子组件想要修改只能通过$emit传递一个自定义时间,父组件接收到后,由父组件进行修改。
15.说说v-if和v-show的
(1)v-if:是通过操作添加和删除DOM元素控制元素的。
(2)v-show:是通过控制display来控制元素的显示与隐藏。
v-if具有更高的切换消耗,因为操作DOM,但是初始条件为false则不触发,适合用于偶尔一次触发的场景。
v-show有更高的初始渲染消耗,因为无论首次条件是true/false都会编译,适用于多次触发的场景。
16.vue中ref的使用
这个就是js中获取DOM元素的快捷方式
作用:引用元素、获取自组件实例、获取某元素、调用某子组件内部方法
<div id="box" ref="refdiv"> haha</div>
<div id="box2" ref="refdiv2"> haha</div>
//这些元素最早可以在mounted声明函数中获得
mounted(){
this.$refs.refdiv.style.color = 'red'//修改box的字体颜色
//this.$refs.refdiv 或 this.$refs['refdiv']都可以获取
}
17.vue中强制刷新
(1)location.reload
(2)this.$router.go(0)
(3)provide和inject配合 最好的方法
这都是很基础的面试题,并没有涉及运行原理和底层,我相信大神也不用来看我的文章,如有错误多多指正,感谢!!!