Vue响应式原理

Vue是MVVM(Model-View-ViewModel)架构,响应式核心是通过Object.defineProperty拦截对数据的访问和设置

响应式数据分为两类:

注:

methods、computed和watch的区别

使用场景:

区别:

Vue的异步更新机制是如何实现的

Vue的异步更新机制的核心是利用了浏览器的异步任务队列来实现的,首选微任务队列,宏任务队列次之。

当响应式数据更新后,会调用dep.notify方法,通知dep中收集的watcher去执行update方法,watcher.update将watcher自己放入一个watcher队列(全局的queue数组)

然后通过nextTick方法将一个刷新watcher队列的方法放入一个全局的callbacks数组中

如果此时浏览器的异步任务队列中没有一个flushCallbacks的函数,则执行timerFunc函数,将flushCallbacks函数放入异步任务队列。如果异步任务队列中已经存在flushCallbacks函数,等待其执行完成以后再放入下一个flushCallbacks函数

Vue的nextTick API是如何实现的

Vue.nextTick或者vm.$nextTick是利用Event loop事件线程去异步操作,原理其实是做了两件事:

Vue.use(plugin)做了什么

负责安装plugin插件,其实就是执行插件提供的install方法

Vue.set(target, key, val) 做了什么

由于Vue无法探测普通的新增property,所以通过Vue.set向响应式对象中添加一个property,可以确保这个新property同样是响应式的,且触发视图更新。

SPA单页面的实现方式

SPA单页应用的理解

SPA(single-page application)仅在Web页面初始化加载相应的HTML、JavaScript和CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载和跳转;取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载。

优点:

缺点:

Vue SEO方案

Vue SPA单页应用对SEO不友好,当然也有解决方案:

Vue中Watch高级用法deep和immediate

watch默认绑定,页面首次加载时,是不会执行的。只有值发生改变才会执行。指定immediate为true则可以立即执行。

watch: {
  name: {
    handler(newVal, oldVal) {
      // 执行代码
    },
    immediate: true       // true表示立即执行
  }
}

如果监听的是对象类型,当手动修改对象的某个属性时,发现是无效的。这时就需要deep属性

data: {
  obj: {
    a: 1
  }
},
watch: {
  obj: {
    handler(newVal, oldVal) {
      // 执行代码
    },
    deep: true  // true表示深度监听,这时候就可以监测到a的变化
  },
  'obj.a': {        // deep优化,用字符串的方式来取代深度监听(一个个遍历,很学浪费性能)
    handler(newval, oldVal) {

    }
  }
}

route和router的区别

route是"路由信息对象",包括path、params、hash、query、fullPath、matched、name等路由信息。而router是"路由实例"对象包括了路由的跳转方法,钩子函数等

Vue生命周期

父子组件生命周期: 父beforeCreate => 父created => 子beforeCreated => 子created => 子mounted => 父mounted

keep-alive

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。2.1.0版本后,keep-alive新加入三个属性:

keepalive是一个抽象的组件,缓存的组件不会被mounted,为此提供activated和deactivated钩子函数 页面第一次进入,钩子的触发顺序: created => mounted => activated。退出时触发deactiveated 当再次进入(前进或后退)时,只触发activated 事件挂载的方法等,只执行一次的放在mounted中; 组件每次进去执行的方法放在activated中

v-for中的:key

使用v-for更新已渲染的元素列表时,默认用就地复用策略,列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素。

我们经常使用index(数据的下标)来作为key,但其实这是不推荐的做法。如果在数据中插入一条数据,该条数据后的所有数据都需要更新(key发生了变化)

自定义指令

类似v-model和v-show,例如实现一个自动获取焦点的全局自定义指令:

Vue.directive('focus', {
  inserted: function (el) {
    el.focus();
  }
})

也可以在组件中注册局部指令:

directives: {
  focus: {
    inserted: function (el) {
      el.focus();
    }
  }
}

钩子函数:

v-model原理

语法糖:value+@input。分两种情况:

<input v-model="val">
<!-- 基本等价于,因为内部还有一些其他处理 -->
<input :value="val" @input="val = $event.target.value">

两个方向:

<input v-model="val">
<!-- 等价于 -->
<input v-bind:value="val" v-on:input="val=$event.target.value">

v-for和v-if不建议同时使用

v-for比v-if优化级高,所以使用的话,每次v-for都会执行v-if,造成不必要的计算,影响性能。

Vue的单向数据流

指数据一般从父组件传到子组件,子组件没有权利直接修改父组件传来的数据。

Vue2和Vue3的响应式原理

Vue2的响应式原理是靠Object.defineProperty实现。Vue3是通过Proxy来实现的。

Vue2中Object.defineProperty

Vue2响应式实现

Object.defineProperty(obj, prop, {
  get() {
    return value;
  },
  set(newValue){
    if (newValue === value) return;
    value = newValue;
    update();
  }
})