vue知识点

322 阅读7分钟

总结一下vue重点,做复习之用

  1. mvvm双向数据绑定原理
当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 都加上 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变更的双向绑定效果
  1. vue不能新增不存在的属性,不存在的属性没有getter和setter

  2. vue的Virtual DOM

    Virtual DOM这个概念产生前提示浏览器dom是很昂贵的,浏览器标准把dom设计的很复杂,我们频繁的更新dom,会产生一定的性能问题,Virtual dom就是用原生的JS对象描述DOM

1. 无论我们写.vue文件还是写了template属性,最终都会转化为render方法,调用原型上的$mount进行挂载
2. render函数用来创建VNode, render函数接受一个createElement方法作为第一个参数用来创建vnode
  1. DOM DIFF
对比算法
1. 当对比两棵树时,React首先比较两个根节点。根节点的type不同,其行为也不同。每当根元素有不同类型,React将卸载旧树并重新构建新树。从<a>到<img>或从<Article>到<Comment>,或从<Button> 到 <div>,任何的调整都会导致全部重建。当树被卸载,旧的DOM节点将被销毁。组件实例会产生
2. 当比较两个相同类型的React DOM元素时,React则会观察二者的属性,保持相同的底层DOM节点,并仅更新变化的属性。
3. React支持了一个key属性。当子节点有key时,React使用key来匹配原本树的子节点和新树的子节点。
  1. 请详细说下你对vue生命周期的理解?
创建前/后: 在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,$el还没有。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法。

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
  1. DOM 渲染在 哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
  1. v-if和v-show区别
v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐;
  1. 减小首屏代码体积,我们用异步组件
  2. 组件上监听原生事件native
  3. a: {name: {age: 123}} 改变age能触发视图更新是Object.defineProperty实现setter和getter
  4. 用key 管理可复用的元素
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>
不加key替换时只会换placeholder

监听浏览器关闭事件

// 关闭页面提醒
export default {
  created () {
    // 监听浏览器关闭事件
    window.onbeforeunload = function (e) {
      var dialogText = '离开网站将不保存您所做的更改'
      e.returnValue = dialogText
      return dialogText
    }
  },
  destroyed () {
    // 解除监听浏览器关闭事件
    window.onbeforeunload = null
  }
}

class和style绑定

class绑定一个对象
1. <div v-bind:class="{ active: isActive }"></div>
2. <div v-bind:class="classes"></div>
data: {
    isActive: true,
    hasError: false
}

绑定一个数组,数组中可以加三木运算和对象
3. <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
4. <div v-bind:class="[{ active: isActive }, errorClass]"></div>

style绑定
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

<div v-bind:style="styleObject"></div>
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>

watch高级用法

<div>
      <p>FullName: {{fullName}}</p>
      <p>FirstName: <input type="text" v-model="firstName"></p>
</div>

new Vue({
  el: '#root',
  data: {
    firstName: 'Dawei',
    lastName: 'Lou',
    fullName: ''
  },
  watch: {
    firstName(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    }
  } 
  
  //
  watch: {
  firstName: {
    handler(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    },
    // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
    immediate: true
  }
})

// watch还有deep
watch: {
  obj: { // js的内存地址不变
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true,
    deep: true // 深度监听
  }
} 
deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。

watch: {
  'obj.a': {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true
  }
} 

vue不能更改一下情况

数组:
当你利用索引直接设置一个项时
当你修改数组的长度时

对象:
Vue 不能检测对象属性的添加或删除:

v-model的修饰符:.lazy, .number, .trim

.sync 修饰符

过渡

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

插件

import Vue from 'vue'

function log (message) {
  if (process.env.NODE_ENV !== 'production') {
    window.console.log(message)
  }
}

const ConsolePlugin = {
  install(vue, options) {
    Vue.prototype.$console = log
  }
}

export default ConsolePlugin

new Vue的过程

Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。

v-model实现

<input v-bind:value="ying" v-on:input="ying=$event.target.value">

Vue项目点击浏览器返回,返回至指定的页面

 beforeRouteLeave(to, from, next){
  if(to.name ==='D' ){
    next({name: 'G'});
  }else {
    next(); // 注意:这边next必须要写
  }
},

Object.defineProperty和Proxy区别

Object.defineProperty() 的问题主要有三个:
不能监听数组的变化
必须遍历对象的每个属性
必须深层遍历嵌套的对象
Proxy 在 ES2015 规范中被正式加入,它有以下几个特点:
针对对象:针对整个对象,而不是对象的某个属性,所以也就不需要对 keys 进行遍历。这解决了上述 Object.defineProperty() 第二个问题
支持数组:Proxy 不需要对数组的方法进行重载,省去了众多 hack,减少代码量等于减少了维护成本,而且标准的就是最好的。
除了上述两点之外,Proxy 还拥有以下优势:
Proxy 的第二个参数可以有 13 种拦截方法,这比起 Object.defineProperty() 要更加丰富
Proxy 作为新标准受到浏览器厂商的重点关注和性能优化,相比之下 Object.defineProperty() 是一个已有的老方法。

路由类型

全局守卫
路由独享守卫
路由组件内的守卫

beforeDestory和 destoryed

beforeDestory() 和 destoryed() 前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行

this.$nextTick

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:

async () => {
    await this.$nextTick()
}

mixins

mixin的混入策略可以简单的理解为以下几点
1.数据对象,data中的属性,会进行递归合并,类比es6的展开运算符,如果mixin中存在的,泽一组件定义的数据优先。

2.同名的钩子函数会合并数组,如mounted ,如果组件和mixin都定义了,则都会执行,且组件内定义的后置。即混入的代码会优先执行。

3.同名的函数会覆盖。类似data中的属性,会将组件内函数和mixin中函数递归合并,同名覆盖,这点类似于es5的,同名函数覆盖,组件内函数覆盖混入函数。

Vue 组件 data 为什么必须是函数

每个组件都是 Vue 的实例。
组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他。

计算属性

计算属性是可以依赖另外一个计算属性的

new Vue 发生了什么

前面已经介绍的都是Vue源码的一下细节,这一篇是对前面的一个总结以及梳理。
具体的一下细节,可以看前面的文章。
在执行new Vue()后,Vue先初始化数据:
initLifucycle :规格化 option && 初始化属性
initEcents :把父组件在子组件上绑定的自定义事件传递到子组件中
beforeCreated :执行生命周期函数
initJections:读取 jections 如果有的话
initStates:初始化 props 、methods、data 、computed 、watch
initProvide:初始化 provide
created:执行生命周期函数
模板编译 :把模板编译成渲染函数
beforeMount :执行生命周期函数
Watcher 渲染函数:当渲染函数里面的数据变化会通知 Watcher 实例更新
mounted :挂载实例 替换 el
到此页面就已经渲染到页面上。接下来就是当数据更新时,更新DOM,以及卸载实例。