vue面试总结
1、v-if和v-show区别
v-if 创建、删除 (没有创建元素)
v-show 显示 、隐藏 (有元素存在)
v-if 是真正的条件渲染,因为它会确保在条件切换过程中条件快内的事件监听器和子组件适当地被销毁和重建
v-if也是惰性的,如果在初始条件渲染为假,则什么都不做,一直到条件为真时,开始执行渲染
相比之下,v-show 就简单多了,不管初始条件是什么 元素总是被渲染 并且只是简单地基于css进行切换
一般来说 v-if 有更高的切换开销 而v-show有更高的初始渲染开销。
因此 如果需要非常频繁地切换则使用v-show较好
如果在运行时条件不太可能改变 则使用v-if较好
2、如何让CSS只在当前组件中起作用
将当前组件的style 修改为<style scope></style>
scss、stylus 的扩展
下载scss: npm install sass-loader node-sass --save
使用:<style lang='scss' scope></style>
样式穿透写法:
父元素 /deep/ 子元素 或者
父元素 >>> 子元素
3 v-modle的使用,标签如何绑定事件
```
可以实现双向绑定 在input 或者 select 或者文本域配合value使用
v-on:click 或者 @click
在移动端click有300ms延迟的问题 解决这个问题可以引入fastClic
下载 :npm install fastClick
引入:import FastClick from 'fastClick'
FastClick.attach(document.body)
```
4 vue-loader 是什么 使用它的用途有哪些?
.vue文件的一个加载器 用途:js可以写es6 style样式 scss等
5 NextTick是做什么的
说明:$nextTick是在下次dom 更新循环结束之后 执行延迟回调,在修改数据之后使用$nextTick则可以在回调获取更新后的DOM
场景:需要在视图更新之后,基于新的视图进行操作
6 脚手架组件data为什么必须是函数
vue使用两种方式: (1) 不用脚手架 vue.js ;(2)使用脚手架
因为JS本省的特性带来的,如果data是一个对象,那么由于对象本身属于引用类型,当我修改其中的一个属性时,
会影响到所有Vue实例的数据。如果将data作为一个函数返回对象,那么每一个实例的data属性都是独立的,不会相互影响。
7 vuex是什么?怎么使用?哪种场景使用它?
vuex是一个专门为vue构建的状态集管理
主要是为了解决组件间状态共享的问题
强调的是集中式管理,适合做大型项目
vuex的核心对象:state mutations getters actions modules
8 导航钩子函数有哪些?有哪些参数?
导航钩子翻译过来就是路由的生命周期函数,主要分为全局和局部
全局的钩子函数
beforeEach:在路由切换开始时调用;
afterEach:在路由切换离开时调用;
9 谈一下vue响应式数据的原理?
1.核心点:Object.defineProperty
2.默认Vue在初始化数据时,
会给data中的属性使用Object.defineProperty重新定义所有属性,
当页面取到对应属性时。会进行依赖收集(收集当前组件的watcher)如果属性发生变化会通知相关依赖进行更新操作。
10 vue是如何检测到数组变化?
使用函数劫持的方式,重写了数组的方法
Vue将data中的数组,进行了原型链重写。指向了自己定义的数组原型方法,
这样当调用数组api时,可以通知依赖更新,如果数组中包含着引用类型。会对数组中的引用类型再次进行监控。
11 vue的watch与computed的差异?
两者用途不同 computed 用于产生新的数据 watch 用于监听现有的数据
computed : 计算属性
1.计算属性是由data中的已知值,得到一个新的值;
2.性能不好;
3.别人变化影响我自己(被动变化);
watch 监听data中的数据的变化(主动变化)
1.监听data中的数据
2.我的变化影响别人
12 vue的computed与方法的差异?
13 vue的组件之间的通信?
props 和 $emit
$parent
自定义事件 vue3 需要引入第三方的库来是实现自定义事件:event-emitter
$refs
$attr
provide/inject
Vuex
1.父组件传值子组件:
父组件: <Header :msg='msg'></Header>
子组件: props:{ msg:String} 或 props:['msg']
2.子组件传值父组件
子组件:
this.$emit("自定义事件名称",要传的数据)
例如: this.$emit("childInput",this.changeVal)
父组件:
<Header @childInput="getVal"></Header>
methods: {
getVal(msg) {
//msg就是子组件传递的数据
this.msgVal = msg;
}
}
3.兄弟组件之间的传值
A兄弟传值:
import bus from "../common/bus.js";
bus.$emit("toFooter", this.msg);
B兄弟接收:
import bus from "../common/bus.js";
bus.$on("toFooter", data => {
//data就是this.msg里面的数据
this.str = data;
});
14 vue-cli项目中src目录每个文件夹和文件的用法
src
assets // 静态资源(图片、js、css)
components //非路由组件
views //参与路由的跳转组件
router //路由配置
store //vuex(仓库)
App.vue //挂载的第一个组件
main.js //全局的文件
15 axios是什么?怎么使用?描述使用它的是怎么实现一个登陆流程?
1、axios是什么?怎么使用?
下载安装: npm install axios --save
引入(main.js):
import axios from 'axios'
Vue.prototype.axios =axios;
使用: axios.get('/api/login?userName=???&userPwd=???')
axios.post('/api/login',{
userName:???
userPwd:???
})
2、设置代理,请求接口(跨域)
config/index.js
proxyTable:{
'/api':{
target:"http://localhost:8080",
changeOrigin:true, //允许跨域
pathRewrite:{
//这里是当前调用的接口请求路径
'^/api':'static/mock'
}
}
}
修改了webpack的配置 一定要重启一下服务
15 v-if和v-for可以一起使用么?
不建议一起使用,在vue2里面 v-for 比 v-if运算级别更高一些。
16 vue事件使用以及事件修饰符
event 是原生的事件对象
<button @click="increment2(2,$event)">+2</button>
//自定义事件参数
increment2(val, event) {
this.num = this.num + val;
}
17 vue组件生命周期
创建阶段
挂载阶段
更新阶段
销毁阶段
beforeCreate: 创建一个空白的Vue 实例 data method 尚未被初始化,不可使用
created : Vue 实例初始化完成,完成响应式绑定 data method 都已经初始化完成,可调用 尚未开始渲染模板
beforeMount: 编译模板,调用render生成vdom 还没有开始渲染DOM
mounted 完成DOM渲染 组件创建完成 开始由 创建阶段 进入 运行阶段
created与mounted的主要区别在于:created时vue组件实例已经初始化完成,
但页面还没有完成渲染,mounted是页面已经绘制完成,可以做一些ajax的请求信息和事件绑定的操作。
beforeUpdate: data 发生变化之后 准备更新DOM(尚未更新)
updated: data 发生变化,且DOM 更新完成 (不要在 updated 中修改data,可能会导致死循环)
beforeDestroy 组件进入销毁阶段(尚未销毁,可正常使用) 可移除、解绑一些全局事件、自定义事件 解除销毁子组件以及事件监听器
destroy 组件被销毁了 所有子组件也都被销毁了
keep-alive 组件
onActivated 缓存组件被激活
onDeactivated 缓存组件被隐藏
扩展:Vue3 Composition API 生命周期有何区别?
用 setup 代替了 beforeCreate 和 created
使用 Hooks函数的形式,如 mounted改为 onMounted()
18 vue的keep-alive组件有什么用
缓存组件,使用于频繁切换,不需要重复渲染,Vue常见性能优化
19 vue的mixin是什么?
作用:
多个组件有相同的逻辑,抽离出来
mixin并不是完美的解决方案,会有一些问题
Vue3提出的Composition API旨在解决这些问题
缺点:
变量来源不明确,不利于阅读
多mixin可能会造成命名冲突
mixin和组件可能出现多对多的关系,复杂度较高
20.一旦进入组件会执行哪些生命周期?
beforeCreate created beforeMount mounted
21.父组件引入子组件,那么生命周期会执行哪些?
父:beforeCreate created beforeMount
子:beforeCreate created beforeMount mounted
父:mounted
总结:子组件先于父组件渲染是为了保证数据的流动性和组件的独立性
22.为什么发送请求不放在 beforeCreate? beforeCreate 和created有什么区别
如果请求实在methods封装好的 在beforeCreate阶段调用的时候 是拿不到methods里面的方法(会报错)
beforeCreate 这个阶段没有$el 也没有$data
created 阶段有$data 可以拿到methods里面的方法
23.在created中如何获取dom?
(1)只要写异步代码,获取dom是在异步中获取就可以 如:setTimeOut ajax请求等
(2)使用vue内置的this.$nextTick
(3) $nextTick返回的参数(函数)是一个异步的。功能:获取更新后的dom
源码|原理:
$nextTick(callback){
return Promise.resolve().then(()=>{
callback()
})
}
24.vue里面发送请求在created 还是mounted?
这个要看项目和业务的情况,因为组件的加载顺序,父组件引入了子组件,
那么先执行父的前3个生命周期,再执行子组件的前4个生命周期,
那么如果我们的业务是父组件引入子组件,
并且优先加载子组件的数据,那么在父组件中当前的请求要放在mounted中,
如果当前组件没有依赖关系那么放在哪个生命周期中请求都是可以的。
25.加入keep-alive会执行哪些生命周期
activated
deactivated
keep-alive 是用来缓存当前组件
如果使用了keep-alive组件 当前的组件会额外增加2个生命周期
第一次进入组件会执行五个生命周期 beforeCreate created beforeMount mounted activated
第二次 或者第N次 只会执行一个生命周期 activated
26.你在什么情况下用过哪些生命周期?说一说生命周期使用场景
created ==>单组件请求
mounted ==> 同步可以获取dom 如果先子组件请求后父组件请求
activated ==>判断id是否相等 如果不相同发起请求
destroyed ===> 关闭页面记录视频播放的时间 初始化的时候从上一次的历史开始播放
27.vue组件之间的通信方式(常用)
(1)父传后代(后代拿到了父的数据) 子组件通过prop来接收 这种方式父传子很方便
但父传给孙子辈的组件就很麻烦 而且这种方式不能直接修改父辈组件的值
(2)子组件直接使用父组件的数据使用this.$parent.xxx 来实现 这种方式子组件可以直接修改父组件的数据
(3) 依赖注入 provide/inject 优势:父组件可以直接向某个后代组件传值(不用一级一级的传递) 同级组件之间不可这样传递
(4) 后代传父(父拿到了后代的数据)
1.子组件传值给父组件 子组件定义自定义事件 this.$emit
(5) 平辈之间的组件怎么传值(兄弟组件之间传值)
通过新建bus.js来中转传值
28.子组件是如何修改父组件的数据?
子组件可以通过this.$parent.xxx 来修改 $parent 找到当前组件的父组件 如果找不到就返回
29.父组件如何直接修改子组件的数据?
通过 this.$refs.child.xxx='yyy'
30.如何找到根组件?
this.$root 找到根组件
31.slot使用 ?
在Vue中,插槽是一种让父组件能够向子组件传递标记的方法。这使得组件可以用于模板布局和复用。
插槽分为3种
匿名插槽:插槽没有名字
具名插槽:插槽有名字
作用域插槽:传值
32.Vuex的使用有哪些属性?
state ==>全部共享属性 this.$store.state.xxx 获取state里面的属性 对应的辅助函数mapState
getters ==>针对于state数据进行二次计算 getters是不可以用于修改的
mutation ==> 原子操作 必须是同步方法 存放同步方法的
action ==> 可包含多个mutation 存放异步方法 并用来提交mutation
modules ==> 把vuex再次进行模块之间的划分
使用this.$store.state.xxx 是可以直接修改vuex的state数据的 使用辅助函数的形式 是不可以修改的
33.Vuex的mutations和actions区别
相同点:mutations和actions都是用来存放全局方法的,这个全局方法return的值 拿不到
区别:mutations 同步操作 是用来修改state
actions 返回的是一个Promise 可以执行异步操作 actions的作用是来提交mutations
34.路由的两种模式有什么区别?
区别:
(1) 关于找不到页面发送请求的问题 history 会给后端发送一次请求 这就需要配置一个默认的404页面进行指向
(2) hash模式不会有这种情况
(3) 关于项目打包前端自测问题 hash是可以看到内容的 history 默认是看不到内容的
(4) 表象不同 hash:# history:/
35.router和router和router和route区别
$router不仅包含当前路由还包含整个路由的属性和方法
$route 包含当前路由对象
36.路由导航守卫
1. 全局守卫
beforeEach 路由进入前
afterEath 路由进入后
2. 路由独享守卫
beforeEnter 路由进入之前
3. 组件内守卫
beforeRouteEnter 路由进入之前
beforeRouteUpdate 路由更新之前
beforeRouteLeave 路由离开之前
37.$set的用法
数据更新了但视图没有更新的问题 使用 $set(target,key,修改后的值)
38.data定义数据
数据定义在data的return内和return外的区别
return外:单纯修改这个数据是不可以的修改的 因为没有被get/set
return内: 是可以修改的
39.vue计算属性和监听属性的区别
侦听属性不会像计算属性那样自动缓存,每当监听的数据变化时,相应的函数就会执行。
计算属性适用于一个依赖于其他数据的变化且需要缓存的场景,而侦听属性更适合当一个数据的变化需要执行异步或者代价较高的操作时。
通过get/set 写法 可以改变计算属性的值
当前组件v-model绑定的值是computed来的 那么也可以通过 通过get/set 写法 改变计算属性的值
40.vue 的computed和methods的区别
computed 是有缓存机制 methods是没有缓存机制的 调用几次就执行几次
41.vue 双向数据绑定原理
通过Object.defineProperty劫持数据发生的改变,如果数据发生改变了(在set中进行赋值的),触发update方法进行更新节点内容,从而实现了数据双向绑定的原理。
42.为何在 v-for 中用 key?
必须用key,且不能是index和random随机数
diff 算法中通过 tag 和key 来判断,是否是sameNode
减少渲染次数 提升渲染性能
43.双向数据绑定v-model 的实现原理
input 元素的value = this.name
绑定input 事件this.name = $event.target.value
data更新触发re-render
通过数据劫持 和发布订阅者模式来实现
同时利用Object.defineProperty()劫持各个属性的setter和getter
在数据发生改变的时候发布消息给订阅者 触发对应的监听回调渲染视图
也就是说 数据和视图同步的 数据发生改变 视图跟着发生改变
视图跟着发生改变 视图改变 数据也会发生改变。
44.Vue3比Vue2 有什么优势?
性能更好 更好的代码组织
体积更小 更好的逻辑抽离
更好的ts支持 更多功能
45 Vue 常见性能优化方式
合理使用v-show 和 v-if
合理使用computed
v-for 时加 key ,以及避免和v-if同时使用
自定义事件、DOM 事件及时销毁
合理使用异步组件
合理使用keep-alive
data层级不要太深
使用vue-loader在开发环境做模板编译(预编译)
合理使用keep-alive
webpack 层面的优化(后面会讲)
前端通用的性能优化,如图片懒加载
使用SSR
46 Vue组件设计原则
从功能上拆分层次
尽量让组件原子化
容器组件(只管理数据)& UI 组件(只显示视图)
47 为何在 v-for 中用 key
必须用 key ,且不能是index和random
diff 算法中通过tag 和key 来判断,是否是sameNode
减少渲染次数,提升渲染性能
48 Vue 组件如何通讯(常见)
父子组件 props 和 this.$emit
自定义事件event.$no event.$off event.$emit
vuex
49 描述组件渲染和 更新过程
50 双向数据绑定 v-model的实现原理
input 元素的value = this.name
绑定 input 事件this.name = $event.target.value
data 更新触发re-render
51 对mvvm的理解
52 computed 有何特点
缓存,data 不变不会重新计算
提高性能
53 ajax请求应该放在哪个生命周期
mounted
JS 是单线程的,ajax异步获取数据
放在mounted 之前没有用,只会让逻辑更加混乱
54 如何将组件所有 props 传递给子组件?
$props
<User v-bind= “$props”/>
细节知识点,优先级不高
55 何时使用异步组件
加载大组件
路由异步加载
56 何时需要使用keep-alive ?
缓存组件,不需要重复渲染
如多个静态tab 页的切换
57 何时需要使用beforeDestory
解绑自定义事件event.$off
清除定时器
解绑自定义的 DOM 事件,如 window scroll 等