web大前端复习——Vue

1.vue和react的区别

相似之处:

(1).他们都专注于创造前端的富应用,react和vue都只有骨架,其它的功能如路由、状态管理等是框架分离的组件;

(2).虚拟DOM(Virtual DOM),它是一个映射真实DOM的js对象,如果需要改变任何元素的状态,首先在虚拟DOM上进行改变,而不是直接改变真实的DOM。当有变化发生时,一个新的Virtual DOM对象会被创建并计算新旧虚拟DOM之间的差别,然后把这些差别应用在真实的DOM上;

(3).组件化和数据驱动;

(4).可以使用自己的构建工具快速搭建开发环境。React可以使用Create React App(CRA),而Vue对应的则是vue-cli;

(5).配套全家桶;

(6).都有自己的移动端解决方案,React——react native;Vue——weex;

主要区别:

(1).React整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在React中,是单向数据流,强调数据的不可变;而Vue2是通过Object.defineProperty()劫持getter/setter(Vue3通过Proxy)来双向绑定数据,能精确知道数据的变化,使用的是可变数据;

(2).在React中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树;在Vue中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确的知晓哪个组件确实需要被渲染

(3).React使用JSX语法,Vue虽然现在也支持了JSX,但默认使用更多的还是<template>模板

2.单页应用(SPA)的原理和优缺点

什么是单页应用?

单页应用(Single Page Application),是一种只需要将单个页面作为容器加载到浏览器之中的Web应用程序。

原理:主要由History和Hash两种形式实现

History:主要依靠Window.history对象的pushState()方法和replaceState()方法,这两个方法可以用来向历史栈中添加或修改数据,就好像URL变化了一样(过去只有URL变化,历史栈才会变化),前端路由就是基于这个原理实现的,当他们执行修改时,虽然改变了当前的URL,但浏览器不会立即向后端发送请求;

Hash:在URL中可以带上一个#,这个就是hash模式,location.hash的值实际就是#后面的东西,当URL的片段标识符(#后面的东西)发生变化时,将触发window对象中的onhashchange事件,然后做一些操作即可;

优点:

(1).避免了页面的重新加载,用户有良好流畅的交互体检

(2).得益于ajax,可以实现无跳转刷新,没有页面之间的切换

(3).减轻服务器压力,服务器只用出数据就可以了,不用管展示逻辑和页面合成

缺点:

(1).第一次加载首页耗时相对长一些

(2).不利于seo的优化

(3).不适合开发大型项目(设计大量DOM的操作)

3.什么是vuex?以及它的使用场景?

vuex是vue的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化

常应用于多个组件共享状态时,如购物车、登录状态等

4.什么是MVVM框架,它和MVC的区别?

MVC:

image.png

Model:数据模型,可以把它看做从数据库中查出来的一条数据

View:视图,用户肉眼可见的界面层

Controller:控制器,数据模型和视图层之间的桥梁层,负责数据的处理、组装等页面业务逻辑。使用MVC的目的就是将M和V的代码分离。MVC是单向通信,也就是View和Model必须通过Controller来承上启下。

MVVM:

image.png

Model:数据模型,可以把它看做从数据库中查出来的一条数据

View:视图,用户肉眼可见的界面层

ViewModel:View和Model之间的桥梁,将二者绑定起来。它是双向的,一个方向是是通过数据绑定的方式,将模型转化成视图,即将数据转化成所看到的的页面;另一个方向是将视图转化成模型,即通过DOM事件监听,将所看到的的页面转成数据。这两个方向称为数据的双向绑定。在MVVM中视图和模型是不能直接通信的,它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者模式,当数据发生变化时,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,viewModel也能监听到视图的变化,然后通知数据做改动。

总结:MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在的目的在于抽离了Controller中展示的业务逻辑,其它视图操作业务等还是应该放在Controller中实现,也就是说MVVM实现的是业务逻辑组件的重用。

5.Vue.js的核心是什么

数据驱动、组件化

6.Vue的生命周期以及调用顺序

创建前/后:

beforeCreate,vue实例的$el和数据对象data此时都为undefined,还未初始化;

created,vue实例的数据对象data有了,但是$el还没有

载入前/后:

beforeMount,vue实例的$el和data都初始化了,data中的模板和数据生成了html,但还没有挂载在html上;

mounted,挂载完成,也就是模版中的html渲染到到html页面中

更新前/后:

beforeUpdate,数据更新之前被调用;

updated,更新完成之后调用,组件Dom已经更新,要避免在此期间更改数据,否则可能会导致无限循环

销毁前/后:

beforeDestory,在实例销毁之前调用,此时实例仍然完全可用,一般可以在这一步做一些重置的操作,比如清除定时器和监听的dom事件;

destoryed,在实例销毁之后调用,此时所有的事件监听器都会被移除,组件已被拆解,数据绑定被卸载,所有的子实例也会被销毁

组件的调用顺序都是先父后子,渲染完成的顺序是先子后父;

组件的销毁操作是先父后子,销毁完成的顺序是先子后父;

7.第一次页面加载会触发哪几个钩子

beforeCreate——created——beforeMounted——mounted

8.Vue的双向绑定原理

Vue2

原理:采用数据劫持结合发布者-订阅者模式的方法,通过Object.defineProperty()来劫持各个属性的getter、setter属性,在数据变动后,通知订阅者,触发更新回调函数,重新渲染视图。当把一个普通js对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty()将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。

实现:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>Document</title>

</head>

<body>

<div id="app">

    <input type="text" id="input">

    <span id="span"></span>

</div>

</body>

<script>

    let obj = {};  //定义一个空对象

    let val = 'gwy';  //赋予初始值

    Object.defineProperty(obj, 'val', {//定义要修改对象的属性

        get: function () {

            return val;

        },

        set: function (newVal) {

            //定义val等于修改后的内容

            val = newVal

            //让文本框的内容等于val

            document.getElementById('input').value = val

            //让span的内容等于val

            document.getElementById('span').innerHTML = val

        }

    })

    document.addEventListener('keyup', function (e) {

        //当在文本框输入内容时让对象里你定义的val等于文本框的值

        obj.val = e.target.value;

    })

</script>

</html>

Vue3

原理:Vue 3.0与Vue 2.0的区别仅是数据劫持的方式由Object.defineProperty更改为Proxy代理,其他代码不变

为什么要用Proxy取代Object.defineProperty?

(1).Object.defineProperty存在一定的局限性,无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。针对数组的某些方法进行了hack处理,只有以下八种方法可以检测到变化:

push()

pop()

shift()

unshift()

splice()

sort()

reverse()

(2).Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue里,是通过递归以及遍历data对象来实现对数据的监控的,如果属性值也是一个对象那么需要深层遍历,显然如果能劫持一个完整的对象,不管是对操作性还是性能都会有一个很大的提升。

要取代Object.defineProperty的Proxy有两个优点:

(1).可以劫持整个对象,并返回一个新对象

(2).有13种劫持操作

什么是Proxy?

Proxy是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。

实现:

const obj = {};

    const input = document.getElementById("input")

    const title = document.getElementById("title")

    const newObj = new Proxy(obj, {

      get: function(target, key, receiver) {

        console.log(`getting ${key}!`)

        return Reflect.get(target, key, receiver)

      },

      set: function(target, key, value, receiver) {

        console.log(target, key, value, receiver)

        if (key === "text") {

          input.value = value

          title.innerHTML = value

        }

        return Reflect.set(target, key, value, receiver);

      }

    })

    input.addEventListener("keyup", function(e) {

      newObj.text = e.target.value;

    })

什么是Reflect?

Reflect是ES6里的新的对象,非构造函数,不能用new操作符。可以把它跟Math类比,Math是处理JS中数学问题的方法函数集合,Reflect是JS中对象操作方法函数集合,它暴露出来的方法与Object构造函数所带的静态方法大部分重合,实际功能也类似,Reflect的出现一部分原因是想让开发者不直接使用Object这一类语言层面上的方法,还有一部分原因也是为了完善一些功能。Reflect提供的方法还有一个特点,完全与Proxy构造函数里Hander参数对象中的钩子属性一一对应。

9.从template转换成真实DOM的实现机制

先将template中的html转换成函数,然后利用这个函数生成virtual dom对象,遍历这个对象,生成真实的dom

10.virtual DOM原理

Virtual DOM是一个简单的js对象,在页面进行更新的时候,借助虚拟DOM元素的改变可以在内存中进行比较,并将多次比较的结果合并以后一次性的更新到页面,从而减少页面渲染的次数,提高渲染效率。

具体实现步骤如下:

(1).用js对象结构表示DOM树的结构,然后用这个树构建一个真正的DOM树,插入到文档中

(2).当状态变更的时候,重新构造一颗新的对象树,然后用新的树和旧的树进行比较,记录两棵树的差异

(3).把记录到的差异应用到真正的DOM树上,视图就更新了

11.v-if与v-show的区别与应用场景?

v-if是通过重建和销毁dom来达到显示和隐藏的效果

v-show是通过修改dom的display属性来显示和隐藏

当需要频繁切换的时候,用v-show

12.nextTick原理

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

首先来了解一下js的运行机制:

(1).所有的同步任务都在主线程上执行,形成一个执行栈(execution context stack)

(2).主线程之外,会存在一个任务队列(task queue),只要异步任务有了运行结果,就在任务队列中放置一个事件

(3).一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行

(4).主线程不断重复上面的第三步

这里主线程的执行过程就是一个tick,而所有的异步结果都是通过任务队列来调度。Event Loop分为宏任务和微任务,无论是执行宏任务还是微任务,完成后都会进入到下一个tick,并在两个tick之间进行UI渲染。

由于Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保得到更新后的DOM,所以设置了Vue.nextTick()方法,Vue会在内部尝试对异步队列延迟调用,由于宏任务耗费的时间是大于微任务的,所以在浏览器的支持下,优先使用微任务,如果浏览器不支持微任务,再使用宏任务。

延迟调用的优先级:Promise > MutationObserver > setImmediate > setTimeout

浅析Vue.nextTick原理

Vue.nextTick原理和用途

13. Vue跨组件通信方案

父传子:属性传值,父组件给子组件标签上定义属性,子组件通过props接收

子传父:事件传值,子组件通过$emit,父组件通过在子组件上定义自定义事件来接收

兄弟组件:通过中央事件总线(Event Bus)

Vuex:全局状态管理

14.Vue组件中的data为什么是一个函数

一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。

15.v-model的原理

v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。 可以通过model属性的prop和event属性来进行自定义。原生的v-model,会根据标签的不同生成不同的事件和属性。

<input v-model="sth" />

//  等同于

<input :value="sth" @input="sth = $event.target.value" />

16.vue 常用的修饰符

v-model.number:将用户输入的值转为数值类型

v-model.trim:自动过滤用户输入的首尾空白字符

@click.stop:阻止事件冒泡

@click.once:事件只执行一次

v-on:keyup.enter:(键盘修饰符)按下键盘的时候

17.v-on 监听多个方法

<input type="text" v-on="{input:onInput,focus:onFocus,blur:onBlur}">

18.Vue 中 key 值的作用

Key的作用就是尽可能的复用dom元素,当有相同的标签名和元素切换时,需要通过key的特效设置唯一的值来标记,让vue区分它们,否则vue为了效率只会替换相同标签内部的内容

19.vue 事件中如何使用event对象

<button @click="Event($event)">事件对象</button>

methods: {

Event(e){

   console.log(e)

}

}

20.v-for 与v-if的优先级,如何同时使用

v-for比v-if具有更高的优先级

永远不要把 v-if 和 v-for 同时用在同一个元素上

21.Vue更新数组时触发视图更新的方法

改变原数组:push(),pop(),shift(),unshift(),splice(),sort(),reverse()

不改变原数组:filter(),concat(),slice()

Vue.set(target, key, value)

target:要更改的数据源(可以是对象或者数组)

key:要更改的具体数据

value :重新赋的值

22.Vue如何优化首屏加载速度

(1).路由懒加载,把不同路由对应的组件分隔成不同的代码块,按需加载

(2).减少入口文件体积

(3).静态资源本地缓存

(4).使用CDN资源,减小服务器带宽压力

(5).使用Nginx开启gzip压缩,减小网络传输的流量大小

(6).使用SSR

23.router-link和a标签的区别

router-link的to属性跳转比起a标签的href跳转的区别是,router-link进行跳转不会跳转到新页面,避免了重新渲染,它只更新变化的部分从而减少dom性能的消耗

24.Vue模版编译原理

简单来说,Vue的编译过程就是将template转换成render函数的过程,会经历一下阶段:

(1).将模版字符串转换成element ASTs(解析器)

首先是解析模板,生成AST树(一种用js对象的形式来描述整个模板)。使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理

(2).对AST进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)

Vue的数据是响应式的,但模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的对比,对运行时的模板起到很大的优化作用

(3).使用element ASTs生成render函数代码字符串(代码生成器)

编译的最后一步是将优化后的AST树转换为可执行的代码

25.Vue2.x和Vue3.x渲染器的diff算法

简单来说,diff算法有以下过程:

(1).同级比较,再比较子节点

(2).先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)

(3).比较都有子节点的情况(核心diff)

(4).递归比较子节点

Vue2的核心diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比react的diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅

Vue3借鉴了ivi算法和inferno算法,在创建VNode时就确定其类型,以及在mount/patch的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的diff算法,使得性能上较Vue2有了提示

26.keep-alive了解吗

<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染

27.关于服务端渲染(SSR)

什么是服务端渲染?

简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序

优点:

(1).更利于SEO

爬虫只会爬取源码,不会执行网站的任何脚本(google除外,据说google可以运行JavaScript)。使用了React或其它的MVVM框架之后,页面大多数DOM元素都是在客户端根据js动态生成的,可供爬虫抓取分析的内容就很少。而服务端渲染返回给客户端的是已经获取了异步数据并执行了JS脚本的最终的HTML,爬虫就可以抓取到完整的信息

(2).更利于首屏渲染

首屏的渲染是node发送过来的html字符串,并不依赖于js文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页应用,打包后文件体积比较大,普通客户端渲染加载所有所需文件时间较长,首页就会有一个很长的白屏等待时间。

缺点:

(1).服务端压力较大

本来是通过客户端完成渲染,现在统一到服务端node服务去做。尤其是高并发访问的情况,会大量占用服务端CPU资源

(2).开发条件受限

在服务端渲染中,beforeCreate和created,因此项目引用的第三方的库也不可用其它生命周期钩子,这对引用库的选择产生了很大的限制

28.你都做过哪些Vue的性能优化

编码阶段:

(1).尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher

(2).v-if和v-for不能连用

(3).如果需要使用v-for给每项元素绑定事件时使用事件代理

(4).SPA页面采用keep-alive缓存组件

(5).如果不需要频繁切换,使用v-if替代v-show

(6).Key值保持唯一

(7).使用路由懒加载

(8).防抖,节流

(9).第三方模块按需导入

(10).长列表滚动加载

(11).图片懒加载

SEO优化:

(1).预渲染

(2).服务端渲染SSR

打包优化:

(1).压缩代码

(2).使用cdn加载第三方模块

(3).Tree Shaking/Scope Hoisting

(4).多线程打包happypack

(5).splitChunks抽离公共文件

(6).sourceMap优化

29.Vue2的响应式是如何监听Array的?

Vue中利用Object.defineProperty监听数组和对象是有缺陷的,Vue 不能检测到对象属性的添加或删除,当数组通过下标赋值或者通过改变数组长度去改变数组,都无法更新视图,这是由于Vue没有做相应的处理,但是Vue通过劫持数组的原型方法,将所有可能使得数组产生变化的方法劫持,当数据调用这些方法的时候,dep.notify(),会通知依赖于此数据的视图update(),手动派发更新。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335