CSDN话题挑战赛第2期
参赛话题:面试宝典
面试题
面试题一:
Vue组件之间通信⽅式有哪些
问题简介:
Vue是组件化开发框架 对于vue应用来说 组件间的数据通信很重要
此题考查vue的基本功,对于vue基础api的运用熟练度
问题思路:
1.综述知道的所有方式
2.按组件关系阐述使用场景
问题解答:
1.组件常用的通信方式有8钟:
- props
- $emit/
$on$children/$parent- $attrs/
$listeners- ref
- $root
- eventbus
- vuex
- (其中删除线的为Vue3废弃的API)
2.根据组件之间关系讨论组件通信是最清晰的
- 父子组件
- props/$emit/$parent/ref/$attrs
- 兄弟组件
- $parent/$root/eventbus/vuex
- 跨层级关系
- eventbus/vuex/provide + inject
组件传参的各种方式图解
面试题二:
v-if和v-for哪个优先级最高?
问题简介:
此题考查常识, 项目中经常会遇到,能够看出面试者对API熟悉程度和应用能力
问题思路:
1.先出结论
2.为什么这样,说出细节
3.哪些场景可能导致这样做,该怎么处理?
4.总结 拔高
问题解答:
1.在实践中 不应该把v-for和v-if放在一起
2.在vue2中 v-for优先级高于v-if. 它们放在一起 输出的渲染函数中可以看出先执行循环再判断条件 哪怕我们只渲染列表中一小部分元素,也得在每次重新渲染的时候遍历整个列表.但是在vue3中则是v-if的优先级高于v-for,所以v-if执行时 它调用的变量还不存在,就会导致异常.
3.通常有两种场景下导致我们这样做:
为了过滤列表中的项目.如(v-for="user in users" v-if="user.isActive").此时定义一个计算属性(activeUsers)让其返回过滤后的列表.(如:users.filter(u=>u.isActive))
为了避免渲染 本来应该被隐藏的列表(如:v-for="user in users" v-if="isShowUsers")此时把v-if移动到容器元素上(如:ul 或 ol)或者外面包一层template即可.
4.在官方文档中指出,永远不要把v-if和v-for同时用在一个元素上.
5.在源码当中,关于代码生成的部分,能够清晰的看到是先处理v-if还是v-for的,顺序上,vue2和vue3正好相反.但是不管怎么样 都是不能把它们写在一起的.
源码中找答案:
Vue2:codegen/index.js中60行
Vue3:codegen.ts文件570行
面试题三:
Vue的生命周期及每个阶段做的事
问题简介:
考察vue基础知识
问题思路:
1.给出概念
2.说出生命周期各个阶段
3.说出整体流程
4.综合实践
5.拓展:vue3中的变化
问题解答:
1.每个Vue组件被创建过后都会经过一系列初始化步骤,如:它需要数据观测,模版编译,挂载实例到DOM上,以及数据变化时更新DOM,这个过程中会运行 叫做生命周期的钩子函数,方便在特定阶段添加自己的代码
2.Vue生命周期有8个阶段,创建前后,载入前后,更新前后,销毁前后,以及特殊的生命周期.vue3新增了3个用于调试和服务器渲染的场景.
Vue2生命周期 Vue3生命周期 描述 beforeCreate beforeCreate 组件实例被创建之初 created created 组件实例被完全创建 beforeMount beforeMount组件挂载前 mounted mounted组件挂载后 beforeUpdate beforeUpdate组件数据发生变化,更新之前 updated updated组件数据更新之后 beforeDestroy beforeUnmounted组件实例销毁之前 destroyed unmounted组件实例销毁之后 activated activatedkeep-alive 缓存组件激活前 deactivated deactivatedkeep-alive 缓存组件停用时调用 errorCaptured errorCaptured捕获一个子孙组件的错误时调用 renderTracked 调试钩⼦,响应式依赖被收集时调⽤ renderTriggered 调试钩⼦,响应式依赖被触发时调⽤ serverPrefetch ssr only ,组件实例在服务器上被渲染前调⽤4.综合实践:
beforeCreate:用于插件开发中执行一些初始化任务
created:组件初始化完毕,可以访问各种数据,获取接口等
mounted:dom创建,用于获取访问数据和dom元素,访问子组件等.
beforeUpdate:此时 view 层未更新,可获取更新前各种状态
updated:完成 view层的更新,更新后 所有状态为新
beforeUnmounted:实例被销毁前,可用于一些定时器或订阅取消
unmounted:销毁一个实例,可清理它与其他实例的连接,解绑它全部指令及事件监听器
追问:
1.setup和created谁先执行?
2.setup中为什么没有beforeCreate和created?
setup最先执行,此时组件实例在setup内部已经创建,所以created的处理对于setup来讲明显在后面,对于开发者来说已经没有意义, 所以setup中没必要再使用beforeCreate和created。
面试题四:
双向绑定的使用和原理
问题简介:
双向绑定是 vue 的特⾊之⼀,开发中必然会⽤到的知识点,此题还问了实现原理,升级为深度考查。
问题思路:
1.说出双向绑定的定义
2.双向绑定带来的好处
3.在哪里使用双向绑定
4.使用方法 细节 Vue3中的变化
5.原理实现描述
问题解答:
1.Vue中双向绑定指令v-model 可以绑定一个响应式数据到视图,同时视图中的变化能改变该值.
2.v-model是语法糖,默认情况下相当于:value和@input.使用v-model可以减少大量的事件处理代码,提高开发效率
3.通常在表单上使用v-model.在自定义组件上使用 表示某个值的输入和输出控制
4.通过input v-model="xxx"的方式将xxx的值绑定到表单元素的value上,可以结合lazy,.number,.trim对v-mode的⾏为做进⼀步限定; v-model用在自定义组件上又有很大的不同,在vue3中类似于sync修饰符,最终展开的结果为modelValue属性和update:modelValue事件;vue3中我们可以⽤参数形式指定多个不同的绑定,例如v-model:foo和v-model:bar.
5.v-model是一个指令;v-model的模板,转换为渲染函数之后实际上还是是value属性的绑定及input事件监听,事件回调函数中会做出相应变量的更新操作.编译器根据表单元素的不同会展开不同的DOM属性和事件. 如text类型的input和textarea会展开为 value和input事件
追问:
1.v-model 和 sync 修饰符有什么区别
格式不同:v-model="xx",:num.sync="xx"
v-model:等价于:@input + value
:num.sync:等价于:@update:num
v-model只能用一次;.sync可以有多个
面试题五:
Vue中如何扩展一个组件
问题简介:
实践题,考察对 vue 常⽤ api 使⽤熟练度,答题时不仅要列出这些解决⽅案,同时最好说出他们异同。
问题思路:
1.按照逻辑扩展和内容扩展来列举,
逻辑拓展有:mixins extends composition api
内容拓展有slots
2.说出它们使用方法 场景差异和问题
3.拓展: 说说vue3新引入的composition api带来的变化
问题解答:
1.常见的组件拓展方法有:mixins slots extends等
2.混入mixins是分发Vue组件中可服用功能的非常灵活的方式混⼊对象可以包含任意组件选项。当组件使⽤ 混⼊对象时,所有混⼊对象的选项将被混⼊该组件本身的选项。
// 复用代码:是一个配置对象 选项和组件里面一样 const myMixin = { methods:{ doSomething(){} } } // 全局混入: 将混入对象传入 Vue.mixin(myMixin) // 局部混入: 数组选项设置到mixins选项,仅作用于当前组件 const comp = { mixins:[myMixin] }
3.插槽主要⽤于vue组件中的内容分发,也可以⽤于组件扩展。
// 子组件Child <div> <slot>这里的内容会被父组件传递的内容替换</slot> </div> // 父组件 Parent <div> <Child>来⾃父亲的内容</Child> </div>
如果要精确分发到不同位置可以使用具名插槽,如果要使用子组件中的数据可以使用作用域插槽.
4.组件选项中还有一个不常用的选项 extends 也可以起到扩展组件的目的
// 拓展对象 const myExtends = { methods:{ doSomething(){} } } // 组件拓展: 做数组项设置到extends选项,仅作用于当前组件 // 跟混入的不同 它只能拓展单个对象 // 如果和混入发生冲突 该选项优先级高,优先起作用 const comp = { extends:myExtends }
5混入的数据和方法不能明确判断来源 ,可能和当前组件内变量产生命名冲突,vue3中引入的compositionApi很好的解决这些问题,利用独立出来的响应式模块 可以很方便的编写独立逻辑并且提供响应式的数据,然后在setup选项中组合使用,增强代码的可读性和可维护性.
// 复用逻辑1: function useXX() {} // 复用逻辑2: function useYY() {} // 逻辑组合 const comp = { setup(){ const {xx} = useXX() const {yy} = useYY() return {xx,yy} } }
面试题六:
子组件可以直接改变父组件的数据吗?
问题简介:
组件化开发过程中有个 单项数据流原则 ,不在⼦组件中修改⽗组件是个常识问题。
问题思路:
1.讲讲单项数据流原则,为何不能这么做?
2.举例子说说解决方案
3.结合实践说一下如果需要修改父组件状态应该怎么做?
问题解答:
1.所有的 prop 都使得其⽗⼦之间形成了⼀个 单向下⾏绑定 :⽗级 prop 的更新会向下流动到⼦组件中,但是反过来则不⾏。这样会防⽌从⼦组件意外变更⽗级组件的状态,从⽽导致你的应⽤的数据流向难以理解。另外每次⽗级组件发⽣变更时,⼦组件中所有的 prop 都将会刷新为最新的值。这意味着你 不 应该在⼀个⼦组件内部改变 prop 。如果你这样做了, Vue 会在浏览器控制台中发出警告。2. 实际开发过程中有两个场景会想要修改⼀个属性这个 prop ⽤来传递⼀个初始值;这个⼦组件接下来希望将其作为⼀个本地的 prop 数据来使⽤。 在这 种情况下,最好定义⼀个本地的 data ,并将这个 prop ⽤作其初始值const props = defineProps(['initialCounter']) const counter = ref(props.initialCounter)
这个 prop 以⼀种原始的值传⼊且需要进⾏转换。 在这种情况下,最好使⽤这个 prop 的值来定义⼀个计 算属性const props = defineProps(['size']) // prop变化,计算属性⾃动更新 const normalizedSize = computed(() => props.size.trim().toLowerCase())
3.实践中如果确实想要改变⽗组件属性应该emit⼀个事件让⽗组件去做这个变更。注意虽然我们不能直接修改
⼀个传⼊的对象或者数组类型的 prop ,但是我们还是能够直接改内嵌的对象或属性。
面试题七:
说⼀说你对vue响应式理解?
问题简介:
这是⼀道必问题⽬,但能回答到位的⽐较少。如果只是看看⼀些⽹⽂,通常没什么底⽓,经不住⾯试官推敲,但像我们这样即看过源码还造过轮⼦的,回答这个问题就会⽐较有底⽓啦。
问题思路:
1.什么是响应式?
2.为什么Vue需要响应式
3.它能给我们带来什么好处?
4.Vue的响应式是怎么实现的?有哪些优缺点?
5.Vue3中的响应式的新变化
问题解答:
1.能够使数据变化可以被检测并且对这种变化做出响应的机制叫做响应式.
2.MVVM框架中需要解决的一个核心问题就是连接数据层和视图层,通过数据驱动应用,数据变化 视图更新 要做到这点就需要对数据做出响应式处理 这样一旦数据发生变化就可以立即做出更新处理.
3.Vue通过数据响应加上虚拟DOM和patch算法,开发人员只需要操作数据,关心业务.提高开发效率,降低开发难道.
4.vue2中的数据响应式会根据数据类型来做不同处理,如果是对象则采⽤Object.defineProperty()的⽅式定 义数据拦截,当数据被访问或发⽣变化时,我们感知并作出响应;如果是数组则通过覆盖数组对象原型的7个变更⽅法,使这些⽅法可以额外的做更新通知,从⽽作出响应。这种机制很好的解决了数据响应化的问题,但 在实际使⽤中也存在⼀些缺点:⽐如初始化时的递归遍历会造成性能损失;新增或删除属性时需要⽤户使用Vue.set/delete这样特殊的api才能⽣效;对于es6中新产⽣的Map、Set这些数据结构不⽀持等问题
5.为了解决这些问题,vue3重新编写了这⼀部分的实现:利⽤ES6的Proxy代理要响应化的数据,它有很多好 处,编程体验是⼀致的,不需要使⽤特殊api,初始化性能和内存消耗都得到了⼤幅改善;另外由于响应化的 实现代码抽取为独⽴的reactivity包,使得我们可以更灵活的使⽤它,第三⽅的扩展开发起来更加灵活了。