前端八股文
# 1.什么是单向绑定?什么是双向绑定?
- 单向绑定:修改data中初始化的数据,则Vue管理的页面的模板中的数据随之发生改动,这就叫单向绑定,也被称之为数据实现了可响应式,大虎子表达式和指令语法中的指令都支持单向绑定(数据可响应式)
- 双向绑定:修改Vue管理的模板中的数据,则data初始化的值随之发生改动,这就叫双向绑定,v-model天生支持双向绑定,其它数据如果想支持双向绑定则必须使用计算属性
# 2.什么MVVM思想
- 根据技术的特点将其分为三层
- M:model(模型层):就是指data中封装的各种数据
- V:view(视图层):就是指页面的模板
- VM:viewmodel(视图模型):就是指我们创建的Vue实例
- Vue提供了一种MVVM绑定思想,当我们修改M层中的数据时,通过VM层可以同时修改绑定在V层上的数据(单向绑定,数据的可响应式),当我们修改V层中的数据时,则通过VM层可以同时修改M层中的数据(双向绑定)
# 3.在Vue2中函数 计算属性 侦听器的不同 使用场合
- 函数
- 多绑定激发事件 也可以绑定v-model直接调用 或者调用在大胡子表达式中 只有单向绑定功能无法实现双向绑定 函数没有缓存机制 只要被调用 不管数据是否发生更改都会执行 注意平时我们如果绑定事件 没有参数 则函数没有括号 @click="demo"
- 计算属性
- 依赖现有的属性(初始化的值)通过计算返回一个新的属性,这个属性是最终计算得来的也会被看做一个属性初始化在Vue实例根属性中,只要依赖的属性发生了更改,则计算属性重新执行,计算属性存在缓存机制,只要依赖属性没有发生变化,则不会再次执行,仅仅读取缓存中已经计算出的值,在页面中如果存在多个相同的计算属性,则效率大大高于多个相同的函数,计算属性可以同时支持单双向绑定功能,getter函数代表单向,setter函数代表双向功能
- 侦听器
- 一般不考虑单双向绑定问题,用来侦听某个值的变换,只要这个值发生更改,则侦听器执行,如果设置了immediate属性,则可以立即执行侦听器,侦听器默认只能侦听基本数据类型,如果要侦听复杂类型,则必须添加 deep:true 开启深度侦听功能
- 计算属性能做的事 侦听器都能做 侦听器能做的事 计算属性不一定能做 由于计算属性在书写单向绑定时必须书写return 所以无法书写异步代码
# 4.Vue如何进行样式渲染
使用 Vue 来渲染样式主要存在两种思路
- 绑定class
- :class="初始化的值" 这个初始化的值对应的是类名
- :class = "{类名:初始化的值,类名:初始化的值...}" 如果初始化的值为真值 则类名存在 假值类名不存在
- :class = "[类名1,类名2]" 每一个类名都会进行匹配
- 绑定style
- :style = "{样式名:绑定的值,样式名:绑定的值}" 样式名必须使用小驼峰格式
# 5.Vue条件渲染中 v-if 与 v-show 的区别
- v-if:如果后面绑定的值是真值,则元素显示,如果是假值,则底层不渲染,页面不显示可以取反,由于切换时会导致元素底层的切换,所以一般适用于切换不频繁的场合,因为切换时消耗较大,另外v-if还可以搭配v-else-if 与 v-else使用,通过template标签可以实现复杂逻辑的流程控制
- v-show:如果后面绑定的值是真值,则元素显示,如果是假值,则底层依然渲染,页面不显示,只不过是添加了一个行内式 display:none; 来隐藏元素,可以取反,初始载入消耗较大,之后切换消耗较少,适用于切换频繁的场合,不能与 v-else-if v-else连用
# 6.Vue2中事件原型如何使用 如何获取元素节点
如果一个函数没有任何参数,则函数自动从底层传递一个事件原型
如果一个函数存在实参,则不再自动传递事件原型,如果需要事件原型,则我们必须手动传递事件原型的实参 $event
event:形参 表示事件原型 demo(event){ event:就表示这个激发的事件 event.target:就表示这个事件的目标,这里也就是button元素节点 },
# 7.请列举Vue2中的常用事件修饰符
一般存在多种书写方式格式: @事件.事件修饰符="" 是对事件的一个补充
@事件.stop:防止事件冒泡影响 当父子都存在同一个激发事件时 会一层层的被调用
@事件.prevent:屏蔽特定元素本身固有的功能,例如 链接 和 表单的同步提交
@事件.once:事件仅仅激发一次
@事件.capture:使用事件的捕获模式 在最外层开始调用
@事件.self:只有event.target是当前操作的元素时才触发事件;
keyup:键盘键位抬起 keydown:键盘键位落下 @keyup.键位名="" 只要特定键位满足条件,例如这里是键盘键位抬起,则激发后面的函数 @keyup.enter 回车 @keyup.space 空格
# 8. Vue2中如何实现对象的可响应式,数组的可响应式
实现对象的可响应式 -- 以下书写方式可以实现对象属性的可响应式
this.$set(对象,'属性名','属性值')
实现数组的可响应式 -- Vue2中只允许使用 以下七个函数对数据进行操作
push() splice() reverse() sort() unshift() shift() pop()
注意这七个与js数组七函数不是同一个,而是作者根据原先七个重新封装的函数,仅仅是重名而已 Vue3不再局限这七个函数
2
3
4
5
# 9. 请简单介绍下Vue2中的数据劫持 与 数据代理
Vue实例对我们书写的data对象到底做了什么 STEP1: 对封装初始化数据的-进行了一个叫做数据劫持的工作,将data中每一个属性(包括内部子属性等) 全部实现了可响应式功能,之后将其封装在Vue实例中的 _data 中 只有实现了可响应式的数据才能实现修改数据,则模板中的数据发生改动,这也叫 单向绑定 data => _data 数据劫持
STEP2: 由于 _data 中的属性值并不是 Vue实例的根属性,所以在使用 插值语法必须添加 _data前缀 例如 ,这在开发中是非常不方便的,之后Vue实例通过 数据代理,将_data中的数据代理到 Vue的根属性中,这样直接可以在模板中使用 _data => 根属性 数据代理
# 数据代理
通过一个对象对另外一个对象中属性的操作 (读/写) 称之为数据代理
使用 Object.defineProperty() 给一个对象添加属性值
# 数据劫持 实现了内部属性可响应式
用户书写的 data 对象仅仅是一个普通的对象,没有任何可响应式功能,Vue实例对我们写的这个data进行了一个封装,在这个封装过程中添加了可响应式功能,其实就是数据更改,则页面模板随之发生更改(单向绑定)之后我们被封装的添加了可响应式功能的 data变为 _data
let obs = new Observer(data)
/* 模拟Vue实例 */
let vm = {}
/* Observer的构造函数 */
function Observer(obj) {
/* 拿到传入对象的所有属性名 ['name','address'] */
let keys = Object.keys(obj)
keys.forEach(k => {
/* this:就是这个对象 */
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(newVal) {
console.log(`${k}被修改啦!!,可响应式启动,我要去重新渲染页面模板中的数据了之后生成虚拟DOM,最终被真实DOM覆盖`)
obj[k] = newVal
}
})
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 10. Object.defineProperty()如何给一个对象添加属性值
Object.defineProperty(vm,'name',{
/* 如果读取vm中的name属性,则执行方法 */
get(){
console.log('我是getter函数,我要读取name啦------')
return _data.name
},
/* 如果修改vm中的name属性,则执行此方法,newVal就是更改后的值 */
set(newVal){
console.log('我是setter函数,我要修改name啦------')
_data.name = newVal
}
})
2
3
4
5
6
7
8
9
10
11
12
# 11. 请简述所有你用过的 指令元素
Vue的各种指令只能使用在标签上,绑定的值不是必须
1.v-bind:给元素绑定属性
格式: <tagName v-bind:属性名="初始化的数据" />
语法糖: <tagName :属性名="初始化的数据" />
2.v-on:给元素绑定事件 一般都是跟函数 但是简单逻辑的操作也可
格式:<tagName v-on:事件="函数" />
语法糖: <tagName @事件="函数" />
3.v-html:给元素绑定数据,且该指令可以解析html标签
注意 在前端开发中为了防止网络XSS攻击,禁止使用v-html执行脚本只能插入html或者css
4.v-text:给元素绑定数据(超文本),不解析标签
5.v-model:数据双向绑定
6.v-once: 一次性绑定,之后失去单向绑定功能
7.v-for:遍历数组
v-for="(alias,index) in 数组"
alias:别名
index:索引,可以不写,如果不写小括号省略
in:可以替换of
数组:必须是初始化的数据
8.v-if:条件渲染指令,动态在DOM内添加或删除DOM元素
根据绑定的值的真假 用啦判断是否显示该标签
8.v-else:条件渲染指令,必须跟v-if成对使用
9.v-else-if:判断多层条件,必须跟v-if成对使用
多搭配Vue中提供的 template标签使用,此标签并不会在页面中被浏览器解析不会存在任何结构
10.v-show: 与v-if功能一致 区别就是v-show不会对dom进行删除操作只是在标签上添加了一个行内式 display:none; 进行隐藏
11.v-cloak:解决插值闪烁问题 在真实dom出现之前 都会隐藏 vue开始工作后就会进行显示
<style>
[v-cloak] {
display: none;
}
</style>
12.v-pre:跳过这个元素以及子元素的编译过程,以此来加快整个项目的编译速度
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 12. v-for会出现什么问题?
当使用v-for迭代数组时,如果出现从数组头部插入数据,并且插入之后存在输入功能时,则有可能引入 diff算法中的就近策略导致的bug出现选择错误 为了杜绝这个bug的出现,则绑定一个属性 key 这个key后面绑定的是主键
# 13. 请说出如何使用Vue创建自定义指令
在Vue中允许我们自己设置指令元素从而实现我们自己的需求 自定义指令名 不能包含 v- 因为我们自己定义的指令元素名会自动添加 v-前缀 自定义指令分为全局自定义和局部自定义 全局自定义:不限定在哪个Vue实例管理的模板中 局部自定义:必须书写在固定的某个Vue实例管理的模板中
1:全局自定义指令,凡是全局的设置必须书写在我们自己创建得Vue实例之前
Vue.directive('指令名',{
//渲染样式
bind(el){
// el:element的简写就表示书写我们自定义指令得元素节点
},
//渲染动作
inserted(el,binding){
//binding:就表示我们得自定义指令 v-etoak
//binding.value:就表示我们自定义指令v-指令后面绑定的值
}
})
2
3
4
5
6
7
8
9
10
11
12
new Vue({
/* 2:局部自定义指令,只能书写在某一个特定的Vue实例中,并且只能管理这个实例管理的模板 */
directives:{
/* 指令名 */
指令名:{
//渲染样式
bind(el){
// el:element的简写就表示书写我们自定义指令得元素节点
},
//渲染动作
inserted(el,binding){
//binding:就表示我们得自定义指令 v-etoak
//binding.value:就表示我们自定义指令v-指令后面绑定的值
}
}
}
}).$mount('#app2')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 14. 请说出如何使用Vue对数据进行过滤,应该注意什么?
过滤器你要知道的的细节
1:过滤器当中不能使用this,this指向undefined,我们无法使用this获取整个Vue实例中的数据
2:过滤器不能与v-model连用,因为不支持双向过滤器
3:Vue3完全删除了过滤器
new Vue({
// 过滤器
filters:{
过滤器名(被过滤的值){
return 处理后的结果
}
}
})
2
3
4
5
6
7
8
9
10
11
12
待续...