关于Vue

生命周期钩子函数


在 beforCreate 钩子函数调用的时候,是获取不到props或者data中的数据的,因为这些数据的初始化都在initState中。

然后执行created钩子函数,在这个钩子函数中就可以访问props和datas了,但是这时组件还没有挂载。

然后执行beforeMount钩子函数,开始创建VDOM,最后执行mounted钩子,并把VDON渲染成真实DOM并渲染数据。组建中如果有子组件的话,会递归挂载子组件,只有当所有子组件全部挂载完毕,才会还行根组件的挂载钩子。

数据更新时会调用的钩子函数beforeUpdate和Updated,这两个钩子函数分别在数据更新前和更新后会调用。

keep-alive独有的生命周期,分别为actived和deactivated。用keep-alive包裹的组件在切换时不会进行销毁,而是缓存在内存中并执行deavtived钩子函数,命中缓存渲染后会执行actived钩子函数。

最后是销毁组件的钩子函数beforeDestroy 和destroyed 。在beforeDestroy 中适合移除事件、定时器等等。否则可能引起内存泄露。然后进行一系列的销毁操作,如果有子组件,也会递归销毁子组件,所有子组件销毁完毕后会执行根组件的destroyed钩子函数。

组件通信


组件通信一般分为一下几种情况:

  • 父子组件通信
  • 兄弟组件通信
  • 跨多层级组件通信
  • 任意组件

父子组件通信

父组件通过props传递数据给子组件,子组件通过emit发送事件传递数据给父组件。

这种通信方式是单向数据流,父组件通过props传递数据,子组件不能直接修改props,而是必须通过发送事件的方式告知父组件修改数据。

还可以通过$parent或者$children来访问组件实例中的方法和数据。

兄弟组件通信

可以通过查找父组件中的子组件实现,也就是this.$parent.$children ,在$children中可以通过组件 name 查询到需要的组件实例,然后通信。

任意组件通信

可以通过Vuex和Event Bus解决。

mixin和mixins区别


mixin 用于全局混入,会影响到每个组件实例。

Vue.mixin({
  beforeCreat(){
    // 这种方式会影响每个组件的beforeCreate钩子函数
  }
})

mixins是最常用的扩展组件的方式。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过mixins混入代码。

mixins混入的钩子函数会先于组件内的钩子函数执行,并且遇到同名选项的时候会有选择性的进行合并。

computed和watch区别


computed是计算属性,依赖其他属性计算值,并且computed的值有缓存,只有当计算只变化才会返回内容。

watch监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。

一般来说需要依赖别的属性来动态获得值的时候可以使用computed,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用watch。

组件中 data 什么时候可以使用对象

组件复用时所有组件实例都会共享data,如果data是对象的话,就会造成一个组件修改data以后影响到其他所有组件,所以需要将data写成函数,每次用到就调用一次函数获得新的数据。

当使用new Vue()方式的时候,无论我们将data设置为对象还是函数都可以,因为new Vue()方式生成一个根组件,该组件不会复用,也就不存在共享data的情况了。

响应式原理

vue内部使用了Object.defineProperty()来实现数据响应式,通过这个函数可以监听到set和get的事件。

var data = {name : 'yck'}
observe(data);
let name = data.name;  // get value
data.name = 'yyy' // set value

function observe(obj){
  // 判断类型
  if(!obj || typeof obj !== 'object'){
    return;    
  }
  Object.keys(obj).forEach(key=>{
    defineReactive(obj, key, obj[key])
  })
}

function defineReactive(obj, key, val){
  observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,  // 可枚举
    configurable: true, // 可配置
    get: function  reactiveGetter(){
      return val
    },
    set : funtcion reacticeSetter(newVal){
      console.log("change value")
      val = newVal
    }
  })
}

只有执行了依赖收集,才能在属性更新的时候派发更新。

<div>{{name}}</div>

在解析如上模板代码中,会遇到{{name}}就会进行依赖收集

接下来我们实现一个Dep类,用来解耦属性的依赖收集和派发更新操作。

class Dep{
  constructor(){
    this.subs =[]
  }
  addSub(sub){ // 添加依赖
    this.subs.push(sub)
  }
  notify(){ //更新
    this.subs.forEach(sub=>{
      sub.update()
    })
  }
}
Dep.target = null // 全局属性,通过该属性配置Watcher

当需要依赖收集的时候调用addSub,当需要派发更新的时候调用notify。

Vue组件挂载时添加响应式的过程:

  1. 先对所有属性调用Object.defineProperty()
  2. 实例化Watcher,传入组件更新的回调(实例化工程中,会对模板中的属性进行求值,触发依赖收集)

触发依赖收集:

class Watcher{
  constructor(obj, key, cb){
    Dep.target = this;
    this.cb = cb
    this.obj = obj
    this.key = key
    this.value = obj[key]
    Dep.target = null
  }
  update(){
    this.value = this.obj[this.key]
    this.cb(this.value)
  }
}

此时需要对defineReactive函数进行改造

function defineReactive(obj, key, val){
  observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,  // 可枚举
    configurable: true, // 可配置
    get: function  reactiveGetter(){
      if(Dep.target){ //将Watcher添加到订阅
        dp.addSub(Dep.target)
      }
      return val
    },
    set : funtcion reacticeSetter(newVal){
      console.log("change value")
      val = newVal
      dp.notify()  // 执行watcher的update方法
    }
  })
}

下面测试一下代码:

var data ={name: 'yck'}
observe(data)
function update(value){
  document.querySelector('div').innerText = value;
}
new Watcher(data,'name',update);
data.name = 'xxx'

编译过程

Vue会通过编译器将模板通过几个阶段最终编译成render函数,然后通过执行render函数生成Virtual Dom 最终映射为真是的DOM。

编译过程可分为三个阶段:

  1. 将模板解析成AST
  2. 优化AST
  3. 将AST转换为render函数

第一阶段,最主要的事情还是通过各种各样的正则表达式匹配模板中的内容,然后将内容提取出来做各种逻辑操作,接下来生成一个最基本的AST对象

{
  type :1, // 类型
  tag, // 标签属性
  attrsList: attrs, //属性列表
  attrsMap : makeAttrsMap(attrs), //属性映射
  parent, //父节点
  children:[] //子节点
}

在这一阶段,还有一起其他的判断逻辑,比如对比前后开闭标签是否一致……

第二阶段,优化AST阶段,对阶段进行了静态内容提取,即将永远不会变动的节点提取出来,实现复用Virtual DOM。

最后阶段,主要是遍历整个AST,根据不同的条件生成不同的代码。

每张故作坚强的笑脸背后,是怎样风雨漂泊的一生---Lin

本文分享自微信公众号 - 女程序员的日常(gh_df41d619fb70),作者:凛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Vue.js的组件、组件间通信

    props定义了这个组件有哪些可配置的属性,props最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值。

    用户3258338
  • 温故知新-JS深拷贝

    用户3258338
  • http的options请求是什么鬼?

    哈喽,大家好,今天是正月十七,年算是真正的过完了,各位宝宝有没有胖三斤?不说不开心的!资本寒冬和倒春寒,各位宝宝记得套上大棉袄、二棉裤哦!

    用户3258338
  • 前端面试宝典(五)—— Vue

    MVVM是Model-View-ViewModel的简写,Model 层代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑;View 代表 UI...

    萌兔IT
  • 知乎 Android 客户端组件化实践

    知乎 Android 客户端最早使用的是最常见的单工程 MVC 架构,所有业务逻辑都放在了主工程 Module 里,网络层和一些公共代码分别被抽成了一个 Mod...

    用户1269200
  • Vue组件开发三板斧:prop、event、slot

    组件,有些可以完全独立运行完全不依赖外部属性,比如层级较高的页面组件。但大多时候,组件还是需要使用方做一些定制操作,并可以在状态变化时通知给使用方,于是,一个组...

    娜姐
  • –vue2.0父子组件及非父子组件间实现通信

    大象无痕
  • Vue中组件最常见通信的方式

      父组件通过prop的方式向子组件传递数据,而通过$emit子组件可以向父组件通信。

    前端迷
  • Vue.js 组件编码规范

    本规范提供了一种统一的编码规范来编写 Vue.js 代码。这使得代码具有如下的特性:

    最靓的崽
  • 基于 React 的可视化编辑平台实践

    前段时间发在朋友圈的一句话:各种自主搭建的平台,想起好多年各种DIY博客,行业门户网站,本质不变,变的是实现的手段了

    黄泽杰

扫码关注云+社区

领取腾讯云代金券