Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是Vue的生命周期
生命周期 | 描述 |
---|---|
beforeCreate | 组件实例被创建之初,组件的属性生效之前 |
created | 组件实例已经完全创建,属性也绑定,但真实dom还没有生成,$el还不可用 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 |
beforeUpdate | 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前 |
update | 组件数据更新之后 |
activited | keep-alive专属,组件被激活时调用 |
deadctivated | keep-alive专属,组件被销毁时调用 |
beforeDestory | 组件销毁前调用 |
destoryed | 组件销毁后调用 |
vue 双向数据绑定是通过 数据劫持
结合 发布订阅模式
的方式来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变; 核心:Object.defineProperty()
方法。
v-model
本质上是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件
复制代码
设置在自组件内部的插槽
像一个盒子,位置由子组件决定,放什么内容由父组件决定。
实现了内容分发,提高了组件自定义的程度,让组件变的更加灵活
无需name
属性,取子组件肚子里第一个元素节点作为默认插槽。
子页面
hello,world!
子页面
hello,world!
复制代码
在多个插槽的情况下使用,利用name
标识插槽。
子页面
头部
脚部
身体
子页面
头部
身体
脚部
复制代码
子组件给父组件传递数据。
子页面
头部: {
{ slotProps.data }}
子页面
头部: data from child-component.
复制代码
Vue与AngularJS的区别
Watcher
越多越慢;Vue.js使用基于依赖追踪
的观察并且使用异步队列
更新,所有的数据都是独立触发的。Vue与React的区别
props
是可以动态变化的,子组件也实时更新,在react中官方建议props要像纯函数那样,输入输出一致对应,而且不太建议通过props来更改视图;插槽
分发内容,使得可以混合父组件的内容与子组件自己的模板;指令系统
,让模版可以实现更丰富的功能,而React只能使用JSX语法;computed
和watch
,而在React中需要自己写一套逻辑来实现;all in js
,通过js来生成html,所以设计了jsx,还有通过js来操作css,社区的styled-component、jss等;而 vue是把html,css,js组合到一起,用各自的处理方式,vue有单文件组件,可以把html、css、js写到一个文件中,html提供了模板引擎来处理。redux
的combineReducer
就对应vuex
的modules
, 比如reselect就对应vuex的getter和vue组件的computed, vuex的mutation是直接改变的原始数据,而redux的reducer是返回一个全新的state,所以redux结合immutable来优化性能,vue不需要。redux-form
,组件的横向拆分一般是通过高阶组件。而vue是数据可变的,双向绑定,声明式的写法,vue组件的横向拆分很多情况下用mixin
$route
和$router
的区别路由信息对象
,包括path,params,hash,query,fullPath,matched,name等路由信息参数。路由实例
对象包括了路由的跳转方法,钩子函数等。编码阶段
data
中的数据,data
中的数据都会增加getter
和setter
,会收集对应的watcher
v-if
和v-for
不能连用v-for
给每项元素绑定事件时使用事件代理SPA
页面采用keep-alive
缓存组件key
保证唯一SEO优化
SSR
,nuxt.js
打包优化
Tree Shaking/Scope Hoisting
cdn
加载第三方模块happypack
splitChunks
抽离公共文件sourceMap
优化用户体验
PWA
渐进式Web应用,使用多种技术来增强web app的功能,让网页应用呈现和原生应用相似的体验。还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启
gzip
压缩等。
核心原因:粒度
React
通过setState
知道有变化了,但不知道哪里变化了,所以需要通过diff
找出变化的地方并更新dom。Vue
已经可以通过响应式系统知道哪里发生了变化,但是所有变化都通过响应式会创建大量Watcher
,极其消耗性能,因此vue采用的方式是通过响应式系统知道哪个组件发生了变化,然后在组件内部使用diff
。这样的中粒度策略,即不会产生大量的Watcher,也使diff的节点减少了,一举两得。编译的核心是把 template 模板编译成 render 函数,主要分为如下三个步骤:
MVVM
是Model-View-ViewModel
缩写,也就是把MVC
中的Controller
演变成ViewModel
。Model
层代表数据模型,View
代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
Vue2.x
在初始化数据时,会使用Object.defineProperty
重新定义data
中的所有属性,当页面使用对应属性时,首先会进行依赖收集
(收集当前组件的watcher),如果属性发生变化会通知相关依赖进行派发更细
(发布订阅模式)。
vue3.0
采用es6
中的proxy
代替Object.defineProperty
做数据监听。
Proxy的优势如下:
Object.defineProperty的优势如下:
$nextTick
在下次 DOM
更新循环结束之后执行延迟回调。nextTick
主要使用了宏任务和微任务。根据执行环境分别尝试采用
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。
复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,不会共享同一个data
对象。
props
$emit
、ref
EventBus
vue-router
是vue的官方插件,主要用来管理前端路由。 对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义。前端路由的核心,就在于:改变视图的同时不会向后端发出请求。
功能有:
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
像 vue 这种单页面应用,如果没有路由懒加载,运用 webpack 打包后的文件将会很大,造成进入首页时,需要加载的内容过多,出现较长时间的白屏,运用路由懒加载则可以将页面进行划分,需要的时候才加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时。
vue 路由懒加载有以下三种方式:
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资料的小伙伴只需要点击这里就可以免费获取!
有被问到题目的小伙伴们评论区可以聊聊你是怎么回答的哦,没有被问到的更要多看熟记,说不定就会碰到啦~这篇文章对你有帮助请评论点赞支持一波,谢谢!