推荐网站:http://bigerfe.com/
这个网站是免费的,不但可以看面试题,也会在做题的过程收获很多
目录
## 2、methods、computed、watch的区别
## 8、vue2.x的响应式原理中Object.defineProperty有神魔缺陷,为神魔在3.0中采用了Proxy
## 9、在vue中子组件为何不能修改prop,如果修改了vue是如何监控到属性的修改并给出警告
## 1、vue的组件传值的方式
1)父->子,使用props [官方文档]
2)子传父 使用$emit() [官方文档]
3)使用BUS工具进行同一组件传值 ,创建一个工具类bus.js
4)还有一种通过$parent 和 $children进行应急访问,官方不推荐使用 [官方文档]
5)使用ref访问子组件或子实例 [官方文档]
6)使用vuex进行状态管理 例子
7)依赖注入(provide/inject)
测试小例:
//bus.js
import Vue from 'vue'
export default new Vue()
//子组件--lian1.vue
<template>
<div>
<h3>进行同级组件的值传递</h3>
</div>
</template>
<script>
import bus from "@/util/bus.js"
export default {
provide: {
name: "来自lianxi1的问候", //依赖注入
},
created() {
bus.page = "来自lian1组件的问候"
}
}
</script>
```
```
//子组件--lian.vue
<template>
<div>
<h2>{
{ mess }}</h2>
<button @click="mytest">测试</button>
</div>
</template>
<script>
import bus from "@/util/bus.js";
export default {
props: {
mess: {
type: String,
value: "",
},
},
inject: ['name'], //依赖注入
mounted() {
let page = bus.page;
console.log("收到" + page);
console.log(this.$parent, "父l");
console.log(this.$children, "子l");
console.log("lianxi页面已接收"+this.name)
},
methods: {
mytest1() {
console.log("测试$parent和$children");
},
mytest() {
this.$emit("mytest", "1111");
},
},
};
</script>
//父组件
<template>
<div class="home">
<lian :mess="mess" @mytest="mytest" ref="lianref"/> <lian1 />
<button @click="handleClick">test</button>
</div>
</template>
<script>
import lian from '@/components/lian.vue'
import lian1 from '@/components/lian1.vue'
export default {
name: 'home',
data() {
return {
mess:"测试父到子传值"
}
},
mounted() {
console.log(this.$refs.lianref)
console.log(this.$parent, "父");
console.log(this.$children, "子");
},
methods: {
handleClick() {
this.$children[0].mytest1()
},
mytest(e) {
console.log(e)
}
},
components: {
lian,
lian1
}
}
</script>
## 2、methods、computed、watch的区别
1)methods无缓存,每次调用都需要重新执行,对开销比较大的属性不友好
2)computed有缓存,且基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。适用于多对一
3)watch侦听,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的,即适用于一对多
使用:
//computed
computed:{
mycount() {
return this.count
}
}
//关掉缓存
mycount: {
cache: false,
get: function () {
return this.count+Date.now();
},
},
watch侦听 [官方文档]
watch不能监听到的情况 [官方文档]
**数组的变动
1)当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
解决:
data() {
return {
arr:[1,2,3],
obj:{ name:"小李",b:1 },
}
},
watch: {
arr(nv,ol) {
console.log(nv,ol)
},
obj(nv,ov) {
console.log(nv,ov)
}
},
methods: {
test1() {
this.$set(this.arr, 0, this.arr[0]++) //解决关键
//或 this.arr.splice(0, 1, ++this.arr[0])
}
},
2)当你修改数组的长度时,例如:vm.items.length = newLength
解决;
methods: {
test1() {
this.arr.splice(2) //解决关键
}
},
3)监听整个对象(可以监听到对象的单个属性),如果在监听时配置deep也可直接监听到,ps上述数组情况不可
methods: {
test1() {
//this.$set(this.obj,'b',5)使用这个方法直接监听原属性的变化,需要配置监听属性deep,否则由于嵌套的原因监听不到变化。
this.obj = Object.assign({}, this.obj, { name: '王' })
}
},
//watch的监听属性
obj: {
handler: function (val, oldVal) {
console.log(val, oldVal)
},
deep: true, //deep属性,该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
immediate: true //该回调将会在侦听开始之后被立即调用
}
## 3、vue的双向数据绑定原理
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。[具体的实现步骤]
>原文:https://www.cnblogs.com/zhangym118/p/8717999.html
>Object.defineProperty(obj,prop,descriptor)
参数:
obj:目标对象
prop:需要定义的属性或方法的名称
descriptor:目标属性所拥有的特性
可供定义的特性列表:
value:属性的值
writable:如果为false,属性的值就不能被重写。
get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。
set:一旦目标属性被赋值,就会调回此方法。
configurable: 如果为false,则任何尝试删除目标属性或修改属性性以下特性(writable, configurable, enumerable)的行为将被无效化。
enumerable: 是否能在for...in循环中遍历出来或在Object.keys中列举出来。
数据劫持:
当我们访问或设置对象的属性的时候,都会触发相对应的函数,然后在这个函数里返回或设置属性的值。即可以在触发函数的时候动一些手脚做点我们自己想做的事情,这也就是“劫持”操作。
## 4、vue的声明周期有哪些
[原址](https://juejin.cn/post/6844903858804621325#heading-2)
1)beforeCreate (创建前)vue实例的挂载元素和数据对象 data都是undefined, 还未初始化
2)created (创建后) 完成了 data数据初始化, 元素还未初始化
3)beforeMount (载入前) vue实例的元素和data都初始化了, 相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
4)mounted (载入后) 在el 被新创建的 vm.$el替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行前后台数据对接
5)beforeUpdate (更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
6)updated (更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
7)beforeDestroy (销毁前) 在实例销毁之前调用。实例仍然完全可用。
8)destroyed (销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
## 5、浅谈对MVVM的理解
[推荐博文]
推荐博文1:[涉及到脏数据检查、数据劫持的实现代码]
Model:数据模型,定义数据和业务
View:UI视图,负责数据的展示
ViewModel:监听Model中数据的改变并且控制视图的更新,处理用户交互的操作。
MVVM模式简化了界面与业务的依赖,解决了数据频繁更新。MVVM 在使用当中,利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化。
## 6、vue的父组件和子组件生命周期执行顺序
[引荐]
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父beforeUpdate->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
## 7、双向绑定和vuex是否冲突
解决:见[官方文档]
## 8、vue2.x的响应式原理中Object.defineProperty有神魔缺陷,为神魔在3.0中采用了Proxy
[推荐博文]
1)Object.defineProperty无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
2)Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。
3)Proxy不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
## 9、在vue中子组件为何不能修改prop,如果修改了vue是如何监控到属性的修改并给出警告
[来源]
问一答:[官方文档]
单向数据流,易于监测数据的流动,出现了错误可以更加迅速的定位到错误发生的位置。
问二答:
在initProps的时候,在defineReactive时通过判断是否在开发环境,如果是开发环境,会在触发set的时候判断是否此key是否处于updatingChildren中被修改,如果不是,说明此修改来自子组件,触发warning提示。
if (process.env.NODE_ENV !== 'production') {
var hyphenatedKey = hyphenate(key);
if (isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)) {
warn(
("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as component prop."),
vm
);
}
defineReactive$$1(props, key, value, function () {
if (!isRoot && !isUpdatingChildComponent) {
warn(
"Avoid mutating a prop directly since the value will be " +
"overwritten whenever the parent component re-renders. " +
"Instead, use a data or computed property based on the prop's " +
"value. Prop being mutated: \"" + key + "\"",
vm
);
}
});
}
## 10、vue的响应式原理
[官方文档]
当一个Vue实例被创建时,vue会遍历data选项的属性,用Object.defineProperty将它们转为getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把接触过的数据属性记录下来,之后当依赖项的setter被调用时,会通知watcher重新计算,从而使他关联的组件得以更新。