1、Vue的基本原理
【】当一个Vue实例创建时,Vue会遍历data
中的属性,用 Object.defineProperty
(vue3.0使用proxy )将它们转为 getter/setter
,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher
程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter
被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
2、双向绑定数据的原理
【】Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:
- 需要
observe
的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化 compile
解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图Watcher
订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退- MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果
3、使用 Object.defineProperty() 来进行数据劫持有什么缺点
【】通过下标方式修改数组数据或者给对象新增属性,这都不能触发组件的重新渲染,因为 Object.defineProperty 不能拦截到这些操作
4、MVVM 理解
【】MVVM 分为 Model、View、ViewModel
:
- Model 代表数据模型,数据和业务逻辑都在Model层中定义
- View 代表UI视图,负责数据的展示
- ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作
5、Computed、Watch、Methods、Fliters
【】对于 Computed:
- 支持缓存,只有依赖的数据发生了变化,才会重新计算
- 不支持异步,当Computed中有异步操作时,无法监听数据的变化
【】对于 Watch:
- 不支持缓存,数据变化时,它就会触发相应的操作
- 支持异步监听
【】对于 Methods:
- 同一函数可以定义为一个 method 或者一个计算属性,但是 method 不支持缓存,每次都会调用
【】对于 Fliters:
- 对数据进行格式化。过滤器用在插值表达式
{{ }}
和v-bind
表达式 中,然后放在操作符“ | ”
后面进行指示
6、slot是什么?有什么作用?原理是什么?
【】slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口
【】分为三类:默认插槽,具名插槽和作用域插槽
【】实现原理:当子组件 vm 实例化时,获取到父组件传入的 slot 标签的内容,存放在vm.$slot
中,默认插槽为vm.$slot.default
,具名插槽为vm.$slot.xxx
,xxx 为插槽名,当组件执行渲染函数时候,遇到 slot 标签,使用 $slot 中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽
7、常见的事件修饰符
【】.stop
:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡
【】.prevent
:等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为
【】.capture
:与事件冒泡的方向相反,事件捕获由外到内
【】.self
:只会触发自己范围内的事件,不包含子元素
【】.once
:只会触发一次
8、v-if 和 v-show 的区别
【】手段:v-if 是动态的向DOM树内添加或者删除DOM元素;v-show 是通过设置DOM元素的display样式属性控制显隐
【】编译过程:v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show 只是简单的基于css切换
【】编译条件:v-if 是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show 是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留
9、data 为什么是一个函数而不是对象
【】首先当多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其他实例中的数据也会发生变化
【】在Vue中,更多的是想要复用组件,那就需要每个组件都有自己的数据,这样组件之间才不会相互干扰。数据以函数返回值的形式定义,这样当每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有自己的私有数据空间,它们各自维护自己的数据,不会干扰其他组件的正常运行
10、nextTick() 的作用
【】在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构的时候,这个操作就需要方法在nextTick()的回调函数中
【】在vue生命周期中,如果在created()钩子进行DOM操作,也一定要放在nextTick()的回调函数中。因为在created()钩子函数中,页面的DOM还未渲染,这时候也没办法操作DOM
11、自定义指令
【】一般需要对DOM元素进行底层操作时使用,尽量只用来操作 DOM展示,不修改内部的值。当使用自定义指令直接修改 value 值时绑定v-model的值也不会同步更新;如必须修改可以在自定义指令中使用keydown事件,在vue组件中使用 change事件,回调中修改vue数据
【】全局定义:Vue.directive("focus",{})
。 局部定义:directives:{focus:{}}
【】钩子函数:bind inSerted update componentupdate unbind
. 钩子函数参数:el. bing. name. value. oldValue. expression. arg. modifers. vnode. oldVnode
12、assets 和 static 的区别
【】assets
和 static
两个都是存放静态资源文件
【】在项目打包时,assets 中放置的静态资源文件会进行打包上传,static 中放置的静态资源文件就不会要走打包压缩格式化等流程
【】将项目中 template需要的样式文件js文件等都可以放置在 assets 中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css 等文件可以放置在 static 中,因为这些引入的第三方文件已经经过处理,不再需要处理,直接上传
13、Vue 模版编译原理
【】解析阶段:使用大量的正则表达式对 template 字符串进行解析,将标签、指令、属性等转化为抽象语法树AST
【】优化阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重渲染的时候进行diff比较时,直接跳过这一些静态节点,优化runtime的性能
【】生成阶段:将最终的AST转化为render函数字符串
14、对 SSR 的理解
【】SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端
【】优势:更好的SEO;首屏加载速度更快
【】缺点:服务器端渲染只支持beforeCreate和created两个钩子;更多的服务端负载
15、对 SPA 单页面的理解
【】SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载
【】优点:
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
- 基于上面一点,SPA 相对对服务器压力小
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理
【】缺点:
- 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势
16、Vue 子组件和父组件的执行顺序
【】加载渲染过程:父组件 beforeCreate. >. 父组件 created. >. 父组件 beforeMount. >. 子组件 beforeCreate. >. 子组件 created. >. 子组件 beforeMount. >. 子组件 mounted. >. 父组件 mounted
【】更新过程:父组件 beforeUpdate. >. 子组件 beforeUpdate. >. 子组件 updated. >. 父组件 updated
【】销魂过程:父组件 beforeDestroy. >. 子组件 beforeDestroy. >. 子组件 destroyed. >. 父组件 destoryed
17、组件通信方式
【】props / $emit
【】eventBus 事件总线
【】依赖注入(provide / inject):依赖注入所提供的属性是非响应式的
【】ref / $refs
【】$parent / $children
【】$attrs / $listeners
18、对虚拟 DOM 的理解
【】从本质上来说,Virtual Dom是一个JavaScript对象,通过对象的方式来表示DOM结构。将页面的状态抽象为JS对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次DOM修改的结果一次性的更新到页面上,从而有效的减少页面渲染的次数,减少修改DOM的重绘重排次数,提高渲染性能
19、虚拟 DOM 的解析过程
【】首先对将要插入到文档中的 DOM 树结构进行分析,使用 js 对象将其表示出来,比如一个元素对象,包含 TagName、props 和 Children 这些属性。然后将这个 js 对象树给保存下来,最后再将 DOM 片段插入到文档中
【】当页面的状态发生改变,需要对页面的 DOM 的结构进行调整的时候,首先根据变更的状态,重新构建起一棵对象树,然后将这棵新的对象树和旧的对象树进行比较,记录下两棵树的的差异
【】最后将记录的有差异的地方应用到真正的 DOM 树中去,这样视图就更新了
参考文章:https://juejin.cn/post/6919373017218809864