面试之 Vue 原理(一)

一、描述 Vue 组件生命周期

组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
组件的销毁操作是先父后子,销毁完成的顺序是先子后父。

加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted

子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程
父 beforeUpdate -> 父 updated

销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

二、描述组件渲染和更新过程

概念:
渲染组件时,会通过 Vue.extend 方法构建子组件的构造函数,初始化组件的时候会进行实例化。终手动调用 $mount() 进行组件挂载渲染。更新组件时会进行 patchVnode 流程.核心就是diff算法。
在这里插入图片描述
vue 组件渲染/更新过程

1、vue 组件初次渲染过程
在这里插入图片描述

  • 解析模板为 render 函数
    这部分是说vue 编译相关,也就是说把 vue 语法编译 成 js 语法,通过执行 vue-template-compiler 的 compiler 函数,得到 render
  • 触发响应式
    响应式关键 Object.defineProperty(),将模版初次渲染使用到的变量绑定到 Object.defineProperty() 中,首次渲染会 触发 getter
    在这里插入图片描述
    执行render 函数
    第一点说到已经得到render函数,现在要执行render函数, 将 vue 语法转成 h 函数的结果,也就是 vNode,后续进行一系列操作

2、vue 组件更新过程

在这里插入图片描述
3、完整流程图
首先从黄色部分开始,执行render函数,生成虚拟DOM数,此时监听数据变动,一旦变动,触发 setter 函数,通知watcher,重新执行render 函数,循环往复
在这里插入图片描述

三、Vue 组件如何通讯

1、父传子
props主要用于父组件传递数据给子组件,是你可以在组件上注册一些自定义特性。当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性。这样在子组件就可以使用该该值。请注意:所有的prop都使得期父子prop之间形成了一个单向下行绑定,即父级prop的更新会向下流动到子组件,但是反过来就不行,子组件不能改变父组件的状态。

**父组件代码**
<template>
    <header-box :title-txt="showTitleTxt"></header-box>
</template>
<script>
    import Header from './header'
    export default {
        name: 'index',
        components: {
            'header-box': Header
        },
        data () {
            return {
                showTitleTxt: '首页'
            }
        }
    }
</script>


**子组件代码**
<template>
    <header>
        {{thisTitleTxt}}
    </header>
</template>
<script>
    export default {
        name: 'header-box',
        props: {
            titleTxt: String
        },
        data () {
            return {
                thisTitleTxt: this.titleTxt
            }
        }
    }
</script>

每次父组件发生更新时,子组件中所有的prop都会被刷新为最新的值。

2、子传父
利用on和on和emit 即子组件利用一个事件来触发$emit来传递出去一个事件及参数,然后在父组件里绑定这个事件,然后处理这个事件,获取传递的参数
子组件改变父组件传递的props(你会发现通过props可传递复杂类型数据,可以通过子组件改变数据内容,不推荐使用,因为vue是规定props是单向绑定)
父组件可以在使用子组件的地方直接用 v-on来监听子组件触发的事件 。即父组件中使用 v-on绑定自定义事件,然后在子组件中使用

*通过$on,$emit*
**父组件代码**
<template>
    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
</template>
<script>
    import ButtonCounter from './buttonCounter'
    export default {
        name: 'index',
        components: {
            'button-conuter': ButtonCounter
        },
        data () {
            return {
                total: 0
            }
        },
        methods: {
            incrementTotal () {
                this.total++
            }
        }
    }
</script>


**子组件代码**
<template>
    <button @click="incrementCounter">{{counter}}</button>
</template>
<script>
    export default {
        name: 'button-counter',
        data () {
            return {
                counter: 0
            }
        },
        metheds: {
            incrementCounter () {
                this.$emit('increment')
                this.counter++
            }
        }
    }
</script>

$emit(eventName,data)触发事件,每个Vue对象实例都实现了事件接口,所以可以使用 o n ( e v e n t N a m e ) 监 听 事 件 , 使 用 on(eventName)监听事件,使用on(eventName)监听事件,使用emit 来触发事件.父组件挂载的时候,为该子组件绑定监听事件,子组件中还是通过 $emit 来触发事件。

3、非父子

创建一个空的vue实例,然后挂载到当前的vue实例的原型上,然后一个组件进行e m i t 传 递 事 件 以 及 需 要 传 递
的 数 据 。 在 另 一 个 组 件 那 里 就 可 以 进 行 使 用
emit传递事件以及需要传递的数据。在另一个组件那里就可以进行使用emit传递事件以及需要传递的数据。在另一个组件那里就可以进行使用on来接受这个事件并处理这个传递参数

let bus =new Vue()
Vue.prototype.bus = bus

4、组件间通信:Slot

四、为何 v-for 中要用 key

key 是 Vue 使用 v-for 渲染列表时的节点标识。使用了 key 之后,当列表项发生变化时,Vue 会基于 key
的变化而重新排列元素顺序,并且移除 key 不存在的元素,提升运行效率。

key的作用:key是为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一的key属性。

注意:key的取值必须是number 或 string,不能是对象,而且使用 v-for 循环的每一项的值,都要保证唯一性 。

五、重中之重、Vue的双向数据绑定原理是什么?

vue.js
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调

具体步骤:

  • 第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
    这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
  • 第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  • 第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
    1、在自身实例化时往属性订阅器(dep)里面添加自己
    2、自身必须有一个update()方法
    3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发 Compile中绑定的回调,则功成身退。
  • 第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化
    -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小 Ziyi.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值