Vue-6-生命周期


Vue生命周期

虚拟节点

虚拟节点的概念,方便理解视图框架(Vue、React、小程序)

目前流行视图框架都是基于虚拟节点技术开发的

jq落伍是因为jq里DOM操作性能不好。

而视图框架 更新视图的最后一步是DOM操作,尽量以最低代价进行DOM操作,

视图框架如何进行最低代价的DOM操作 => 虚拟节点 => 虚拟节点的更新 => diff算法.

虚拟节点在描述一个标签时,都有3个最基本的属性 => 标签名,属性列表,子节点列表。

虚拟节点就是真实节点的js描述.(AST语法树)

Vue实例的虚拟节点:console.log(vm._vnode)

生命周期

Vue的生命周期 Vue实例从创建达到销毁的过程中的特定阶段

创建前,创建后,挂载前,挂载后 都只触发一次(在实例化的过程中)

生命周期图示:

你描述下Vue的生命周期.(Vue的钩子函数).

1:基本的回答 => 8个钩子函数的名字.(不懂英文说中午).

2:回答生命周期图示.(更详细).

new Vue实例化(组件实例化)

触发beforeCreate

通过Object.defineProperty给data数据设置数据劫持

触发created

判断有没有el选项.

如果有,继续判断有没有template选项

如果有template选项,则编译template

如果没有template选项,则编译el所在的标签

触发beforeMount

根据编译的虚拟节点生成真实节点vm.$el.并且用真实的新视图替换掉老视图

触发mounted.

如果没有el选项,则等待$mount方法触发,如果这个方法也没触发,则实例化失败.

创建期

创建期有 创建前beforeCreate() 和创建后created()两个函数

创建 给vue实例添加数据 给data设置数据劫持

创建前后即是数据劫持前后

new Vue({
  el: '#app',
  data: {
    msg: ''
  },
  // 创建前 => 没什么用.
  beforeCreate() {
    console.log('创建前');
    console.log('beforeCreate', this.$data); // undefined
  },
  // 创建后 => 一帮用于数据初始化。
  // 在这个构造函数内只能操作数据,不能操作视图.
  created() {
    console.log('创建后');
    console.log('created', this.$data);
    this.msg = '吴签';
  },
})

挂载期

挂载 新视图替换老视图

挂载前后 新视图出现前后

mounted 视图初始化

挂载都发生了什么事情?

  1. 编译template(把字符串模板编译成虚拟节点)
  2. 编译遇到指令和插值表达式,会进行求值(收集依赖)
  3. 把虚拟节点转为新视图,替换老视图

// created => 处理数据(默认处理一次)

// mounted => 处理视图(默认处理一次)

new Vue({
  el: '#app',
  data: {
    msg: '按钮'
  },
  template: `<button>{{msg}}</button>`,
  created() {
    console.log('created');
  },
  // 新视图挂载前 (老视图最终会被删除,数据不会显示在老视图上);
  beforeMount() {
    console.log('挂载前');
  },
  // 新视图挂载后.(数据显示到了视图上);
  mounted() {
    console.log('挂载后');
  }
})

销毁期

destroyed => 组件销毁后的善后处理,例如停止定时器

组件销毁只是让数据不去动视图更新,组件实例还在

因此在组件的定时器还会继续

const box = {
  template: `<h3>box组件--{{count}}</h3>`,
  data() {
    return { count: 0 }
  },
  // 销毁前
  beforeDestroy() {
    console.log('销毁前')
  },
  // 销毁后
  destroyed() {
    console.log('销毁后');
    // 销毁后关闭定时器
    clearInterval(this.id);
  },
  created() {
    console.log('创建后');
    // 记录当前的定时器id.
    this.id = setInterval(() => {
      // console.log(this.count);
      this.count++
    },1000);
  },
  mounted() {
    console.log('挂载后')
  }
}

视图更新过程

数据变化 => 导致视图更新 (响应式)

数据变化 => 先更新虚拟节点 => diff算法判断 => 最后更新真实节点。

更新真实节点

1:原地更新.(标签不增删,不移动,直接修改内容或者属性)

2:替换更新.(会增删,移动元素)

什么时候原地更新?什么时候替换更新?

1:比较更新前后的虚拟节点.(同级比较)

2:如果同级的tag一致,并且key一样,则表示更新前后是同一个标签,使用原地更新策略.

3:如果同级的tag或者key有一个不一样,则表示更新前后不是同一个标签,使用替换更新策略.

key

如果tag和key一致,就原地更新

只要给上不一样的key,则使用替换更新策略

以后v-for都要加key => 数据更新 和视图更新保持一致,需要加key,保证更新前后的key不一致

v-if和v-show

对于多次显示隐藏的标签,应该用v-show

对于只有一次显示隐藏的,应该用v-if

v-for和v-if的优先级

v-for优先级更高 => 不管有没有虚拟节点,都会循环 => 性能不好.不推荐v-for和v-if一起使用.

  <div id='app'>
   <ul>
      <li v-for='d in arr' v-if='d%2 === 0'>{{d}}</li>
   </ul>
   <ul>
     <li v-for='d in arr.filter(item => item%2 === 0)'>{{d}}</li>
   </ul>
   <ul>
     <li v-for='d in list'>{{d}}</li>
   </ul>
  </div>
const vm = new Vue({
  el: '#app',
  data: {
    arr: [111, 222, 333, 444]
  },
  computed: {
    list() {
      return this.arr.filter(item => item%2 === 0)
    }
  }
})