文章目录
- 常用的vue指令有哪些?你怎么理解指令?
- v-if 和 v-show 有什么区别?
- 文本插值有“{{}}一闪而过”问题,怎么处理?
- v-for 可以循环哪些数据类型?
- v-for列表渲染时为什么加key?
- v-model 有哪些修饰符?
- vue 中怎么阻止冒泡?怎么阻止默认事件?怎么监听键盘enter键?
- 工作中你封装过自定义指令吗?举一些例子
- 计算属性有什么作用?(两大作用)
- 计算属性能不能绑定在v-model上?(可以)
- 怎么理解计算属性的缓存功能?
- 说一下Vue的响应式原理?
- 侦听器可以侦听什么?
- 什么是组件化?你怎么理解组件化?
- 你工作中有没有封装比较好的组件?
- 父子组件之间如何通信?(父传子、子传父)
- 什么是插槽?什么是具名插槽?
- 在创建/挂载/更新/销毁阶段,`Vue`在背后分别做了些什么事儿?
- Vue的生命周期
- 响应式原理,发生在`Vue`哪些生命周期阶段?
- 虚拟DOM,在哪些阶段生成的?
- 什么虚拟DOM?(是一个很大的`JSON`数据,用于描述视图模板的,保存在内存中)
- 虚拟DOM存在的价值点在哪里?(更新,把DOM更新粒度降到最低,规避人为DOM滥操作)
- 哪些场景下你会用到动态组件?
- 混入有什么优势,有什么缺点?
- 常用指令有哪些?你怎么理解指令?你工作是否自已封装过指令?
- 举一个你封装自定义指令的例子
- 复用真的好吗?
- 你有封装过`Vue`插件?怎么封装的?封装过什么?
- 请问 `Vue.use()` 有什么用?讲一讲它背后做了什么?
- 谈一谈你对 `Vue.nextTick()` 的理解?有什么用?
- `nextTick()` 和 updated() 的区别
- `Vue`响应式有没有缺陷呢?有什么缺陷?遇到这种问题你会怎么办?
- 什么是深拷贝?什么是浅拷贝?有哪些深拷贝的方法?让你手写一个深拷贝方法,你会怎么写?
- `Vue`中有哪些常用的通信方案?
- 谈一谈你对事件总线的理解(“订阅-发布”模式)的理解?
- 以上九种通信方案之间的区别?或者任意两种通信方案之间的区别?(语法区别、使用场景的区别)
- 你做vue项目用的是哪个版本的脚手架?(v4/v5)怎么创建项目?(vue ui / vue create)
- 使用脚手架有什么好处?(有ESlint代码检测、有热更新、有单文件组织、背后还有webpack功能丰富)
- 什么是单文件组件?浏览器是怎么解析.vue代码?(vue-loader)
- 说一下history和hash路由有什么区别?
- 什么是命名视图、命名路由、别名?(<router-view name>、{path,component,name,alias})
- 说一下路由怎么传参?什么是动态路由?(两种传参。所谓动态路由,就是定义路由规则时path字段串中有冒号)
- 什么是路由守卫(导航守卫)?你项目的鉴权怎么做的?你这个管理系统的权限怎么设计的?
- 在Vue中做组件的显示与隐藏,有哪些方案?(v-show/v-if、<component>、路由或嵌套路由)
- 在Vue中,怎么监听路由的变化?(watch监听$route)
- 什么是单页面应用程序(SPA)?你怎么理解单页面应用程序?
- 简述Vuex的作用和意义?(基于Flux思想的状态管理工具,用于组件间数据通信、用于数据缓存)
- 简述Vuex的工作流程?(actions -> mutations -> state -> 组件)
- 什么是单向数据流?(state -> view -> action)
- 说一下状态管理的五个概念分别代表什么?说一下mutations和actions的区别?
- 其他
常用的vue指令有哪些?你怎么理解指令?
-
v-show指令 显示隐藏
-
v-if指令 v-else 条件显示
-
v-for 遍历渲染数据
-
v-text 文本 ,简写{{}}
-
v-bind 动态绑定,简写:
-
v-on 简写@,绑定事件
-
v-model表单输入元素或组件上创建双向绑定
封装好的方法,更加方便直接的操作dom的指令
v-if 和 v-show 有什么区别?
- 手段:v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;
- 编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;
- 编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
- 性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
文本插值有“{{}}一闪而过”问题,怎么处理?
- 加上v-cloak
v-for 可以循环哪些数据类型?
- Array | Object | number | string
v-for列表渲染时为什么加key?
1.vue中列表循环需加:key=“唯一标识” 唯一标识尽量是item里面id等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM。
2.key主要用来做dom diff算法用的,diff算法是同级比较,比较当前标签上的key还有它当前的标签名,如果key和标签名都一样时只是做了一个移动的操作,不会重新创建元素和删除元素。
3.没有key的时候默认使用的是“就地复用”策略。如果数据项的顺序被改变,Vue不是移动Dom元素来匹配数据项的改变,而是简单复用原来位置的每个元素。如果删除第一个元素,在进行比较时发现标签一样值不一样时,就会复用之前的位置,将新值直接放到该位置,以此类推,最后多出一个就会把最后一个删除掉。
4.尽量不要使用索引值index作key值,一定要用唯一标识的值,如id等。因为若用数组索引index为key,当向数组中指定位置插入一个新元素后,因为这时候会重新更新index索引,对应着后面的虚拟DOM的key值全部更新了,这个时候还是会做不必要的更新,就像没有加key一样,因此index虽然能够解决key不冲突的问题,但是并不能解决复用的情况。如果是静态数据,用索引号index做key值是没有问题的。
5.标签名一样,key一样这时候就会就地复用,如果标签名不一样,key一样不会复用。
v-model 有哪些修饰符?
vue 中怎么阻止冒泡?怎么阻止默认事件?怎么监听键盘enter键?
- 阻止冒泡 .stop
- 阻止默认事件 .prevent
- 监听键盘enter键 .enter
工作中你封装过自定义指令吗?举一些例子
-
可以使用Vue.directive() 或 directives选项来自定义指令。
v-focus
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
//注册局部指令
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
- 简单的如通过自定义指令转换元素内文本的大小写,数据的小数点保留位数v-longpress
- 需求:实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
思路 - 创建一个计时器,2 秒后执行函数当用户按下按钮时触发 mousedown 事件,启动计时器;用户松开按钮时调mouseout 事件。如果 mouseup事件 2 秒内被钟发,就清除计时器,当作一个普通的点未事件如里计时器没有在2秒内清除,则判定为一次长按,可以执行关联的函数。在移动端要考虑 touchstart,touchend 事件
- 需求:实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
- V-debounce
- 背景:在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱,比如新增表单的提交按钮,多次点击就会新增多条重复的数据。
- 需求:防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。
- 思路:
定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。将事件绑定在 click 方法上
1.防抖指令 v-debounce背景:在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱比如新增表单的提交按钮,多次点击就会新增多条重复的数据。需求:防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。思路:
定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。
将时间绑定在 click 方法上。
//js
const debounce = f
inserted: function (el,binding) {
Tet timer
el.addEventListener('keyup',() => [if (timer)f
clearTimeout(timer)
个
timer = setTimeout(O =>
binding.value(0)
},1000)
3
1
export default debounce
//使用: 给 Dom 加上 v-debounce 及回调函数即可
<tempTate>
<button v-debounce="debouncecTick">防抖</button></template>
计算属性有什么作用?(两大作用)
- 作用1:当指令的表达式比较复杂时,我们建议使用计算属性来优化,提升视图模板中代码的可阅读性、可维护性。
- 作用2:用于缓存一个复杂的运算,避免组件更新时产生没有必要的性能损耗。计算属性本质上是一个函数,Vue会分析函数体中使用到了哪些声明式变量,有且仅有这些声明式变量发生变化时,计算属性才会重新执行。
计算属性能不能绑定在v-model上?(可以)
怎么理解计算属性的缓存功能?
- 有且仅有被关联的声明式变量变化时,计算属性才会重新计算
说一下Vue的响应式原理?
https://juejin.cn/post/7021062174399283213
响应式原理
* 响应式reactive(当你get/set一个变量时,你可以“捕获”这个操作行为;就好比叫你一声,你会答应一样)
* 劫持(使用Object.defineProperty对data选项进行遍历并添加getter/setter钩子)
* touch(当指令第一次与声明式变量绑定时,第一次触发声明式变量的get钩子)
* 依赖收集(当第一次touch时,把当前声明式变量的更新方法watcher添加到dep依赖数组中)
* Watcher(与声明式变量对应的dom更新方法)
* re-render(当声明式变量被set时,Vue通知Watcher更新DOM,即重新渲染)
Vue的响应式原理(相关参考文章)
- 第一步,组件初始化,生命周期第一阶段,Vue使用Object.defineProperty()对data进行遍历劫持,添加get/set。执行touch,收集依赖,调用warcher,更新DOM,初始化页面
- 第二步,变量发生变化时,再次通过Wathcer渲染页面。
侦听器可以侦听什么?
- data 计算属性 vuex数据 $route(只要这个数据有__ob__都可以被侦听器)
- 作用: 监听到变化,然后去一些事件
- 特点: 默认情况下,只能侦听第一层,想深度侦听,deep:true(性能优化)
什么是组件化?你怎么理解组件化?
- 把页面拆分成多个组件
- 组件是可以复用性的
- 易于维护
- 有封装性,易于使用
- 大型项目中降低组件之间重复性
你工作中有没有封装比较好的组件?
https://blog.csdn.net/wanghaoyingand/article/details/122097424
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.layer {
background-color: rgba(0, 0, 0, .6);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.modal {
position: absolute;
top: 100px;
left: 50%;
width: 520px;
margin-left: -260px;
border-radius: 3px;
background-color: #fff;
}
header {
line-height: 50px;
box-sizing: border-box;
padding: 0 20px;
font-size: 14px;
overflow: hidden;
border-bottom: 1px solid #eee;
}
header>.title {
float: left;
font-size: 18px;
}
header>.close {
float: right;
cursor: pointer;
}
main {
box-sizing: border-box;
padding: 20px;
font-size: 14px;
}
footer {
line-height: 50px;
border-top: 1px solid #eee;
height: 50px;
}
footer>span {
float: right;
height: 30px;
line-height: 28px;
margin-right: 20px;
cursor: pointer;
display: inline-block;
padding: 0 20px;
margin-top: 10px;
border: 1px solid #ccc;
border-radius: 2px;
}
footer>span.primary {
border-color: blue;
background-color: blue;
color: white;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="show=true">累加器</button>
<lc-modal title="累加数" :show="show" @submit="onSubmit" @close="onClose" @add="onadd" @sub="onsub">
<template v-slot:one>
<div>
<span>累加数:</span>
<input type="text" v-model="num">
</div>
</template>
<template v-slot:two>
{{total}}
</template>
</lc-modal>
</div>
<script id="modal" type="x-template">
<div class="layer" v-if='show'>
<div class="modal">
<header>
<span class='title' v-text='title'></span>
<span class='close' @click="$emit('close')">X</span>
</header>
<main>
<slot name='one'> </slot>
<button @click='$emit("sub")'> - </button>
<slot name='two'> </slot>
<button @click='$emit("add")'> + </button>
</main>
<footer>
<span class="primary" @click="$emit('submit')">确定</span>
<span @click="$emit('close')">取消</span>
</footer>
</div>
</div>
</script>
<script>
Vue.component('lc-modal', {
template: '#modal',
props: {
title: {
type: String,
default: ''
},
show: {
type: Boolean,
default: false
}
}
})
let vm = new Vue({
el: "#app",
data() {
return {
num: 1,
show: false,
total: 10,
}
},
methods: {
onSubmit() {
this.num = ''
this.show = false
},
onClose() {
this.show = false
},
onadd() {
this.total += ~~this.num
},
onsub() {
this.total -= ~~this.num
}
},
});
</script>
</body>
</html>
父子组件之间如何通信?(父传子、子传父)
props、自定义事件、ref、事件总线、集中状态管理、v-model、provide inject、
r o o t 、 root、 root、attr、 l i n s e r s 、 linsers、 linsers、parent、$children、.sync、slot
什么是插槽?什么是具名插槽?
- 父组件调用子组件时,额外增加的内容
- 具名插槽就是有具体名字的插槽,子组件中与父组件相对应名字的内容将添加
在创建/挂载/更新/销毁阶段,Vue
在背后分别做了些什么事儿?
- 创建:声明methods中的方法和生命周期钩子函数
注入数据,初始化响应式系统
- 挂载:通el
$menout
template找模块
把模块变成render函数,创建虚拟DOM,虚拟DOM转化真实DOM,进行挂载
- 更新:生成新的虚拟DOM,新的虚拟DOM和老的虚拟DOM进行对比
执行path运算,diff
算法,找到两个虚拟DOM的最小差异,进行异步更新
- 销毁:移除当前组件的watcher,移除所有子组件,移除事件监听
Vue的生命周期
-
创建期间的生命周期函数:
- beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好data 和 methods 属性
- created:实例已经完成了模板的编译,但是还没有挂载到页面中
- beforeMount:此时已经完成了模板的翻译,但是还有完全挂载到页面中
- mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
-
运行期间的生命周期函数:
-
beforeUpdate:状态更新之前执行此函数,此时 data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点
-
updated:实例更新完毕之后调用次函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了
-
-
销毁期间的生命周期函数:
-
beforeDestroy:实例销毁之前调用,在这一步,实例仍然完全可用
- 当执行 beforeDestroy 钩子函数的时候,Vue实例就已经从运行阶段进入到了销毁阶段;当执行 beforeDestroy 的时候,实例身上所有的 data 和所有的 methods, 以及 过滤器、指令、、 都处于可用状态,此时,还没有真正执行销毁的过程
-
destroyed:Vue 实例销毁后调用。调用后,vue 实例 指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁
-
响应式原理,发生在Vue
哪些生命周期阶段?
init
阶段,创建阶段。- 更新阶段
虚拟DOM,在哪些阶段生成的?
- 挂载阶段
- 更新阶段
什么虚拟DOM?(是一个很大的JSON
数据,用于描述视图模板的,保存在内存中)
- 用
js
对象来表示真实的 DOM 树结构,真实dom
的一个js 对象
映射 - 频繁的操作 DOM,会产⽣⼀定的性能问题
- 在组件渲染的时候会调用
render
函数,这个函数会生成一个虚拟dom
,再根据这个虚拟dom
生成真实的dom
,然后这个真实的dom
会挂载到我们的页面中。 - 数据发生改变的时候 render 函数会生成一个新的虚拟
dom
新的虚拟dom
树和旧的虚拟dom
树进行对比,找到要要修改的虚拟dom
的部分,去修改相对应部分的真实dom
虚拟DOM存在的价值点在哪里?(更新,把DOM更新粒度降到最低,规避人为DOM滥操作)
- 避免直接操作DOM,提高开发效率
- 虚拟DOM作为一个中间层可以跨平台,除了在Web平台使用以外,还支持服务端渲染,以及
weex
框架可以跨移动端平台 - 提高性能
- 复杂视图情况下提升渲染性能,如果有频繁DOM操作的话,虚拟DOM在更新真实DOM之前,首先会通过
Diff
算法对比新旧两个DOM树的差异,最终把差异更新到真实DOM上,不会每次操作真实DOM,另外通过给节点设置Key属性,可以让节点重用,避免大量的重绘 (提高性能)
- 复杂视图情况下提升渲染性能,如果有频繁DOM操作的话,虚拟DOM在更新真实DOM之前,首先会通过
哪些场景下你会用到动态组件?
- keep-alive include exclude 还有两个新的生命周期钩子
- 一般用于需要根据数据动态渲染的场景或类似tab切换栏,即组件类型不确定
混入有什么优势,有什么缺点?
- 有点:解决选项的复用问题,简化代码
- 缺点:造成混乱,不容易维护
常用指令有哪些?你怎么理解指令?你工作是否自已封装过指令?
-
v-show v-if v-text v-model v-bind v- on v-for
-
指令本质上就是DOM功能的一种抽象封装
https://zhuanlan.zhihu.com/p/337659611
https://juejin.cn/post/6906028995133833230
举一个你封装自定义指令的例子
(权限指令、拖拽指令)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2 v-color="col">{{name}}</h2>
<input type="text" v-lcmodel="name">
</div>
<script>
Vue.directive('lcmodel', {
bind(el, binding, vnode) {
let { expression, modifiers } = binding
let { context } = vnode
let { lazy, trim, upper, number } = modifiers
el.value = context[expression]
el.addEventListener(lazy ? 'blur' : 'input', function (e) {
let val = e.target.value
if (trim) val = val.trim()
if (upper) val = val.toUpperCase()
if (number) val = parseFloat(val)
context[expression] = val
})
},
update(el, binding, vnode) {
}
})
let vm = new Vue({
el: '#app',
data() {
return {
name: 'lc',
col: 'red'
}
},
// 一个指令有两种写法
// 指令的底层都是操作DOM
directives: {
// 等价与bind + update两个钩子函数
// 'color': function (el, binding, vnode) {
// el.style.color = binding.value
// console.log(el);
// console.log(binding);
// console.log(vnode);
// },
'color': {
bind(el, binding, vnode) {
el.style.color = binding.value
console.log(11);
},
update(el, binding, vnode) {//更新时触发
el.style.color = binding.value
console.log(222);
},
}
}
})
</script>
</body>
</html>
复用真的好吗?
(对新手不太友好,复用太多,改bug,一个出问题,其它地方也会出问题,容易造成项目瘫痪。)
你有封装过Vue
插件?怎么封装的?封装过什么?
https://blog.csdn.net/qq_46038620/article/details/119205367
(有,老项目中封装的好用东西,以插件的方式搬到新项目中去)
请问 Vue.use()
有什么用?讲一讲它背后做了什么?
注册全局插件
vue.use()为注册全局插件所用,接收函数或者一个包含install属性的对象为参数,如果参数带有install就执行install, 如果没有就直接将参数当install执行, 第一个参数始终为vue对象, 注册过的插件不会重新注册。
// vue中如何封装插件,两种写法
// 1)const MyPlugin = { install(Vue){ } }
// Vue.use(Myplugin)
// 2)const Myplugin = function(Vue){ }
谈一谈你对 Vue.nextTick()
的理解?有什么用?
nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
nextTick()
和 updated() 的区别
1、使用场景不同。有时候只需要下一次更新DOM时触发。回调函数写在updated()里会导致每次数据改变、DOM更新时,回函数都会被触发。
2、触发顺序不同。响应式数据发生变化时,Vue会立刻将更新的全部微任务按照顺序(beforeUpdate() update() updated())插入到微任务队列中。之后Vue对虚拟DOM树进行更新。之后虚拟DOM树和真实DOM树进行对比更新。但此时浏览器不会立即渲染更新后的真实DOM树,而是会先清空微任务队列。在顺序执行微任务时,在updated()执行结束后会立即执行nextTick(), 即便后面还有别的微任务。因此执行顺序updated()在前,nextTick()在后。
Vue
响应式有没有缺陷呢?有什么缺陷?遇到这种问题你会怎么办?
在复杂的Vue应用中,如果声明式变量是引用数据类型,当你set操作这些复杂的引用数据类型时,视图不更新。
(比如直接通过修改数组下标,界面不会更新;类型为对象时,增加和删除,页面不会做出响应式)
解决方案,set操作完成后,立即调用 this.$forceUpdate()强调更新(强制re-render)有时候,this.$forceUpdate()也无法解决上述问题,对set操作的变量进行一行深复制。
什么是深拷贝?什么是浅拷贝?有哪些深拷贝的方法?让你手写一个深拷贝方法,你会怎么写?
深拷贝,就是深度遍历数据,深层拷贝数据,改变新的数据不影响旧的数据
浅拷贝,除了深拷贝都是浅拷贝
方法:`json`,递归函数, 用别人封装好的方法
function clone(source){
let newobj={};
for(let key in source ){
if(typeof source[key]==='object'){
newobj[key]=clone(source[key])
}else{
newobj[key]=source[key]
}
}
return newobj;
}
Vue
中有哪些常用的通信方案?
- 通过 props 传递
- 通过
$emit
触发自定义事件 - 使用 ref
EventBus
(中央事件总线)$parent
或$root
attrs
与 listeners- Provide 与 Inject
Vuex
- 插槽
参考地址面试官:Vue组件之间的通信方式都有哪些? | web前端面试 - 面试官系列 (vue3js.cn)
谈一谈你对事件总线的理解(“订阅-发布”模式)的理解?
-
借助于
Vue
内置的事件系统( o n / on/ on/emit/ o f f / off/ off/once)实现“订阅-发布”式的通信,这种通信方式是一种与组件层级无关的“一对多”的通信。 -
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
-
发布订阅模式主要有两个角色
-
发布方(Publisher):也称为被观察者,当状态改变时负责通知所有订阅者。
-
订阅方(Subscriber):也称为观察者,订阅事件并对接收到的事件进行处理。
-
-
发布订阅模式有两种实现方式:
- 简单的实现方式:由Publisher维护一个订阅者列表,当状态改变时循环遍历列表通知订阅者。
- 委托的实现方式:由Publisher定义事件委托,Subscriber实现委托。总的来说,发布订阅模式中有两个关键字,通知和更新。被观察者状态改变通知观察者做出相应更新。解决的是当对象改变时需要通知其他对象做出相应改变的问题。
以上九种通信方案之间的区别?或者任意两种通信方案之间的区别?(语法区别、使用场景的区别)
-
props和$emit
- 这是父子组件在传参时中常用的一种方式,父组件通过v-bind传入参数,子组件通过props来接收,子组件通过内建的$emit方法传入事件名来触发一个事件,父组件通过v-on像监听原生DOM事件一样来监听这个事件。
- 适用场景:适用于直接父子关系(中间无嵌套组件)的组件间进行通信。
-
$attrs
和$listeners
-
$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class
和style
除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件。 -
适用场景:组件之间跨级传参,可以使用
$attrs
属性,这样使得代码更加简洁,更利于维护。
-
-
ref
- 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的
$refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。 - 适用场景:当使用
element-ui
组件时,可用于调用组件方法,例如el-table
组件的选择表格项,排序等等。
- 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的
-
v-model
- 一个组件上的
v-model
默认会利用名为value
的 prop 和名为input
的事件,但是像单选框、复选框等类型的输入控件可能会将value
attribute 用于不同的目的。model
选项可以用来避免这样的冲突。 - 适用场景:
v-model
适用于在封装input
类型的组件时,用于给数据进行双向绑定.
- 一个组件上的
-
Sync修饰符
sync
与v-model
非常类似,也是适用于需要子组件改变父组件的值时。:isShow.sync="isShow"
其实是@update:isShow="bol=>isShow=bol"
语法糖
你做vue项目用的是哪个版本的脚手架?(v4/v5)怎么创建项目?(vue ui / vue create)
使用脚手架有什么好处?(有ESlint代码检测、有热更新、有单文件组织、背后还有webpack功能丰富)
- vue脚手架用于自动生成vue和webpack的项目模板;vue脚手架是一个快速构建vue项目的工具,可以自动安装vue所需要的插件,避免手动安装各种插件,以及寻找各种cdn并一个个引入的麻烦。
什么是单文件组件?浏览器是怎么解析.vue代码?(vue-loader)
- 单文件就是把一个页面拆分为多个,多层次的组件,通过多层引用大大缩短vue文件的长度和页面复杂度
- 使用
vue-loader
来转换(webpack的一个loader) - 解析转换.vue文件。提取出script,css,template,再分别交给对应的loader去处理。
说一下history和hash路由有什么区别?
1、hash路由再地址栏URL上有“#”,而history路由没有;
2、进行回车刷新操作时,hash路由会加载到地址栏对应的页面,而history路由一般会出现404错误;
3、hash支持一些低版本的浏览器,而history不支持。
什么是命名视图、命名路由、别名?(<router-view name>、{path,component,name,alias})
- 命名路由就是在routers配置路由的时候给路由取个名
- 命名视图:就是给不同的router-view定义不同的名字,通过名字进行对应组件的渲染
- 别名:就是取个别名
- redirect和alias的区别
- redirect:直接改变了url的值,把url变成了真实的path路径。\
- alias:url路径没有别改变,这种更友好,让用户知道自己访问的路径,只是改变了中的内容。
- redirect和alias的区别
说一下路由怎么传参?什么是动态路由?(两种传参。所谓动态路由,就是定义路由规则时path字段串中有冒号)
- 路由怎么传参:
- query传参:在跳转路由的url后面用?a=1&b=2&c=3这种方式传参,在另一个组件中使用this.$route.query接收。
- 动态路由传参:像这样
{path: '/good/:id', component }
定义路由规则,在这条动态路由规则对应的组件中使用this.$route.params接收,或者开启props:true后使用 props选项来接收。
- 动态路由:对路由的添加通常是通过
routes
选项来完成的
什么是路由守卫(导航守卫)?你项目的鉴权怎么做的?你这个管理系统的权限怎么设计的?
- 路由守卫:在router实例对象上有三个重要的全局钩子(beforeEach、beforeResolve、afterEach),每次url发生变化时,都会触发这三个钩子按顺序执行。那么以后我可以在这些钩子编写验证逻辑,如果验证通过就放你过去,你就可以正常访问你想访问的页面;如果验证失败,就阻止你访问目标页面,这就实现“守卫”的效用了。在路由中,使用导航守卫和路由元信息,可以做鉴权、还可以做权限设计。
在Vue中做组件的显示与隐藏,有哪些方案?(v-show/v-if、<component>、路由或嵌套路由)
在Vue中,怎么监听路由的变化?(watch监听$route)
什么是单页面应用程序(SPA)?你怎么理解单页面应用程序?
- SPA(single-page application),翻译过来就是单页应用
SPA
是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换打断用户体验在单页应用中,所有必要的代码(HTML
、JavaScript
和CSS
)都通过单个页面的加载而检索,或者根据需要(通常是为响应用户操作)动态装载适当的资源并添加到页面页面在任何时间点都不会重新加载
简述Vuex的作用和意义?(基于Flux思想的状态管理工具,用于组件间数据通信、用于数据缓存)
简述Vuex的工作流程?(actions -> mutations -> state -> 组件)
1. 在vue组件里面,通过dispatch来触发actions提交修改数据的操作。
2. 然后再通过actions的commit来触发mutations来修改数据。
3. mutations接收到commit的请求,就会自动通过Mutate来修改state(数据中心里面的数据状态)里面的数据。
4. 最后由store触发每一个调用它的组件的更新
什么是单向数据流?(state -> view -> action)
- 单向数据流指只能从一个方向来修改状态
说一下状态管理的五个概念分别代表什么?说一下mutations和actions的区别?
-
状态管理的五个概念
-
state: {} 用于定义可被组件共享数据,是具有响应式的;在组件中使用this.$store.state来访问它们。
-
getters: {fn} 用于计算state,相当于Vue的计算属性,当state发生变化时getters方法自动自动重新计算;在组件中使用this.$store.getters来访问它们。
-
mutations: {fn} 专门用于修改state的,所以mutations方法是这样fn(state,payload)定义的;mutations方法在actions中或组件中使用,使用$store.commit(‘mutations方法’,payload)
-
actions: {fn} 专门用于调接口的,所以actions方法是这样fn(store,payload)定义的;在组件中使用this.$store.dispatch(‘actions方法’, payload)。
-
modules: {子store} 是一个Vuex架构层面的概念,用于拆分子store。大家在拆分子store务必在子store中使用namespaced:true开启命名空间。
-
-
mutations和actions的区别
-
actions主要用于响应组件中的动作,通过 commit( )来触发 mutation 中函数的调用, 间接更新 state,不是必须存在的;mutations主要用于操作修改数据,是必须存在的;
-
actions可以进行异步操作,可用于向后台提交数据或者接受后台的数据;
mutations中是同步操作,不能写异步代码、只能单纯的操作 state ,用于将数据信息写在全局数据状态中缓存,不能异步操作;
-
其他
Vue中自定义事件的$event传参问题
- 在原生事件中, e v e n t 是事件对象,在自定义事件中, event是事件对象,在自定义事件中, event是事件对象,在自定义事件中,event是传递过来的数据(参数)
- 如果遇到子组件向父组件传数据,需要用到自定义事件来处理,此时我们在父组件上监听那个自定义事件,并且需要接收子组件传过来的参数,同时我们自己还想传递一个参数给下面方法