生命周期钩子函数
Vue 实例有一个残缺的生命周期,也就是从开始创立、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,咱们称这是Vue的生命周期
- Vue中组件生命周期调用程序
生命周期 | 形容 |
---|---|
beforeCreate | 组件实例被创立之初,组件的属性失效之前 |
created | 组件实例曾经齐全创立,属性也绑定,但实在dom还没有生成,$el还不可用 |
beforeMount | 在挂载开始之前被调用:相干的 render 函数首次被调用 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例下来之后调用该钩子 |
beforeUpdate | 组件数据更新之前调用,产生在虚构 DOM 打补丁之前 |
update | 组件数据更新之后 |
activited | keep-alive专属,组件被激活时调用 |
deadctivated | keep-alive专属,组件被销毁时调用 |
beforeDestory | 组件销毁前调用 |
destoryed | 组件销毁后调用 |
虚构dom
- 因为dom操作耗时非常长,且dom对象的体积很大,单个div的dom属性就有294个之多;
- Virtual DOM 就是用一个原生的 JS 对象去形容一个 DOM 节点,所以它比创立一个 DOM 的代价要小很多。
- VNode 是对实在 DOM 的一种形象形容,它的外围定义无非就几个要害属性,标签名、数据、子节点、键值等,其它属性都是用来扩大 VNode 的灵活性以及实现一些非凡 feature 的。因为 VNode 只是用来映射到实在 DOM 的渲染,不须要蕴含操作 DOM 的办法,因而它是十分轻量和简略的。
- Virtual DOM到实在的dom须要通过以下过程:VNode 的 create、diff、patch
v-model双向数据绑定原理
vue 双向数据绑定是通过 数据劫持
联合 公布订阅模式
的形式来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变动,视图变动,数据也随之产生扭转; 外围:Object.defineProperty()
办法。
v-model
实质上是语法糖,v-model在外部为不同的输出元素应用不同的属性并抛出不同的事件
- text 和 textarea 元素应用 value 属性和 input 事件
- checkbox 和 radio 应用 checked 属性和 change 事件
- select 字段将 value 作为 prop 并将 change 作为事件
<input v-model="sth" /><!-- 二者等价 --><input :value="sth" @input="sth = $event.target.value" />复制代码
computed和watch区别
vue 插槽
设置在自组件外部的插槽
像一个盒子,地位由子组件决定,放什么内容由父组件决定。
实现了内容散发,进步了组件自定义的水平,让组件变的更加灵便
- 默认插槽:
无需name
属性,取子组件肚子里第一个元素节点作为默认插槽。
<!-- 子组件,组件名:child-component --><div class="child-page"> <h1>子页面</h1> <slot></slot> <!-- 替换为 <p>hello,world!</p> --></div><!-- 父组件 --><div class="parent-page"> <child-component> <p>hello,world!</p> </child-component></div><!-- 渲染后果 --><div class="parent-page"> <div class="child-page"> <h1>子页面</h1> <p>hello,world!</p> </div></div>复制代码
- 具名插槽:
在多个插槽的状况下应用,利用name
标识插槽。
<!-- 子组件,组件名:child-component --><div class="child-page"> <h1>子页面</h1> <slot name="header"></slot> <slot></slot> <!-- 等价于 <slot name="default"></slot> --> <slot name="footer"></slot></div><!-- 父组件 --><div class="parent-page"> <child-component> <template v-slot:header> <p>头部</p> </template> <template v-slot:footer> <p>脚部</p> </template> <p>身材</p> </child-component></div><!-- 渲染后果 --><div class="parent-page"> <div class="child-page"> <h1>子页面</h1> <p>头部</p> <p>身材</p> <p>脚部</p> </div></div>复制代码
- 作用域插槽:
子组件给父组件传递数据。
<!-- 子组件,组件名:child-component --><div class="child-page"> <h1>子页面</h1> <slot name="header" data="data from child-component."></slot></div><!-- 父组件 --><div class="parent-page"> <child-component> <template v-slot:header="slotProps"> <p>头部: {{ slotProps.data }}</p> </template> </child-component></div><!-- 渲染后果 --><div class="parent-page"> <div class="child-page"> <h1>子页面</h1> <p>头部: data from child-component.</p> </div></div>复制代码
Vue与Angular以及React的区别?
Vue与AngularJS的区别
- Angular采纳TypeScript开发, 而Vue能够应用javascript也能够应用TypeScript
- AngularJS依赖对数据做脏查看,所以
Watcher
越多越慢;Vue.js应用基于依赖追踪
的察看并且应用异步队列
更新,所有的数据都是独立触发的。 - AngularJS社区欠缺, Vue的学习老本较小
Vue与React的区别
- vue组件分为全局注册和部分注册,在react中都是通过import相应组件,而后模版中援用;
props
是能够动态变化的,子组件也实时更新,在react中官网倡议props要像纯函数那样,输入输出统一对应,而且不太倡议通过props来更改视图;- 子组件个别要显示地调用props选项来申明它期待取得的数据。而在react中不必须,另两者都有props校验机制;
- 每个Vue实例都实现了事件接口,不便父子组件通信,小型我的项目中不须要引入状态管理机制,而react必须本人实现;
- vue应用
插槽
散发内容,使得能够混合父组件的内容与子组件本人的模板; - vue多了
指令系统
,让模版能够实现更丰盛的性能,而React只能应用JSX语法; - Vue减少的语法糖
computed
和watch
,而在React中须要本人写一套逻辑来实现; - react的思路是
all in js
,通过js来生成html,所以设计了jsx,还有通过js来操作css,社区的styled-component、jss等;而 vue是把html,css,js组合到一起,用各自的解决形式,vue有单文件组件,能够把html、css、js写到一个文件中,html提供了模板引擎来解决。 - react做的事件很少,很多都交给社区去做,vue很多货色都是内置的,写起来的确不便一些,比方
redux
的combineReducer
就对应vuex
的modules
, 比方reselect就对应vuex的getter和vue组件的computed, vuex的mutation是间接扭转的原始数据,而redux的reducer是返回一个全新的state,所以redux联合immutable来优化性能,vue不须要。 - react是整体的思路的就是函数式,所以推崇纯组件,数据不可变,单向数据流,当然须要双向的中央也能够做到,比方联合
redux-form
,组件的横向拆分个别是通过高阶组件。而vue是数据可变的,双向绑定,申明式的写法,vue组件的横向拆分很多状况下用mixin
$route
和$router
的区别
- $route是
路由信息对象
,包含path,params,hash,query,fullPath,matched,name等路由信息参数。 - 而$router是
路由实例
对象包含了路由的跳转办法,钩子函数等。
Vue的SPA 如何优化加载速度
- 缩小入口文件体积
- 动态资源本地缓存
- 开启Gzip压缩
- 应用SSR,nuxt.js
vue我的项目中的优化
编码阶段
- 不要在模板外面写过多表达式
- 尽量减少
data
中的数据,data
中的数据都会减少getter
和setter
,会收集对应的watcher
v-if
和v-for
不能连用- 如果须要应用
v-for
给每项元素绑定事件时应用事件代理 SPA
页面采纳keep-alive
缓存组件- 频繁切换的应用v-show,不频繁切换的应用v-if
- 循环调用子组件时增加key,
key
保障惟一 - 应用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动静加载
- 图片懒加载
SEO优化
- 预渲染
- 服务端渲染
SSR
,nuxt.js
打包优化
- 压缩代码
Tree Shaking/Scope Hoisting
- 应用
cdn
加载第三方模块 - 多线程打包
happypack
splitChunks
抽离公共文件sourceMap
优化
用户体验
- 骨架屏
PWA
渐进式Web利用,应用多种技术来加强web app的性能,让网页利用出现和原生利用类似的体验。
还能够应用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip
压缩等。
vue有了数据响应式,为何还要diff?
外围起因:粒度
React
通过setState
晓得有变动了,但不晓得哪里变动了,所以须要通过diff
找出变动的中央并更新dom。Vue
曾经能够通过响应式零碎晓得哪里产生了变动,然而所有变动都通过响应式会创立大量Watcher
,极其耗费性能,因而vue采纳的形式是通过响应式零碎晓得哪个组件产生了变动,而后在组件外部应用diff
。这样的中粒度策略,即不会产生大量的Watcher,也使diff的节点缩小了,两全其美。
vue模版编译
编译的外围是把 template 模板编译成 render 函数,次要分为如下三个步骤:
- 生成AST树
- 优化
- codegen
MVVM
MVVM
是Model-View-ViewModel
缩写,也就是把MVC
中的Controller
演变成ViewModel
。Model
层代表数据模型,View
代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并主动将数据渲染到页面中,视图变动的时候会告诉viewModel层更新数据。
响应式数据原理(Vue2.x & Vue3.0)
Vue2.x
在初始化数据时,会应用Object.defineProperty
从新定义data
中的所有属性,当页面应用对应属性时,首先会进行依赖收集
(收集以后组件的watcher),如果属性发生变化会告诉相干依赖进行派发更细
(公布订阅模式)。
vue3.0
采纳es6
中的proxy
代替Object.defineProperty
做数据监听。
Proxy与Object.defineProperty的优劣比照?
Proxy的劣势如下:
- Proxy能够间接监听对象而非属性
- Proxy能够间接监听数组的变动
- Proxy有多达13种拦挡办法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的
- Proxy返回的是一个新对象,咱们能够只操作新的对象达到目标,而Object.defineProperty只能遍历对象属性间接批改
- Proxy作为新规范将受到浏览器厂商重点继续的性能优化,也就是传说中的新规范的性能红利
Object.defineProperty的劣势如下:
- 兼容性好,反对IE9
vue的$nextTick
在下次 DOM
更新循环完结之后执行提早回调。nextTick
次要应用了宏工作和微工作。依据执行环境别离尝试采纳
- Promise
- MutationObserver
- setImmediate
- 如果以上都不行则采纳setTimeout
定义了一个异步办法,屡次调用nextTick会将办法存入队列中,通过这个异步办法清空以后队列。
vue组件中data为什么必须是一个函数
复用组件的时候,都会返回一份新的data,相当于每个组件实例都有本人公有的数据空间,不会共享同一个data
对象。
vue中组件通信的形式
- 父传子:
props
- 子传父:
$emit
、ref
- 兄弟:
EventBus
vue-router
vue-router
是vue的官网插件,次要用来治理前端路由。 对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面利用),须要引入前端路由零碎,这也就是 Vue-Router 存在的意义。前端路由的外围,就在于:扭转视图的同时不会向后端发出请求。
性能有:
- 扭转URL且不让浏览器向服务器发出请求
- 检测URL的扭转
- 记录以后页面的状态
- 能够应用浏览器的后退后退性能
- URL门路决定页面如何显示
history和hash模式的区别
1. 实现原理
hash 模式和 history 模式都属于浏览器本身的个性,Vue-Router 只是利用了这两个个性(通过调用浏览器提供的接口)来实现前端路由。
2. 比照表格
区别 \ mode | hash | history |
---|---|---|
监听事件 | hashChange | popstate |
毛病 | # 号不难看 | 子路由刷新404、ie9及以下不兼容 |
push操作 | window.location.assign | window.history.pushState |
replace操作 | window.location.replace | window.history.replaceState |
拜访操作 | window.history.go | window.history.go |
后退操作 | window.history.go(-1) | window.history.go(-1) |
向前操作 | window.history.go(1) | window.history.go(1) |
3. 对于 popstate 事件监听路由的局限 history对象的 back(), forward() 和 go() 三个等操作会被动触发 popstate 事件,然而 pushState 和 replaceState 不会触发 popstate 事件,这时咱们须要手动触发页面跳转(渲染)。
4. 对于子路由刷新的解决形式
history
模式子路由刷新会404,因而须要后端配合,将未匹配到的路由默认指向html
文件
5. 浏览器(环境)兼容解决
history 模式中pushState
、replaceState
是HTML5
的新个性,在 IE9
下会强行降级应用 hash
模式,非浏览器环境转换成abstract
模式。
6. router-link router-link
点击相当于调用$router.push
办法去批改url
<router-link>
比起写死的 <a href="...">
会好一些,理由如下:
- 无论是 HTML5 history 模式还是 hash 模式,它的体现行为统一,所以,当你要切换路由模式,或者在 IE9 降级应用 hash 模式,毋庸作任何变动。
- 在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再从新加载页面。
- 当你在 HTML5 history 模式下应用 base 选项之后,所有的 to 属性都不须要写(基门路)了。
vue-router路由懒加载
像 vue 这种单页面利用,如果没有路由懒加载,使用 webpack 打包后的文件将会很大,造成进入首页时,须要加载的内容过多,呈现较长时间的白屏,使用路由懒加载则能够将页面进行划分,须要的时候才加载页面,能够无效的分担首页所承当的加载压力,缩小首页加载用时。
vue 路由懒加载有以下三种形式:
- vue 异步组件
- ES6 的 import()
- webpack 的 require.ensure()
1. vue 异步组件 这种办法次要是应用了 resolve 的异步机制,用 require 代替了 import 实现按需加载
export default new Router({ routes: [ { path: '/home',', component: (resolve) => require(['@/components/home'], resolve), }, { path: '/about',', component: (resolve) => require(['@/components/about'], resolve), }, ],})复制代码
2. ES6 的 import() vue-router 在官网提供了一种办法,能够了解也是为通过 Promise 的 resolve 机制。因为 Promise 函数返回的 Promise 为 resolve 组件自身,而咱们又能够应用 import 来导入组件。
export default new Router({ routes: [ { path: '/home', component: () => import('@/components/home'), }, { path: '/about', component: () => import('@/components/home'), }, ],})复制代码
1. webpack 的 require.ensure() 这种模式能够通过参数中的 webpackChunkName 将 js 离开打包。
export default new Router({ routes: [ { path: '/home', component: (resolve) => require.ensure([], () => resolve(require('@/components/home')), 'home'), }, { path: '/about', component: (resolve) => require.ensure([], () => resolve(require('@/components/about')), 'about'), }, ],})复制代码
篇幅无限,还有没有收回来的题目都前端面试题材料里,须要残缺PDF材料的小伙伴只须要点击这里就能够收费获取!
有被问到题目的小伙伴们评论区能够聊聊你是怎么答复的哦,没有被问到的更要多看熟记,说不定就会碰到啦~这篇文章对你有帮忙请评论点赞反对一波,谢谢!