1. 什么是Vue生命周期
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
分为三个阶段:初始化、运行中、销毁。
beforeCreate : 实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作
Created : 挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取
beforeMount : 接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取
Mounted : 接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情...
beforeUpdate : 当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿
Updated : 当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom
beforeDestroy : 当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等
Destroyed : 组件的数据绑定、监听...去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以
2. 钩子函数的的实际应用
beforecreate : 举个栗子:可以在这加个loading事件
created :在这结束loading,还做一些初始化,实现函数自执行
mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
beforeDestroy: 你确认删除XX吗? destroyed :当前组件已被删除,清空相关内容
3. 说一下 Vue 的双向绑定数据的原理
vue 实现数据双向绑定主要是: 采用数据劫持结合“发布者 - 订阅者”模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter、 getter,在数据变动时发布消息给订阅者,触发相应监听回调。
Vue的双向数据绑定主要通过Object.defineProperty来实现,先为所有的属性加上get/set的监控,这样当属性值改变时就会触发对应的set方法,然后再在set方法中通过观察者来更新视图,同时在get方法中进行依赖收集。
var obj = {
name: 'hcc',
age: 18,
yanzhi: 99.9
}
// Obejct.defineProperty: 可以给对象增加一个新的属性, 修改一个对象属性的的描述
// 参数1: 需要修改的对象
// 参数2: 需要修改的属性
// 参数3: 描述信息
let temp = obj.yanzhi
Object.defineProperty(obj, 'yanzhi', {
// writable: false, // 该属性是否可以修改
// enumerable: false, // 该属性是否可枚举, 是否能被for..in遍历出来
// configurable: false, //这个属性不能再次被配置,
// 注意: writable不能与get和set一同出现
// 当我们获取对象的某个属性的时候, 会被get方法劫持, 得到的结果是get的返回值
get() {
console.log('我获取obj的yanzhi')
return temp
},
// 当我们设置某个对象的属性,会被set劫持到,设置的值变成set的参数
set(value) {
console.log('我劫持到了属性的设置', value)
temp = value
}
})
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的
setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 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 变更的双向绑定效果。
4. Vue 如何去除 URL 中的#
vue-router 默认使用 hash 模式,所以在路由加载的时候,项目中的 URL 会自带 “#”。如果不想使用 “#”, 可以使用 vue-router 的另一种模式 history:
newRouter({
mode: 'history',
routes: [ ]
})
需要注意的是,当我们启用 history 模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现 “404” 的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 “index.html” 页面。
5. v-if与v-show的区别
v-if
- 真正的条件渲染,确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;
- 惰性的:如果在初始渲染时条件为
false,则什么也不做。 - —直到条件第一次变为
true时,才会开始渲染条件块。
v-show
- 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
区别
- v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景
- v-show 则适用于需要非常频繁切换条件的场景。
6. computed 和 watch 的区别和运用的场景?
watch和computed各自处理的数据关系场景不同 1.watch擅长处理的场景:一个数据影响多个数据 2.computed擅长处理的场景:一个数据受多个数据影响
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值; watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景: 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
7. 组件通信
父组件向子组件通信
子组件通过 props 属性,绑定父组件数据,实现双方通信。
子组件向父组件通信
将父组件的事件在子组件中通过 $emit 触发。
非父子组件、兄弟组件之间的数据传递
/*新建一个Vue实例作为中央事件总嫌*/
let event = newVue();
/*监听事件*/
event.$on('eventName', (val) => {
//......do something
});
/*触发事件*/
event.$emit('eventName', 'this is a message.')
vue组件通信 1. props/$emit
2. $emit/$on
3.vuex 4. provide/inject5. $parent / $children与 ref 6. vueX与LocalStorage
7. 你使用过vuex么?
vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
(2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
主要包括以下几个模块:
- State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
8. vue.filter
可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值。
Vue.filter('reverse', function(value) {
return value.split('').reverse().join('')
})
<!-- 'abc' => 'cba' -->
<spanv-text="message | reverse"></span>
过滤器也同样接受全局注册和局部注册。
8. 对 keep-alive 的了解
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
<keep-alive>
<component>
<!-- 该组件将被缓存!-->
</component>
</keep-alive>
Props:
- include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
- exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
- max - 数字。最多可以缓存多少组件实例。
可以使用 API 提供的 props,实现组件的动态缓存。 具体参考官方API(cn.vuejs.org/v2/api/#kee…
9.Vue 中怎么自定义指令
全局注册
// 注册一个全局自定义指令 `v-focus`
Vue.directive(
'focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function(el) {
// 聚焦元素
el.focus()
}
})
局部注册
directives: {
focus: {
// 指令的定义
inserted: function(el) {
el.focus()
}
}
}
参考官方文档:自定义指令(cn.vuejs.org/v2/guide/cu…
10.vue中key的作用
key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
具体参考官方API(cn.vuejs.org/v2/api/#key…