金三银四的 Vue 面试准备

前言

为了金三银四的跳槽季做准备,并且我是vue技术栈的,所以整理了若干个vue的面试题。

每次看别人的博客,都会不自主的去看答案,为了方便检验自己的掌握程度,我特意将答案折叠起来,大家可以先看题目,在脑海中想象一下如果你被问到会怎么回答,然后再展开答案看看和自己的答案有什么不同。

答案非官方,仁者见仁智者见智,仅供参考。

基础使用

MVVM、MVC 有什么区别

MVC通过分离Model、View和Controller的方式来组织代码结构。

其中View负责页面的显示逻辑,

Model负责存储页面的业务数据,以及对相应数据的操作。

Controller层是View层和Model层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Controller中的事件触发器就开始工作了,通过调用Model层,来完成对Model的修改,然后Model层再去通知View层更新。

MVVM分为Model、View、ViewModel。

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

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

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

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

Vue并没有完全遵循MVVM思想呢?

严格的MVVM要求View不能和Model直接通信,而Vue提供了$refs这个属性,让Model可以直接操作View,违反了这一规定,所以说Vue没有完全遵循MVVM。

Vue 的优点

渐进式框架:可以在任何项目中轻易的引入;

轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;

简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;

双向数据绑定:在数据操作方面更为简单;

组件化:很大程度上实现了逻辑的封装和重用,在构建单页面应用方面有着独特的优势;

视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;

对 SPA 单页面的理解,它的优缺点分别是什么?

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

优点:

用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;

有利于前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

缺点:

初次加载耗时多:为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面按需加载;

不利于SEO:由于所有的内容都在一个页面中动态替换显示,所以在SEO上其有着天然的弱势。

怎样理解 Vue 的单向数据流?

父级prop的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值。在子组件内部改变prop的时候 ,Vue会在浏览器的控制台中发出警告。

子组件想修改时,只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改。

有两种常见的试图改变一个prop的情形 :

这个prop用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop数据来使用。 在这种情况下,最好定义一个本地的data属性并将这个prop用作其初始值:

这个prop以一种原始的值传入且需要进行转换。 在这种情况下,最好使用这个prop的值来定义一个计算属性

Data 为什么是一个函数?

因为组件是用来复用的,且JS里对象是引用关系,如果组件中data是一个对象,那么这样作用域没有隔离,子组件中的data属性值会相互影响,如果组件中data选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的data属性值不会互相影响;而new Vue的实例,是不会被复用的,因此不存在引用对象的问题。

Computed 和 Watch 有什么区别?

对于 Computed:

它支持缓存,只有依赖的数据发生了变化,才会重新计算

不支持异步,当Computed中有异步操作时,无法监听数据的变化

如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用 computed

如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。

对于 Watch:

它不支持缓存,当一个属性发生变化时,它就会触发相应的操作

支持异步监听

监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值

监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作

函数有两个的参数:immediate:组件加载立即触发回调函数deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。

Computed 和 Methods 的区别

共同点:

可以将同一函数定义为一个method或者一个计算属性。对于最终的结果,两种方式是相同的。

不同点:

computed: 计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值;

method: 调用总会执行该函数。

.Sync 的作用是什么?

vue修饰符sync的功能是:当父组件提供了一个数据,而子组件想要去更改这个数据,但是Vue的规则不能让子组件去修改父组件的数据,就需要通过this.$emit和$event,来实现数据修改的目的。

:money.sync="total" // 等价于 :money="total" v-on:update:money="total = $event"复制代码

复制代码

绑定事件 @click=handler 和 @click=handler() 那个正确?有什么区别?

都可以,不带括号会传进来一个事件对象,带括号的不会

事件有哪些修饰符?

「事件修饰符」

.stop阻止事件继续传播

.prevent阻止标签默认行为

.capture使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理

.self只当在event.target是当前元素自身时触发处理函数

.once事件将只会触发一次

.passive告诉浏览器你不想阻止事件的默认行为

「v-model 的修饰符」

.lazy通过这个修饰符,转变为在change事件再同步

.number自动将用户的输入值转化为数值类型

.trim自动过滤用户输入的首尾空格

「键盘事件的修饰符」

.enter

.tab

.delete(捕获“删除”和“退格”键)

.esc

.space

.up

.down

.left

.right

「系统修饰键」

.ctrl

.alt

.shift

.meta

「鼠标按钮修饰符」

.left

.right

.middle

什么是插槽?具名插槽?作用域插槽?原理是什么?

slot又名插槽,是Vue的内容分发机制,插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽。

默认插槽:又名匿名插槽,当slot没有指定name属性值的时候,默认显示的插槽,一个组件内只允许有一个匿名插槽。

具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。

作用域插槽:可以是匿名插槽,也可以是具名插槽,该插槽在渲染时,父组件可以使用子组件内部的数据。

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

Vue 中如何实现过度效果?如何实现列表过度?

过渡效果,当然只有dom从显示到隐藏或隐藏到显示才能用

Vue.js为我们提供了内置的过渡组件transition和transition-group

Vue将元素的过渡分为四个阶段,进入前,进入后,消失前,消失后

支持mode属性,可选值:

in-out:要进入的先进入,然后要消失的再消失

out-in:要消失的先消失,然后要进入的再进入

多个元素需要加上过渡效果可以使用name属性进行区分。

可以配合animate.css实现更多的动画效果。

过滤器的作用,如何实现一个过滤器

过滤器是用来过滤数据的,在Vue选项中声明filters来实现一个过滤器,filters不会修改数据,而是处理数据,改变用户看到的输出。

使用场景:

需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。

比如后端返回一个年月日的日期字符串,前端需要展示为多少天前的数据格式,此时就可以用fliters过滤器来处理数据。

过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。过滤器用在插值表达式{{ }}和v-bind表达式中,然后放在操作符|后面进行指示。

例如,在显示金额,给商品价格添加单位:

<li>商品价格:{{item.price | filterPrice}}</li> filters: {    filterPrice (price) {      return price ? ('¥' + price) : '--'    }  }

复制代码

assets 和 static 的区别

相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点

不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。

建议:将项目中template需要的样式文件 js 文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。

对 SSR 的理解

SSR大致的意思就是vue在客户端将标签渲染成的整个html片段的工作在服务端完成,服务端形成的html片段直接返回给客户端,这个过程就叫做服务端渲染。

(1)服务端渲染的优点:

更好的SEO:SSR是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;

首屏加载更快:SPA会等待所有Vue编译后的js文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR直接由服务端渲染好页面直接返回显示,无需等待下载js文件及再去渲染等,所以SSR有更快的内容到达时间;

(2) 服务端渲染的缺点:

更多的开发条件限制:例如服务端渲染只支持beforCreate和created两个钩子函数,

不能进行dom操作。

这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行。

Vue 的性能优化有哪些

(1)代码层面的优化

v-if和v-show区分使用场景

computed和watch区分使用场景

v-for遍历必须为item添加key,且避免同时使用v-if

长列表性能优化

事件的销毁

图片资源懒加载

路由懒加载

第三方插件的按需引入

优化无限列表性能

服务端渲染

(2)Webpack 层面的优化

Webpack对图片进行压缩

减少ES6转为ES5的冗余代码

提取公共代码

模板预编译

提取组件的CSS

优化SourceMap

构建结果输出分析

Vue项目的编译优化

(3)基础的 Web 技术的优化

开启gzip压缩

浏览器缓存

CDN的使用

使用Chrome Performance查找性能瓶颈

Vue 的首屏加载性能优化有哪些

优化前的大小


1.图片优化

之前为了方便开法, 背景图片直接在assets里面扔了一个jpg, 导致加载这张图片的时候就用了十几秒, 于是乎我就把图片上传空间了, 然后改用网络地址。

2.禁止生成.map 文件

build出来的dist文件夹里面有很多的.map文件,这些文件主要是帮助线上调试代码,禁止生成这些文件.

在vue.config.js里面加上这句。


3.路由懒加载


4.cdn 引入公共库

   <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">  

  <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>  

  <script src="https://unpkg.com/element-ui/lib/index.js"></script>  

  <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>  

  <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>   

 <script src="https://cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>


//cdn引入

    configureWebpack: {

        externals: {

            'vue': 'Vue',

            'element-ui': 'ELEMENT',

            'vue-router': 'VueRouter',

            'vuex': 'Vuex',

            'axios': 'axios'

        }

    }

复制代码

网上说可以把import注释掉,亲自操作会报错,也有资料说不用注释也不会打包。

一顿操作最后的文件,效果显著,app.js 还是很大


5.终极法宝 GZIP 压缩

做完这个感觉前四步都是小菜一碟,直接把1.4m的app.js干成一百多kb,其他的都不足挂齿了。


configureWebpack: config => {

        return {

            //配置cdn

            externals: {

                'vue': 'Vue',

                'element-ui': 'ELEMENT',

                'vue-router': 'VueRouter',

                'vuex': 'Vuex',

                'axios': 'axios'

            },

            //配置gzip压缩

            plugins: [

                new CompressionWebpackPlugin({

                    test: new RegExp('\.(js|css)$'),

                    threshold: 10240,

                    minRatio: 0.8

                })

            ],

        }

    }

复制代码

服务端也要配,不然不认识GZIP文件。

//配置GZIP压缩模块

const compression = require('compression');

//在所有中间件之前引入

app.use(compression());

复制代码

最垃圾的服务器通过以上几个优化,一样飞起来了!!!


vue 初始化页面闪动问题

使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。

首先:在css里加上[v-cloak] { display: none; }。如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display:  block }"

Class 与 Style 如何动态绑定?

Class可以通过对象语法和数组语法进行动态绑定:

对象语法:

<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

data: {

  isActive: true,

  hasError: false

}

复制代码

数组语法:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

data: {

  activeClass: 'active',

  errorClass: 'text-danger'

}

复制代码

Style也可以通过对象语法和数组语法进行动态绑定:

对象语法:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {

  activeColor: 'red',

  fontSize: 30

}

复制代码

数组语法:

<div v-bind:style="[styleColor, styleSize]"></div>

data: {

  styleColor: {

    color: 'red'

  },

  styleSize:{

    fontSize:'23px'

  }

}

复制代码

如何让 CSS 只在当前组件中起作用?

在组件中的style标签中加上scoped

如何获取 dom

ref="domName"用法:this.$refs.domName

vue-loader 是什么?使用它的用途有哪些?

vue文件的一个加载器,把template/js/style转换成js模块。

生命周期

Vue 有哪些生命周期钩子?

Vue的生命周期钩子核心实现是利用发布订阅模式先把用户传入的的生命周期钩子订阅好(内部采用数组的方式存储)然后在创建组件实例的过程中会一次执行对应的钩子方法(发布)。

beforeCreate:是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。

created:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。

beforeMount:发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。

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

beforeUpdate:发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。

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

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

destroyed:发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

如果需要发送异步请求,最好放在哪个钩子内?

可以在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data已经创建,可以将服务端端返回的数据进行赋值。

推荐在created钩子函数中调用异步请求,有以下优点:

能更快获取到服务端数据,减少页面loading时间;

ssr不支持beforeMount、mounted钩子函数,所以放在created中有助于一致性;

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

beforeCreate,created,beforeMount,mounted

哪个钩子可以进行 dom 操作?

在钩子函数mounted被调用前,Vue已经将编译好的模板挂载到页面上,所以在mounted中可以访问操作DOM。

父子组件嵌套时,父组件和子组件生命周期钩子执行顺序是什么?

Vue的父组件和子组件生命周期钩子函数执行顺序可以归类为以下4部分:

加载渲染过程父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件更新过程父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程父beforeUpdate->父updated

销毁过程父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

父子组件嵌套时,父组件视图和子组件视图谁先完成渲染?

加载渲染过程父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

可知子组件先完成渲染

keep-alive 中的生命周期哪些

对应两个钩子函数activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated。

指令相关

说说 vue 内置指令


什么是自定义指令?有哪些生命周期?

是vue对HTML元素的扩展,给HTML元素增加自定义功能。vue编译DOM时,会找到指令对象,执行指令的相关方法。

自定义指令有五个生命周期

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。

componentUpdated:被绑定元素所在模板完成一次更新周期时调用。

unbind:只调用一次,指令与元素解绑时调用。

v-text 和 v-html 有什么区别?

v-text和{{}}表达式渲染数据,不解析标签。

v-html不仅可以渲染数据,而且可以解析标签。

v-if 和 v-for 的优先级

当v-if与v-for一起使用时,v-for具有比v-if更高的优先级,这意味着v-if将分别重复运行于每个v-for循环中。所以,不推荐v-if和v-for同时使用。如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去。

V-if 和 v-show 有什么区别?

手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;

编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;

编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;

性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。

组件的 v-model 是如何实现的?

我们在vue项目中主要使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定,我们知道v-model本质上不过是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:

text和textarea元素使用value属性和input事件;

checkbox和radio使用checked属性和change事件;

select字段将value作为prop并将change作为事件。

以input表单元素为例:

<input v-model='something'>

// 相当于

<input v-bind:value="something" v-on:input="something = $event.target.value">

复制代码

v-model 可以被用在自定义组件上吗?如果可以,如何使用?

如果在自定义组件中,v-model默认会利用名为value的prop和名为input的事件,如下所示:

父组件:<ModelChild v-model="message"></ModelChild>复制代码

复制代码

子组件:

<div>{{value}}</div>

props:{

    value: String

},

methods: {

  test1(){

    this.$emit('input', '小红')

  },

},

复制代码

v-on 可以监听多个方法吗?

可以

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

复制代码

组件相关

组件通信的 N 种方式

(1)props / $emit适用 父子组件通信

(2)ref适用 父子组件通信

ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例

(3)$parent/$children/$root:访问父 / 子实例 / 根实例

(4)EventBus ($emit / $on)适用于 父子、隔代、兄弟组件通信

这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

(5)$attrs/$listeners适用于 隔代组件通信

$attrs:包含了父作用域中不被prop所识别 (且获取) 的特性绑定 (class和style除外 )。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定 (class和style除外 ),并且可以通过v-bind="$attrs"传入内部组件。通常配合inheritAttrs选项一起使用。

$listeners:包含了父作用域中的 (不含.native修饰器的)v-on事件监听器。它可以通过v-on="$listeners"传入内部组件

(6)provide / inject适用于 隔代组件通信

祖先组件中通过provide来提供变量,然后在子孙组件中通过inject来注入变量。provide / inject API主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

(7)Vuex适用于 父子、隔代、兄弟组件通信

Vuex是一个专为Vue.js应用程序开发的状态管理模式。每一个Vuex应用的核心就是store(仓库)。store基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。

Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。

改变store中的状态的唯一途径就是显式地提交(commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

(8)插槽

Vue3可以通过usesolt获取插槽数据。

(9)mitt.js适用于任意组件通信

Vue3中移除了$on,$off等方法,所以EventBus不再使用,相应的替换方案就是mitt.js

Vue3 和 vue2 全局组件和局部组件注册的方式?

Vue2:Vue.component()

Vue3:app.component()

什么是动态组件?动态组件的钩子如何执行?

让多个组件使用同一个挂载点,并动态切换,这就是动态组件

简单的说,动态组件就是将几个组件放在一个挂载点下,这个挂载点就是标签,其需要绑定is属性,属性值为父组件中的变量,变量对应的值为要挂载的组件的组件名,然后根据父组件里某个变量来动态显示哪个,也可以都不显示。

缓存<keep-alive>

包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

可以将动态组件放到组件内对动态组件进行缓存,这样动态组件进行切换的时候,就不会每次都重新创建了。

Keep-alive 的作用?使用 keep-alive 的组件如何监控组件切换?

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:

一般结合路由和动态组件一起使用,用于缓存组件;

提供include和exclude属性,两者都支持字符串或正则表达式,include表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存 ,其中exclude的优先级比include高;

对应两个钩子函数activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated。

父组件如何监听子组件的生命周期?

比如有父组件Parent和子组件Child,如果父组件监听到子组件挂载mounted就做一些逻辑处理,可以通过以下写法实现:

// Parent.vue

<Child @mounted="doSomething"/>


// Child.vue

mounted() {

  this.$emit("mounted");

}

复制代码

以上需要手动通过$emit触发父组件的事件,更简单的方式可以在父组件引用子组件时通过@hook来监听即可,如下所示:

// Parent.vue

<Child @hook:mounted="doSomething" ></Child>

doSomething() {

  console.log('父组件监听到 mounted 钩子函数 ...');

},


//  Child.vue

mounted(){

  console.log('子组件触发 mounted 钩子函数 ...');

},   


// 以上输出顺序为:

// 子组件触发 mounted 钩子函数 ...

// 父组件监听到 mounted 钩子函数 ...   

复制代码

当然@hook方法不仅仅是可以监听mounted,其它的生命周期事件,例如:created,updated等都可以监听。

原理相关

Vue 初始化时都做了什么?

第一部分

⭐ 每个vue实例都有一个_uid,并且是依次递增的,确保唯一性。

⭐vue实例不应该是一个响应式的,做个标记。

第二部分

⭐ 如果是子组件,将组件配置对象上的一些深层次属性放到 vm.$options选项中,以提高代码的执行效率。

⭐ 如果是根组件,对options进行合并,vue会将相关的属性和方法都统一放到vm.$options中。vm.$options的属性来自两个方面,一个是Vue的构造函数vm.constructor预先定义的,一个是new Vue时传入的入参对象。

第三部分

initProxy / vm._renderProxy在非生产环境下执行了initProxy函数,参数是实例;在生产环境下设置了实例的_renderProxy属性为实例自身。

⭐ 设置了实例的_self属性为实例自身。

initLifecycle初始化组件实例关系属性 , 比如$parent、$children、$root、$refs等 (不是组件生命周期mounted,created...)

initEvents初始化自定义事件。

initRender初始化插槽 , 获取this.slots, 定义this._c, 也就是createElement方法 , 平时使用的h函数。

callHook执行beforeCreate生命周期函数。

initInjections初始化inject选项

initState响应式原理的核心 , 处理props、methods、computed、data、watch等。

initProvide解析组件配置项上的provide对象,将其挂载到vm._provided属性上。

callHook执行created生命周期函数。

第四部分

⭐ 如果有el属性,则调用vm.$mount方法挂载vm,挂载的目标就是把模板渲染成最终的DOM。

⭐ 不存在el的时候不挂载 , 需要手动挂载。

数据响应式的原理

Vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:

使用observe对需要响应式的数据进行递归,将对像的所有属性及其子属性,都加上setter和getter这样的话,给这个对象的某个属性赋值的时候,就会触发setter,那么就能监听到了数据变化。

compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

在自身实例化时往属性订阅器(dep)里面添加自己

自身必须有一个update()方法

待属性变动触发dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,完成视图更新。

总结:通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到一个数据响应式的效果。


使用 Object.defineProperty() 来进行数据劫持有什么缺点?

无法劫持以下操作

给对象新增属性

给对象删除属性

大部分的操作数组

Vue 框架怎么实现对象和数组的监听?

Vue框架是通过遍历数组递归遍历对象,从而达到利用Object.defineProperty()对对象和数组的部分方法的操作进行监听。

Vue 中给 data 中的对象属性添加一个新的属性或删除一个属性时会发生什么?如何解决?

什么都不会发生,因为Object.defineProperty()监听不到这类变化。

可以使用vm.$set和Vue.set方法去添加一个属性。

可以使用vm.$delete和Vue.delete方法去删除一个属性。

如何解决索引赋值或者修改数组长度无法改变视图?

由于Vue只改写了 7 种修改数组的方法,所以Vue不能检测到以下数组的变动:

当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue

当你修改数组的长度时,例如:vm.items.length = newLength

为了解决第一个问题,Vue提供了以下操作方法:

// Vue.set

Vue.set(vm.items, indexOfItem, newValue)

// vm.$set,Vue.set的一个别名

vm.$set(vm.items, indexOfItem, newValue)

// Array.prototype.splice

vm.items.splice(indexOfItem, 1, newValue)

复制代码

为了解决第二个问题,Vue提供了以下操作方法:

// Array.prototype.splice

vm.items.splice(newLength)

复制代码

数组的响应式是怎么实现的?

择对7种数组(push,shift,pop,splice,unshift,sort,reverse)方法进行重写

所以在Vue中修改数组的索引和长度是无法监控到的。需要通过以上7种变异方法修改数组才会触发数组对应的watcher进行更新

// src/obserber/array.js\

// 先保留数组原型\

const arrayProto = Array.prototype;\

// 然后将arrayMethods继承自数组原型\

// 这里是面向切片编程思想(AOP)--不破坏封装的前提下,动态的扩展功能\

export const arrayMethods = Object.create(arrayProto);\

let methodsToPatch = [\

  "push",\

  "pop",\

  "shift",\

  "unshift",\

  "splice",\

  "reverse",\

  "sort",\

];\

methodsToPatch.forEach((method) => {\

  arrayMethods[method] = function (...args) {\

    //  这里保留原型方法的执行结果\

    const result = arrayProto[method].apply(this, args);\

    // 这句话是关键\

    // this代表的就是数据本身 比如数据是{a:[1,2,3]} 那么我们使用a.push(4)  this就是a  ob就是a.__ob__ 这个属性就是上段代码增加的 代表的是该数据已经被响应式观察过了指向Observer实例\

    const ob = this.__ob__;\

\

    // 这里的标志就是代表数组有新增操作\

    let inserted;\

    switch (method) {\

      case "push":\

      case "unshift":\

        inserted = args;\

        break;\

      case "splice":\

        inserted = args.slice(2);\

      default:\

        break;\

    }\

    // 如果有新增的元素 inserted是一个数组 调用Observer实例的observeArray对数组每一项进行观测\

    if (inserted) ob.observeArray(inserted);\

    // 之后咱们还可以在这里检测到数组改变了之后从而触发视图更新的操作--后续源码会揭晓\

    return result;\

  };\

});

复制代码


$nextTick 的原理是什么?nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法。

简单的理解是:当数据更新了,在 dom 中渲染后, 自动执行该函数。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,Vue 是异步执行 DOM 更新的。created 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中,原因是在函数执行的时候 DOM 其实并未进行任何渲染。常用的场景是在进行获取数据后,需要对新视图进行下一步操作或者其他操作时,发现获取不到 dom。因为赋值操作只完成了数据模型的改变并没有完成视图更新。

有一个 timerFunc 这个函数用来执行 callbacks 里存储的所有回调函数

先判断是否原生支持 promise,如果支持,则利用 promise 来触发执行回调函数;

否则,如果支持 MutationObserver,则实例化一个观察者对象,观察文本节点发生变化时,触发执行所有回调函数。    如果都不支持,则利用 setTimeout 设置延时为 0。

列表循环时 key 有什么作用?key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。Vue 的 diff 过程可以概括为:oldCh 和 newCh 各有两个头尾的变量 oldStartIndex、oldEndIndex 和 newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有 4 种比较方式:newStartIndex 和 oldStartIndex 、newEndIndex 和 oldEndIndex 、newStartIndex 和 oldEndIndex 、newEndIndex 和 oldStartIndex,如果以上 4 种比较都没匹配,如果设置了 key,就会用 key 再进行比较,在比较的过程中,遍历会往中间靠,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较。

所以 Vue 中 key 的作用是:key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速,因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,源码如下:

function createKeyToOldIdx (children, beginIdx, endIdx) {

  let i, key

  const map = {}

  for (i = beginIdx; i <= endIdx; ++i) {

    key = children[i].key

    if (isDef(key)) map[key] = i

  }

  return map

}

复制代码

为什么不建议用 index 作为 key?

使用index作为key和没写基本上没区别,因为不管数组的顺序怎么颠倒,index都是 0, 1, 2...这样排列,导致Vue会复用错误的旧子节点,做很多额外的工作。

v-if、v-show、v-html 的原理

v-if会调用addIfCondition方法,生成vnode的时候会忽略对应节点,render的时候就不会渲染;

v-show会生成vnode,render的时候也会渲染成真实节点,只是在render过程中会在节点的属性中修改show属性值,也就是常说的display;

v-html会先移除节点下的所有节点,设置innerHTML为v-html的值。

Vue 中封装的数组方法有哪些,其如何实现页面更新

数组就是使用object.defineProperty重新定义数组的每一项,那能引起数组变化的方法我们都是知道的,

pop、

push、

shift、

unshift、

splice、

sort、

reverse

这七种,只要这些方法执行改了数组内容,我就更新内容就好了,是不是很好理解。

是用来函数劫持的方式,重写了数组方法,具体呢就是更改了数组的原型,更改成自己的,用户调数组的一些方法的时候,走的就是自己的方法,然后通知视图去更新。

数组里每一项可能是对象,那么我就是会对数组的每一项进行观测,(且只有数组里的对象才能进行观测,观测过的也不会进行观测)

vue3:改用proxy,可直接监听对象数组的变化。

Vue 模板渲染的原理是什么?

vue中的模板template无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的HTML语法,所有需要将template转化成一个JavaScript函数,这样浏览器就可以执行这一个函数并渲染出对应的HTML元素,就可以让视图跑起来了,这一个转化的过程,就成为模板编译。

模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render。

parse 阶段:使用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为抽象语法树AST。

optimize 阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重渲染的时候进行diff比较时,直接跳过这一些静态节点,优化runtime的性能。

generate 阶段:将最终的AST转化为render函数字符串。

说一下什么是 Virtual DOM

Virtual DOM是DOM节点在JavaScript中的一种抽象数据结构,之所以需要虚拟DOM,是因为浏览器中操作DOM的代价比较昂贵,频繁操作DOM会产生性能问题。虚拟DOM的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue对比更新前后的虚拟DOM,匹配找出尽可能少的需要更新的真实DOM,从而达到提升性能的目的。

Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?

Vue是异步执行DOM更新。

只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。

如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要。

然后,在下一个的事件循环tick中,Vue刷新队列并执行实际 (已去重的) 工作。Vue在内部尝试对异步队列使用原生的Promise.then和MessageChannel,如果执行环境不支持,会采用setTimeout(fn, 0)代替。

例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。

当刷新队列时,组件会在事件循环队列清空时的下一个tick更新。

多数情况我们不需要关心这个过程,但是如果你想在DOM状态更新后做点什么,这就可能会有些棘手。

虽然Vue.js通常鼓励开发人员沿着 “数据驱动” 的方式思考,避免直接接触DOM,但是有时我们确实要这么做。为了在数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在DOM更新完成后就会调用。

Vue.mixin 的使用场景和原理

在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立,可以通过Vue的mixin功能抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

Vue.extend 作用和原理

其实就是一个子类构造器 ,是Vue组件的核心api实现思路就是使用原型继承的方法返回了Vue的子类 并且利用mergeOptions把传入组件的options和父类的options进行了合并。

Vue 事件绑定原理

原生事件绑定是通过addEventListener绑定给真实元素的,组件事件绑定是通过Vue自定义的$on实现的。如果要在组件上使用原生事件,需要加.native修饰符,这样就相当于在父组件中把子组件当做普通html标签,然后加上原生事件。

on、emit是基于发布订阅模式的,维护一个事件中心,on的时候将事件按名称存在事件中心里,称之为订阅者,然后emit将对应的事件进行发布,去执行事件中心里的对应的监听器。

虚拟 DOM 实现原理?

虚拟DOM的实现原理主要包括以下3部分:

用JavaScript对象模拟真实DOM树,对真实DOM进行抽象;

diff算法 — 比较两棵虚拟DOM树的差异;

pach算法 — 将两个虚拟DOM对象的差异应用到真正的DOM树。

虚拟 dom 和真实 dom 的区别

虚拟DOM不会进行排版与重绘操作

虚拟DOM就是把真实DOM转换为Javascript代码

虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗

生态相关

vue-router 路由模式有几种?

vue-router有 3 种路由模式:hash、history、abstract:

hash: 使用URL hash值来作路由。支持所有浏览器,包括不支持HTML5 History Api的浏览器;

history: 依赖HTML5 History API和服务器配置。

abstract: 支持所有JavaScript运行环境,如Node.js服务器端。如果发现没有浏览器的API,路由会自动强制进入这个模式.

路由的 hash 和 history 模式的区别

(1)hash 模式的实现原理

早期的前端路由的实现就是基于location.hash来实现的。其实现原理很简单,location.hash的值就是URL中#后面的内容。比如下面这个网站,它的location.hash的值为#search:

https://www.word.com#search

复制代码

hash路由模式的实现主要是基于下面几个特性:

URL中hash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash部分不会被发送;

hash值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash的切换;

可以通过a标签,并设置href属性,当用户点击这个标签后,URL的hash值会发生改变;或者使用JavaScript来对loaction.hash进行赋值,改变URL的hash值;

我们可以使用hashchange事件来监听hash值的变化,从而对页面进行跳转(渲染)。

(2)history 模式的实现原理

HTML5提供了History API来实现URL的变化。其中做最主要的API有以下两个:history.pushState()和history.repalceState()。这两个API可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

window.history.pushState(null, null, path);

window.history.replaceState(null, null, path);

复制代码

history路由模式的实现主要基于存在下面几个特性:

pushState和repalceState两个API来操作实现URL的变化 ;

我们可以使用popstate事件来监听url的变化,从而对页面进行跳转(渲染);

history.pushState()或history.replaceState()不会触发popstate事件,这时我们需要手动触发页面跳转(渲染)。

如何获取页面的 hash 变化

监听$route对象

// 监听,当路由发生变化的时候执行

watch: {

$route: {

handler: function(val, oldVal){

  console.log(val);

},

  // 深度观察监听

deep: true

}

复制代码

route 和 router 的区别

$router是VueRouter的实例,在script标签中想要导航到不同的URL,使用$router.push方法。返回上一个历史history用$router.to(-1)

$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。

如何定义动态路由?如何获取传过来的动态参数?

可以通过query,param两种方式

区别:query通过url传参,刷新页面还在;params属性页面不在

params的类型:

配置路由格式:/router/:id

传递的方式:在path后面跟上对应的值

传递后形成的路径:/router/123

通过$route.params.id获取传递的值

query的类类型

配置路由格式:/router也就是普通配置

传递的方式:对象中使用query的key作为传递方式

传递后形成的路径:/route?id=123

通过$route.query获取传递的值

Vue-router 导航守卫有哪些

Vue-router 跳转和 location.href 有什么区别

使用location.href= /url 来跳转,简单方便,但是刷新了页面;

使用history.pushState( /url ),无刷新页面,静态跳转;

引进router,然后使用router.push( /url )来跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。

其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。

params 和 query 的区别

用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。

url 地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示。

注意点:query刷新不会丢失query里面的数据,params刷新会丢失params里面的数据。

Vuex 的原理

Vue组件会触发(dispatch)一些事件或动作,也就是Actions;

在组件中发出的动作,肯定是想获取或者改变数据的,但是在vuex中,数据是集中管理的,不能直接去更改数据,所以会把这个动作提交(Commit)到Mutations中;

然后Mutations就去改变State中的数据;

当State中的数据被改变之后,就会重新渲染(Render)到Vue Components中去,组件展示更新后的数据,完成一个流程。

Vuex 有哪几种属性

有五种,分别

State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。

Getter:允许组件从Store中获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。

Mutation:是唯一更改store中状态的方法,且必须是同步函数。

Action:用于提交mutation,而不是直接变更状态,可以包含任意异步操作。

Module:允许将单一的Store拆分为多个store且同时保存在单一的状态树中。

Vuex 和单纯的全局对象有什么区别?

Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。

不能直接改变store中的状态。改变store中的状态的唯一途径就是显式地提交mutation。

Vuex 中 action 和 mutation 的区别

Mutation专注于修改State,理论上是修改State的唯一途径;Action业务代码、异步请求。

Mutation:必须同步执行;Action:可以异步,但不能直接操作State。

在视图更新时,先触发actions,actions再触发mutation

mutation的参数是state,它包含store中的数据;action的参数是context,它是state的父级,包含state、getters等。

为什么 Vuex 的 mutation 中不能做异步操作?

Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过Action来提交mutation实现,这样可以方便地跟踪每一个状态的变化,从而能够实现一些工具帮助更好地了解我们的应用。

每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

Vuex 和 localStorage 的区别

(1)最重要的区别

vuex存储在内存中

localstorage则以文件的方式存储在本地,只能存储字符串类型的数据,存储对象需要JSON的stringify和parse方法进行处理。 读取内存比读取硬盘速度要快

(2)应用场景

Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex用于组件之间的传值。

localstorage是本地存储,是将数据存储到浏览器的方法,一般是在跨页面传递数据时使用 。

Vuex能做到数据的响应式,localstorage不能

(3)永久性

刷新页面时vuex存储的值会丢失,localstorage不会,对于不变的数据可以用localstorage可以代替vuex。

Vuex 的严格模式是什么,有什么作用,如何开启?

在严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

在Vuex.Store构造器选项中开启,如下

const store = new Vuex.Store({

    strict:true,

})

复制代码

如何在组件中批量使用 Vuex 的 getter 属性

使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed对象中

import {mapGetters} from 'vuex'

export default{

    computed:{

        ...mapGetters(['total','discountTotal'])

    }

}

复制代码

如何在组件中重复使用 Vuex 的 mutation

使用mapMutations辅助函数,在组件中这么使用

import { mapMutations } from 'vuex'

methods:{

    ...mapMutations({

        setNumber:'SET_NUMBER',

    })

}

复制代码

Vuex 页面刷新数据丢失怎么解决

在created周期中读取sessionstorage中的数据存储在store中,此时用vuex.store的replaceState方法,替换store的根状态

在beforeunload方法中将store.state存储到sessionstorage中。

export default {

  name: 'App',

  created() {

    //在页面加载时读取sessionStorage里的状态信息

    if (sessionStorage.getItem("store")) {

      this.$store.replaceState(Object.assign({},

        this.$store.state, JSON.parse(sessionStorage.getItem("store"))))

    }

    //在页面刷新时将vuex里的信息保存到sessionStorage里

    window.addEventListener("beforeunload", () => {

      sessionStorage.setItem("store", JSON.stringify(this.$store.state))

    })

  }

}

复制代码

3.0 相关

Vue3.0 有什么更新

Vue3.0 defineProperty 和 proxy 的区别

Vue3.x改用Proxy替代Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法。

Proxy 与 Object.defineProperty 优劣对比

Proxy 的优势如下:

Proxy可以直接监听对象而非属性;

Proxy可以直接监听数组的变化;

Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;

Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

Object.defineProperty 的优势如下:

兼容性好,支持IE9。

Vue 3.0 生命周期有哪些变化?


注意:3.0中的生命周期钩子要比2.X中相同生命周期的钩子要快

Composition API还新增了以下调试钩子函数:但是不怎么常用

onRenderTracked

onRenderTriggered

Vue 3.0 自定义指令有哪些变化?

先看看Vue2自定义指令的钩子

bind:当指令绑定在对应元素时触发。只会触发一次。

inserted:当对应元素被插入到DOM的父元素时触发。

update:当元素更新时,这个钩子会被触发(此时元素的后代元素还没有触发更新)。

componentUpdated:当整个组件(包括子组件)完成更新后,这个钩子触发。

unbind:当指令被从元素上移除时,这个钩子会被触发。也只触发一次。

在 Vue3中,官方为了更有助于代码的可读性和风格统一,把自定义指令的钩子名称改的更像是组件生命周期,尽管他们是两回事

bind=>beforeMount

inserted=>mounted

beforeUpdate:新的钩子,会在元素自身更新前触发

update=>移除

componentUpdated=>updated

beforeUnmount:新的钩子,当元素自身被卸载前触发

unbind=>unmounted

后语

最后祝大家在新的一年里,都能找到满意的工作,升职加薪,赚的盆满钵满!

最后

如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:780179818 相互学习,我们会有专业的技术答疑解惑

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点 star:http://github.crmeb.net/u/lsq不胜感激 !

PHP 学习手册:https://doc.crmeb.com

技术交流论坛:https://q.crmeb.com

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