vue面试知识点

SPA单页 Web 应用 (single-page application

简单理解为:仅仅在web页面初始化时加载相应的HTML、JavaScript、CSS,一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转。取⽽代之的是利⽤路由机制实现 HTML 内容的变换,UI 与⽤户的交互,避免⻚⾯的重新加载。

SPA的优缺点

1、优点:
  (1)⽤户体验好、快,内容的改变不需要重新加载整个⻚⾯,避免了不必要的跳转和重复渲染;
(2)SPA 相对对服务器压⼒⼩;
(3)前后端职责分离,架构清晰,前端进⾏交互逻辑,后端负责数据处理;

2、缺点:
   (1)⾸屏(初次)加载慢:为实现单⻚ Web 应⽤功能及显示效果,需要在加载⻚⾯的时候将JavaScript、CSS 统⼀加载,部分⻚⾯按需加载;
(2)不利于 SEO:由于所有的内容都在⼀个⻚⾯中动态替换显示,所以在 SEO 上其有着天然的弱势。

vue 生命周期

vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期

总共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后。

1、创建前/后:

  1. beforeCreate阶段:vue实例的挂载元素el和数据对象data都为undefined,还未初始化。

说明:在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。

  1. created阶段:vue实例的数据对象data有了,el还没有。

说明:可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。

2、载入前/后:

  1. beforeMount阶段:vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点。

说明:当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。

  1. mounted阶段:vue实例挂载完成,data.message成功渲染。

说明:在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。

3、更新前/后:

  1. beforeUpdate阶段:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器。

说明:可以在当前阶段进行更改数据,不会造成重渲染。

  1. updated阶段:虚拟DOM重新渲染和打补丁之后调用,组成新的DOM已经更新,避免在这个钩子函数中操作数据,防止死循环。

说明:当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。

4、销毁前/后:

  1. beforeDestroy阶段:实例销毁前调用,实例还可以用,this能获取到实例,常用于销毁定时器,解绑事件。

说明:在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。

  1. destroyed阶段:实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁。

说明:当前阶段组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

补充回答:

第一次页面加载时会触发:beforeCreate, created, beforeMount, mounted。

  1. created 实例已经创建完成,因为它是最早触发的原因可以进行一些数据,资源的请求。(服务器渲染支持created方法)

  2. mounted 实例已经挂载完成,可以进行一些DOM操作。(接口请求)

MVVM框架设计理念

MVVM分为Model、View、ViewModel三者。

Model 代表数据模型,数据和业务逻辑都在Model层中定义;

View 代表UI视图,负责数据的展示;

ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;

Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。

vue data中声明一个空对象,obj.attr = 5视图会刷新吗?

不会刷新

原因在于在Vue实例创建时,obj.attr 并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api—— $set()

Vue双向绑定实现原理

2.x 原理:Object.defineProperty(),然后重新定义了get()、set()

3.0 采用es6的proxy,(Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。)取代之前的object.defineProperty()

Vue 的响应式原理核心是通过 ES5 的保护对象的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新渲染 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。

1、监听器Observer:用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2、订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图

v-for中为何使用key

使用v-for更新已渲染的元素列表时,默认用就地复用策略;列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;

key的作用主要是为了高效的更新虚拟DOM。

我们经常会使用index(即数组的下标)来作为key,但其实这是不推荐的一种使用方法;

另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。

子组件注册方式

局部注册

  • 1.import 导入

  • 2.components注册

  • 3.以标签的形式,渲染在页面里

全局注册

  • 1.在main.js中import导入组件,

  • 2.使用Vue.component(标签名,组件模块)全局注册

区别:
1.局部注册只可以在对应引用.vue文件中使用。
2.全局注册可以在任意地方使用…

为什么Vue中的v-if和v-for不建议一起用?

原因:v-for优先级比v-if高

注意:

1、永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)

2、如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环


3、如果条件出现在循环内部,可通过计算属性computed提前过滤掉那些不需要显示的项

computed: {
    items: function() {
      return this.list.filter(function (item) {
        return item.isShow
      })
    }
}

父子组件通讯方式:

1.父组件向子组件传值

  • 在父组件的子组件中通过属性值方式传值

  • 子组件通过props接收

2.子组件向父组件传值

  • 父组件通过@符号向子组件传递一个事件方法

  • 子组件使用this.$emit(事件方法,数据,数据)

  • 父组件通过methods方法中的形参接收数据。

vue父子组件 渲染过程

同步引入 例子: import Page from ‘@/components/page’

1.加载渲染过程

父beforeCreated—父created----父beforeMount — 子beforeCreated—子created----子beforeMount — 子mounted — 父mounted

2.子组件更新过程

父beforeUpdate—子beforeUpdate----子updated—父updated

3.销毁过程

父beforeDestroy—子beforeDestroy----子destroyed—父destroyed

异步引入 例子:const Page = () => import(’@/components/page’)
或者: const Page = resolve => require([’@/components/page’], page)
1.加载渲染过程

父组件的beforeCreate、created、beforeMount、mounted --> 子组件的beforeCreate、created、beforeMount、mounted

2.子组件更新过

父beforeUpdate—父updated —子beforeUpdate----子updated

3.销毁过程

父beforeDestroy—父destroyed—子beforeDestroy----子destroyed

vuecli2.0 和 vue3.0 区别

1:目录结构不一样

vuecli2.0有build目录 有static目录

vuecli3.0没有build目录 有pulic目录

2:webpack的配置文件不一样

vuecli2.0有build目录 放置的是对应的 webpack的配置文件

vuecli3.0已经内嵌了webpack得配置 ,如果有修改需要新建一个

vue.config.js文件

3:创建项目的命令不一样

4:vuecli3.0有对应的可视化的界面

Vue性能优化

1、编码阶段

  • 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher;

  • 如果需要使用v-for给每项元素绑定事件时使用事件代理;

  • SPA 页面采用keep-alive缓存组件;

  • 在更多的情况下,使用v-if替代v-show;

  • key保证唯一;

  • 使用路由懒加载、异步组件;

  • 防抖、节流;

  • 第三方模块按需导入;

  • 长列表滚动到可视区域动态加载;

  • 图片懒加载;

2、用户体验:

  • 骨架屏;

  • PWA;

  • 还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。

3、SEO优化

  • 预渲染;

  • 服务端渲染SSR;

4、打包优化

  • 压缩代码;

  • Tree Shaking/Scope Hoisting;

  • 使用cdn加载第三方模块;

  • 多线程打包happypack;

  • splitChunks抽离公共文件;

  • sourceMap优化;

Dom 和 虚拟dom

虚拟dom javascript中的一个内置对象,用来描述真实的dom

vue和react框架中,采用的都是虚拟dom

在页面第一次渲染完成后,会生成一个js对象,用来描述真实的dom,之后当数据有更新或者变化的时候,

会在生成一个虚拟dom,然后新的虚拟dom和旧的dom进行对比(同级对比,采用的是diff算法),找出差异,进行更新,

生成新的虚拟dom,然后和真实的dom对比,修改真实dom中有变化的那一块

回流:当渲染树中的一部分或者全部因为元素的尺寸、布局、隐藏等改变而需要重新构建的时候,这时候就会发生回流

重绘:完成回流以后,浏览器会重新绘制受到影响的部分元素到屏幕中

什么时候会发生回流?

1、添加或者删除可见的DOM元素的时候

2、元素的位置发生改变

3、元素尺寸改变

4、内容改变

5、页面第一次渲染的时候

直接操作dom的时候,引起页面回流和重会的次数很多,而虚拟的dom是不会发生回流和重会的,

它会把要渲染的先统一放到一个对象中,然后通过document.fragment一次性比较并修改真实DOM中需要改的部分,

可以只渲染局部,大大减少了dom的操作,提高了性能

跟keep-alive有关的生命周期是哪些?描述下这些生命周期

activated和deactivated两个生命周期函数

1.activated:当组件激活时,钩子触发的顺序是created->mounted->activated

2.deactivated: 组件停用时会触发deactivated,当再次前进或者后退的时候只触发activated

computed、watch的区别

computed当做属性使用,可以依赖其他 computed,甚至是其他组件的 data必须有返回值,不能与 data 中的属性重复;有缓存的功能;不能接受参数;

watch可以监听data中的属性,也可以监听vuex状态; 监听的属性必须是存在的;允许异步;可接受两个参数

总结:

当有一些数据需要随着另外一些数据变化时,建议使用 computed

当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用 watch

let const var 区别

1.var定义的变量,作用域是整个封闭函数,是全域的;let定义的变量,作用域是在块级或者字块中;

2.变量提升:不论通过var声明的变量处于当前作用于的第几行,都会提升到作用域的最顶部。

而let声明的变量不会在顶部初始化,凡是在let声明之前使用该变量都会报错(引用错误ReferenceError);

3,只要块级作用域内存在let,它所声明的变量就会绑定在这个区域;

4,let不允许在相同作用域内重复声明(报错同时使用var和let,两个let)

const用来专门声明一个常量,它跟let一样作用于块级作用域,没有变量提升,重复声明会报错,不同的是const声明的常量不可改变,声明时必须初始化(赋值)

es6 的特有的类型, 常用的操作数组的方法都有哪些?

① let const 两者都有块级作用域 ② 箭头函数 ③ 模板字符串 ④ 解构赋值
⑤ for of 循环 ⑥ import 、export 导入导出 ⑦ set 数据结构 ⑧ …展开运算符
⑨ 修饰器 @ ⑩ class 类继承 ⑪ async、await ⑫ promise ⑬ Symbol
⑭ Proxy 代理

操作数组常用的方法:

ES5:concat 、join 、push、pop、shift、unshift、slice、splice、substring 和 substr 、sort、 reverse、indexOf 和 lastIndexOf 、every、some、filter、map、forEach、reduce
ES6:find、findIndex、fill、copyWithin、Array.from、Array.of、entries、values、key、includes

super

1.作为函数使用
代表的是父类的构造函数,返回的是子类的实例,即super内部的this指的是子类的实例,因此super()在这里相当于父类.prototype.constructor.call(this)。
2.super作为对象时,在普通方法中,指向父类的原型对象(A.prototype.p());在静态方法中,指向父类。

导航钩子有哪几种,分别如何用,如何将数据传入下一个点击的路由页面

1、全局导航守卫
前置守卫
router.beforeEach((to, from, next) => {
  // do someting
});
后置钩子(没有 next 参数)
router.afterEach((to, from) => {
  // do someting
});
2、路由独享守卫
cont router = new  VueRouter({
 routes: [
  {
    path: '/file',
    component: File,
    beforeEnter: (to, from ,next) => {
       // do someting
    }
   }
 ]
});

3、 组件内的导航钩子
组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的

路由懒加载 (延迟加载或按需加载,即在需要的时候的时候进行加载)

运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时
只会在进入当前这个路由时候才会走 component

1、vue异步组件实现懒加载:component:resolve=>(require([‘需要加载的路由的地址’]),resolve)

2、webpack提供的require.ensure()

3、ES6 提出的import方法:const HelloWorld = ()=>import(‘需要加载的模块地址’)

你可能感兴趣的:(vue)