介绍一下Vue的生命周期
-
beforeCreate
:是new Vue()
之后触发的第一个钩子,当前阶段data
、methods
、computed
以及watch
上的属性和方法均不能访问 -
create
:在实例创建完成之后,当前阶段已经完成了数据的观测,也就是可以使用数据,但是改变数据不会触发update
函数,可以做一些初始数据的获取,当前阶段无法与dom
进行交互,如果非要做交互,可以使用vm.$nextTick
来访问dom
-
beforemount
:发生在挂在之前,在这之前template
模板已导入渲染函数编译,当前阶段虚拟dom
已近创建完成,即将开始渲染,此时也可以修改数据,但是不会触发update
函数 -
mounted
:在挂载完成之后,这时候真实dom
已经挂载完毕,数据完成双向数据绑定,这时候可以进行dom
操作 -
beforeUpdate
:发生在更新之前,也就是响应式数据更新,虚拟dom
重新渲染之前触发,这个阶段可以进行数据的更改,不会重新渲染 -
update
:发生在更新完成之后,当前组件dom
已更新完毕,避免这个期间更改数据,因为可能会导致无限循环更新 -
beforeDestroy
:发生在实例销毁之前,当前阶段实例完全可以使用,这时候我们可以做一些善后操作:比如清除计时器 -
destroy
:发生在实例销毁之后,这时候只剩一个dom
空壳子
Vue的响应式系统
Vue
是MVVM
框架,当数据模型data
变化时,页面视图会得到相应的更新,
其原理对data
的getter/setter
方法进行了拦截(vue2:Object.defineProperty,vue3:proxy
)
利用发布订阅的设计模式,在getter
方法中进行订阅,在setter
方法中发布通知,让所有订阅者完成响应,当该属性变化时,会执行该属性的setter方法,从而完成该属性的发布通知,通知所有订阅者进行更新
computed与watch的区别
computed
和watch
都可以观察属性的变化从而做出响应,不同的是:
计算机属性computed
更多是作为缓存功能的观察者,它可以将一个或多个data
属性进行计算生成一个新的值提供给渲染函数使用,当依赖的属性变化时,computed
不会立即计算生成新的值,而是标记成脏数据,下次computed
被获取时,才会重新计算并返回
而监听器watch
并不具备缓存性,监听器提供一个监听函数,当监听的属性发生变化时,会立即执行该函数
vue双向绑定的原理
vue
双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变; 核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法
$nextTick
当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值, 你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
什么是vue-loader
解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理
用途:js可以写es6,style样式可以写scss或less、template可以加jade等
v-if和v-show的区别
当条件不成立时,v-if
不会渲染DOM
元素,v-show
操作的是样式(display)
,切换当前DOM
的显示和隐藏。
组件中的data为什么是一个函数?
一个组件可以很多地方使用,也就是会创建很多实例,如果data
是个对象的话,对象是引用类型,一个实例修改了data
数据会影响其他实例
所以data
必须使用函数,为每一个实例创建一个自己的data
,使同一组件在不同的实例中互不影响
Vue事件绑定原理
每个vue
实例都是一个Event Bus
,当子组件创建时候,父组件传递事件给子组件,子组件初始化时使用$on
方法,将事件注册在组件内部,子组件需要调用时可以通过 $emit 来调用事件, native
事件是通过addEventLister
在将事件注册到真实dom
中
slot是什么?有什么作用?原理是什么?
slot
又名插槽,是Vue
的内容分发机制,slot
是子组件的一个模板标签元素,怎么显示由父组件决定,分为:默认插槽、具名插槽、作用域插槽。
- 默认插槽,一个组件只有一个,slot没有指定name
- 具名插槽,带有name的slot,一个组件可以有多个
- 作用域插槽,可以是默认插槽也可以是具名插槽,该插槽不同点是,子组件渲染作用域插槽时候,可以将子组件的数据传递给父组件,父组件根据子组件传递过来的值来决定怎么渲染插槽
实现原理:
当子组件实例化的时候,获取到了父组件传入的slot
标签的内容,存放在vm.$slot
中,子组件执行渲染函数时候,遇到slot
标签,会使用$slot中
的内容替换
Vue模板渲染的原理是什么?
vue
会使用正则对template
字符串进行解析,将标签,属性,指定等转化成AST
语法树
遍历AST
语法树,将其转化成render
函数,遍历过程中,遇到静态节点会对其标记,方便重新渲染时diff
比较
再将rander
函数转化成虚拟dom
,遍历虚拟dom
,创建真实dom
template预编译是什么?
在vue
里,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后,再也不会进行编译,编译对组件runtime
是一种性能消耗
而模板编译只是将template
转化成render函数
,这个过程正好可以在项目构建的时候完成,这样就可以让组件的runtime
跳过编译的过程,从而提升性能,这个过程就是预编译
那template和jsx的有什么分别?
template和jsx都是render函数的一种表达方式,不同的是:
jsx
相对于template
而言,更加灵活,在复杂的组件中更有优势
虽然template
显得有些呆滞,但是在代码结构上更符合视图和逻辑分离的习惯,更简单,更直接,更容易维护
说一下什么是虚拟dom
虚拟dom
就是dom
节点在JavaScript
中的一种抽象数据结构,之所以用虚拟dom
,是因为操作真实dom
的代价比较昂贵,频繁的操作dom
会产生性能问题
虚拟dom
,在每次数据更新变化时后,会对比新老虚拟dom
,匹配找出尽可能少的需要更新的真实dom,从而提高性能
key属性的作用是什么
在对节点diff
的过程中,判断是否时同一节点的一个很重要条件就是key
是否相等,如果key
相等,会尽可能地服用原有节点,key
属性时提供给diff
使用的
说说Vue2.0和Vue3.0有什么区别
1、重构了响应式,用proxy
替换了object.defineProperty
它可以直接监听数组类型的数据变化
它可以直接监听对象本身,不用像object.defineProperty
,去遍历对象,提高了性能
可拦截apply
、ownKeys
、has
等13种方法,而Object.defineProperty
不
可以直接对对象的属性那个进行新增/删除
2、新增了composition API
,可以更好的逻辑复用和代码组织
3、重构了虚拟dom
编译模板时,将一些静态的节点编译成常量
slot
优化,slot
编译成lazy
函数,slot
显示权交给子组件
4、代码结构的调整,更便于 tree shaking
,使体积更小
5、使用ts
替换flow
vuex和vue的双向数据绑定有什么冲突
vuex里的值需要在Mutation里去修改,但是表单双向绑定了该用户修改时会尝试修改vuex里的state值,这在严格模式下会报错
解决方法,使用get和set,set函数内部去调用mutation,
<input v-model="message">
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
vue-router中的history模式和hash模式的区别
hash
模式url
永远带着#
号,我们在开发当中默认使用这个模式。
那么什么时候要用history
模式呢?如果用户考虑url
的规范那么就需要使用history
模式,因为history
模式没有#
号,是个正常的url
适合推广宣传。
当然其功能也有区别,比如我们在开发app
的时候有分享页面,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
父子组件生命周期的执行顺序
- 加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程
父beforeUpdate->父updated
- 销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
vue和react的区别
-
数据:
vue:双向数据绑定和单向数据流。双向数据绑定:DOM元素绑定的data值,当发生改变后,vue的响应式机制会自动监听data的变化重新渲染。单向数据流:当父组件给子组件传递数据的时候,子组件只可以读取而不能修改数据。可以用watch监听数据的更改,再赋给父组件的变量。
react:单向数据流。DOM元素依赖于state,但改变state不会改变渲染好的DOM,通过setState()才能重新渲染。父组件传值到子组件,如果顶级的props变了,会重新渲染所有的子组件。 -
虚拟DOM:
vue:计算出虚拟DOM的差异,在渲染的过程中跟踪每个组件的依赖关系,不会重新渲染整个组件树
react:当应用的状态改变时,重新渲染全部子组件,可以通过shouldComponentUpdate生命周期进行优化 -
模板和jsx:
vue:具有单文件组件,可以把html、css、js写在一个vue文件里----MVVM框架
react:依赖于jsx,在JavaScript中创建DOM----视图层框架
你都做过哪些Vue的性能优化?
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用
- 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if替代v-show
- key保证唯一
- 使用路由懒加载、异步组件防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动态加载
- 图片懒加载
内存溢出 内存泄露
内存溢出:是一种程序运行出现的错误; 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
内存泄露:占用的内存没有及时释放; 内存泄露积累多了就容易导致内存溢出
父组件向下(深层)子组件通讯
通过provide/Inject
,向子组件注入属性或者方法
网友评论