再读vue2.x文档总结的常用到的以及面试会用到的知识点

推荐网站:http://bigerfe.com/
这个网站是免费的,不但可以看面试题,也会在做题的过程收获很多

目录

## 1、vue的组件传值的方式

## 2、methods、computed、watch的区别

## 3、vue的双向数据绑定原理

## 4、vue的声明周期有哪些

## 5、浅谈对MVVM的理解

## 6、vue的父组件和子组件生命周期执行顺序

## 7、双向绑定和vuex是否冲突

## 8、vue2.x的响应式原理中Object.defineProperty有神魔缺陷,为神魔在3.0中采用了Proxy

## 9、在vue中子组件为何不能修改prop,如果修改了vue是如何监控到属性的修改并给出警告

## 10、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重新计算,从而使他关联的组件得以更新。


 

猜你喜欢

转载自blog.csdn.net/qq_41687299/article/details/112211514
今日推荐