前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于Vue

关于Vue

作者头像
用户3258338
发布2020-02-25 16:30:51
6950
发布2020-02-25 16:30:51
举报

生命周期钩子函数


在 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 用于全局混入,会影响到每个组件实例。

代码语言:javascript
复制
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的事件。

代码语言:javascript
复制
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
    }
  })
}

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

代码语言:javascript
复制
<div>{{name}}</div>

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

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

代码语言:javascript
复制
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,传入组件更新的回调(实例化工程中,会对模板中的属性进行求值,触发依赖收集)

触发依赖收集:

代码语言:javascript
复制
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函数进行改造

代码语言:javascript
复制
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方法
    }
  })
}

下面测试一下代码:

代码语言:javascript
复制
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对象

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

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

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 女程序员的日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件中 data 什么时候可以使用对象
  • 响应式原理
  • 编译过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档