写点什么

什么样的 vue 面试题答案才是面试官满意的

作者:bb_xiaxia1998
  • 2022-11-09
    浙江
  • 本文字数:10127 字

    阅读完需:约 33 分钟

Vue 组件渲染和更新过程

渲染组件时,会通过 Vue.extend 方法构建子组件的构造函数,并进行实例化。最终手动调用$mount() 进行挂载。更新组件时会进行 patchVnode 流程,核心就是diff算法


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

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


import {mapGetters} from 'vuex'export default{    computed:{        ...mapGetters(['total','discountTotal'])    }}
复制代码

一般在哪个生命周期请求异步数据

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


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


  • 能更快获取到服务端数据,减少页面加载时间,用户体验更好;

  • SSR 不支持 beforeMount 、mounted 钩子函数,放在 created 中有助于一致性。

action 与 mutation 的区别

  • mutation 是同步更新, $watch 严格模式下会报错

  • action 是异步操作,可以获取数据后调用 mutation 提交最终数据


参考:前端vue面试题详细解答

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

不会立即同步执行重新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化, Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。


如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环 tick 中,Vue 刷新队列并执行实际(已去重的)工作。

SPA 首屏加载速度慢的怎么解决

一、什么是首屏加载

首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容


首屏加载可以说是用户体验中最重要的环节


关于计算首屏时间


利用performance.timing提供的数据:



通过DOMContentLoad或者performance来计算出首屏时间


// 方案一:document.addEventListener('DOMContentLoaded', (event) => {    console.log('first contentful painting');});// 方案二:performance.getEntriesByName("first-contentful-paint")[0].startTime
// performance.getEntriesByName("first-contentful-paint")[0]// 会返回一个 PerformancePaintTiming的实例,结构如下:{ name: "first-contentful-paint", entryType: "paint", startTime: 507.80000002123415, duration: 0,};
复制代码

二、加载慢的原因

在页面渲染的过程,导致加载速度慢的因素可能如下:


  • 网络延时问题

  • 资源文件体积是否过大

  • 资源是否重复发送请求去加载了

  • 加载脚本的时候,渲染内容堵塞了

三、解决方案

常见的几种 SPA 首屏优化方式


  • 减小入口文件积

  • 静态资源本地缓存

  • UI 框架按需加载

  • 图片资源的压缩

  • 组件重复打包

  • 开启 GZip 压缩

  • 使用 SSR


1. 减小入口文件体积


常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加



vue-router配置路由的时候,采用动态加载路由的形式


routes:[     path: 'Blogs',    name: 'ShowBlogs',    component: () => import('./components/ShowBlogs.vue')]
复制代码


以函数的形式加载路由,这样就可以把各自的路由文件分别打包,只有在解析给定的路由时,才会加载路由组件


2. 静态资源本地缓存


后端返回资源问题:


  • 采用HTTP缓存,设置Cache-ControlLast-ModifiedEtag等响应头

  • 采用Service Worker离线缓存


前端合理利用localStorage


3. UI 框架按需加载


在日常使用UI框架,例如element-UI、或者antd,我们经常性直接引用整个UI


import ElementUI from 'element-ui'Vue.use(ElementUI)
复制代码


但实际上我用到的组件只有按钮,分页,表格,输入与警告 所以我们要按需引用


import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui';Vue.use(Button)Vue.use(Input)Vue.use(Pagination)
复制代码


4. 组件重复打包


假设A.js文件是一个常用的库,现在有多个路由使用了A.js文件,这就造成了重复下载


解决方案:在webpackconfig文件中,修改CommonsChunkPlugin的配置


minChunks: 3
复制代码


minChunks为 3 表示会把使用 3 次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件


5. 图片资源的压缩


图片资源虽然不在编码过程中,但它却是对页面性能影响最大的因素


对于所有的图片资源,我们可以进行适当的压缩


对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。


6. 开启 GZip 压缩


拆完包之后,我们再用gzip做一下压缩 安装compression-webpack-plugin


cnmp i compression-webpack-plugin -D
复制代码


vue.congig.js中引入并修改webpack配置


const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { // 为生产环境修改配置... config.mode = 'production' return { plugins: [new CompressionPlugin({ test: /\.js$|\.html$|\.css/, //匹配文件名 threshold: 10240, //对超过10k的数据进行压缩 deleteOriginalAssets: false //是否删除原文件 })] } }
复制代码


在服务器我们也要做相应的配置 如果发送请求的浏览器支持gzip,就发送给它gzip格式的文件 我的服务器是用express框架搭建的 只要安装一下compression就能使用


const compression = require('compression')app.use(compression())  // 在其他中间件使用之前调用
复制代码


7. 使用 SSR


SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成 html 字符串,再发送到浏览器


从头搭建一个服务端渲染是很复杂的,vue应用建议使用Nuxt.js实现服务端渲染

四、小结

减少首屏渲染时间的方法有很多,总的来讲可以分成两大部分 :资源加载优化页面渲染优化


下图是更为全面的首屏优化的方案



大家可以根据自己项目的情况选择各种方式进行首屏渲染的优化

Vue 中 computed 和 watch 有什么区别?

计算属性 computed: (1)支持缓存,只有依赖数据发生变化时,才会重新进行计算函数; (2)计算属性内不支持异步操作; (3)计算属性的函数中都有一个 get(默认具有,获取计算属性)和 set(手动添加,设置计算属性)方法; (4)计算属性是自动监听依赖值的变化,从而动态返回内容。


侦听属性 watch: (1)不支持缓存,只要数据发生变化,就会执行侦听函数; (2)侦听属性内支持异步操作; (3)侦听属性的值可以是一个对象,接收 handler 回调,deep,immediate 三个属性; (3)监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些其他事情

vue-loader 是什么?它有什么作用?

回答范例


  1. vue-loader是用于处理单文件组件(SFCSingle-File Component)的webpack loader

  2. 因为有了vue-loader,我们就可以在项目中编写SFC格式的Vue组件,我们可以把代码分割为<template><script><style>,代码会异常清晰。结合其他loader我们还可以用Pug编写<template>,用SASS编写<style>,用TS编写<script>。我们的<style>还可以单独作用当前组件

  3. webpack打包时,会以loader的方式调用vue-loader

  4. vue-loader被执行时,它会对SFC中的每个语言块用单独的loader链处理。最后将这些单独的块装配成最终的组件模块


原理


vue-loader会调用@vue/compiler-sfc模块解析SFC源码为一个描述符(Descriptor),然后为每个语言块生成import代码,返回的代码类似下面


// source.vue被vue-loader处理之后返回的代码// import the <template> blockimport render from 'source.vue?vue&type=template'// import the <script> blockimport script from 'source.vue?vue&type=script'export * from 'source.vue?vue&type=script'// import <style> blocksimport 'source.vue?vue&type=style&index=1'script.render = renderexport default script
复制代码


我们想要script块中的内容被作为js处理(当然如果是<script lang="ts">被作为ts理),这样我们想要webpack把配置中跟.js匹配的规则都应用到形如source.vue?vue&type=script的这个请求上。例如我们对所有*.js配置了babel-loader,这个规则将被克隆并应用到所在Vue SFC


import script from 'source.vue?vue&type=script
复制代码


将被展开为:


import script from 'babel-loader!vue-loader!source.vue?vue&type=script'
复制代码


类似的,如果我们对.sass文件配置了style-loader + css-loader + sass-loader,对下面的代码


<style scoped lang="scss">
复制代码


vue-loader将会返回给我们下面结果:


import 'source.vue?vue&type=style&index=1&scoped&lang=scss'
复制代码


然后webpack会展开如下:


import 'style-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss'
复制代码


  • 当处理展开请求时,vue-loader将被再次调用。这次,loader将会关注那些有查询串的请求,且仅针对特定块,它会选中特定块内部的内容并传递给后面匹配的loader

  • 对于<script>块,处理到这就可以了,但是<template><style>还有一些额外任务要做,比如

  • 需要用 Vue 模板编译器编译template,从而得到render函数

  • 需要对 <style scoped>中的CSS做后处理(post-process),该操作在css-loader之后但在style-loader之前


实现上这些附加的loader需要被注入到已经展开的loader链上,最终的请求会像下面这样:


// <template lang="pug">import 'vue-loader/template-loader!pug-loader!source.vue?vue&type=template'// <style scoped lang="scss">import 'style-loader!vue-loader/style-post-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss'
复制代码

Vue 模板编译原理

Vue 的编译过程就是将 template 转化为 render 函数的过程 分为以下三步


第一步是将 模板字符串 转换成 element ASTs(解析器)第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)
复制代码

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

可以监听多个方法


<input type="text" :value="name" @input="onInput" @focus="onFocus" @blur="onBlur" />
复制代码


v-on 常用修饰符


  • .stop 该修饰符将阻止事件向上冒泡。同理于调用 event.stopPropagation() 方法

  • .prevent 该修饰符会阻止当前事件的默认行为。同理于调用 event.preventDefault() 方法

  • .self 该指令只当事件是从事件绑定的元素本身触发时才触发回调

  • .once 该修饰符表示绑定的事件只会被触发一次

Computed 和 Methods 的区别

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


不同点:


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

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

Vue 为什么没有类似于 React 中 shouldComponentUpdate 的生命周期

  • 考点: Vue的变化侦测原理

  • 前置知识: 依赖收集、虚拟DOM、响应式系统


根本原因是VueReact的变化侦测方式有所不同


  • 当 React 知道发生变化后,会使用Virtual Dom Diff进行差异检测,但是很多组件实际上是肯定不会发生变化的,这个时候需要 shouldComponentUpdate 进行手动操作来减少diff,从而提高程序整体的性能

  • Vue在一开始就知道那个组件发生了变化,不需要手动控制diff,而组件内部采用的diff方式实际上是可以引入类似于shouldComponentUpdate相关生命周期的,但是通常合理大小的组件不会有过量的 diff,手动优化的价值有限,因此目前Vue并没有考虑引入shouldComponentUpdate这种手动优化的生命周期

Vue Ref 的作用

  • 获取dom元素this.$refs.box

  • 获取子组件中的datathis.$refs.box.msg

  • 调用子组件中的方法this.$refs.box.open()

Vue 修饰符有哪些

事件修饰符


  • .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

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

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

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

  • v-html 会先移除节点下的所有节点,调用 html 方法,通过 addProp 添加 innerHTML 属性,归根结底还是设置 innerHTML 为 v-html 的值。

Vue.extend 作用和原理

官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。


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


相关代码如下


export default function initExtend(Vue) {  let cid = 0; //组件的唯一标识  // 创建子类继承Vue父类 便于属性扩展  Vue.extend = function (extendOptions) {    // 创建子类的构造函数 并且调用初始化方法    const Sub = function VueComponent(options) {      this._init(options); //调用Vue初始化方法    };    Sub.cid = cid++;    Sub.prototype = Object.create(this.prototype); // 子类原型指向父类    Sub.prototype.constructor = Sub; //constructor指向自己    Sub.options = mergeOptions(this.options, extendOptions); //合并自己的options和父类的options    return Sub;  };}
复制代码

SPA、SSR 的区别是什么

我们现在编写的VueReactAngular应用大多数情况下都会在一个页面中,点击链接跳转页面通常是内容切换而非页面跳转,由于良好的用户体验逐渐成为主流的开发模式。但同时也会有首屏加载时间长,SEO不友好的问题,因此有了SSR,这也是为什么面试中会问到两者的区别


  1. SPA(Single Page Application)即单页面应用。一般也称为 客户端渲染(Client Side Render), 简称 CSRSSR(Server Side Render)即 服务端渲染。一般也称为 多页面应用(Mulpile Page Application),简称 MPA

  2. SPA应用只会首次请求html文件,后续只需要请求JSON数据即可,因此用户体验更好,节约流量,服务端压力也较小。但是首屏加载的时间会变长,而且SEO不友好。为了解决以上缺点,就有了SSR方案,由于HTML内容在服务器一次性生成出来,首屏加载快,搜索引擎也可以很方便的抓取页面信息。但同时 SSR 方案也会有性能,开发受限等问题

  3. 在选择上,如果我们的应用存在首屏加载优化需求,SEO需求时,就可以考虑SSR

  4. 但并不是只有这一种替代方案,比如对一些不常变化的静态网站,SSR 反而浪费资源,我们可以考虑预渲染(prerender)方案。另外nuxt.js/next.js中给我们提供了SSG(Static Site Generate)静态网站生成方案也是很好的静态站点解决方案,结合一些CI手段,可以起到很好的优化效果,且能节约服务器资源


内容生成上的区别:


SSR



SPA



部署上的区别


Vue 项目中有封装过 axios 吗?主要是封装哪方面的?

一、axios 是什么

axios 是一个轻量的 HTTP客户端


基于 XMLHttpRequest 服务来执行 HTTP 请求,支持丰富的配置,支持 Promise,支持浏览器端和 Node.js 端。自Vue2.0 起,尤大宣布取消对 vue-resource 的官方推荐,转而推荐 axios。现在 axios 已经成为大部分 Vue 开发者的首选


特性


  • 从浏览器中创建 XMLHttpRequests

  • node.js 创建 http请求

  • 支持 Promise API

  • 拦截请求和响应

  • 转换请求数据和响应数据

  • 取消请求

  • 自动转换JSON 数据

  • 客户端支持防御XSRF


基本使用


安装


// 项目中安装npm install axios --S// cdn 引入<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
复制代码


导入


import axios from 'axios'
复制代码


发送请求


axios({          url:'xxx',    // 设置请求的地址  method:"GET", // 设置请求方法  params:{      // get请求使用params进行参数凭借,如果是post请求用data    type: '',    page: 1  }}).then(res => {    // res为后端返回的数据  console.log(res);   })
复制代码


并发请求axios.all([])


function getUserAccount() {    return axios.get('/user/12345');}
function getUserPermissions() { return axios.get('/user/12345/permissions');}
axios.all([getUserAccount(), getUserPermissions()]) .then(axios.spread(function (res1, res2) { // res1第一个请求的返回的内容,res2第二个请求返回的内容 // 两个请求都执行完成才会执行}));
复制代码

二、为什么要封装

axios 的 API 很友好,你完全可以很轻松地在项目中直接使用。


不过随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍


这种重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用


举个例子:


axios('http://localhost:3000/data', {  // 配置代码  method: 'GET',  timeout: 1000,  withCredentials: true,  headers: {    'Content-Type': 'application/json',    Authorization: 'xxx',  },  transformRequest: [function (data, headers) {    return data;  }],  // 其他请求配置...}).then((data) => {  // todo: 真正业务逻辑代码  console.log(data);}, (err) => {  // 错误处理代码    if (err.response.status === 401) {  // handle authorization error  }  if (err.response.status === 403) {  // handle server forbidden error  }  // 其他错误处理.....  console.log(err);});
复制代码


如果每个页面都发送类似的请求,都要写一堆的配置与错误处理,就显得过于繁琐了


这时候我们就需要对axios进行二次封装,让使用更为便利

三、如何封装

  • 封装的同时,你需要和 后端协商好一些约定,请求头,状态码,请求超时时间.......

  • 设置接口请求前缀:根据开发、测试、生产环境的不同,前缀需要加以区分

  • 请求头 : 来实现一些具体的业务,必须携带一些参数才可以请求(例如:会员业务)

  • 状态码: 根据接口返回的不同status , 来执行不同的业务,这块需要和后端约定好

  • 请求方法:根据getpost等方法进行一个再次封装,使用起来更为方便

  • 请求拦截器: 根据请求的请求头设定,来决定哪些请求可以访问

  • 响应拦截器: 这块就是根据 后端`返回来的状态码判定执行不同业务


设置接口请求前缀


利用node环境变量来作判断,用来区分开发、测试、生产环境


if (process.env.NODE_ENV === 'development') {  axios.defaults.baseURL = 'http://dev.xxx.com'} else if (process.env.NODE_ENV === 'production') {  axios.defaults.baseURL = 'http://prod.xxx.com'}
复制代码


在本地调试的时候,还需要在vue.config.js文件中配置devServer实现代理转发,从而实现跨域


devServer: {    proxy: {      '/proxyApi': {        target: 'http://dev.xxx.com',        changeOrigin: true,        pathRewrite: {          '/proxyApi': ''        }      }    }  }
复制代码


设置请求头与超时时间


大部分情况下,请求头都是固定的,只有少部分情况下,会需要一些特殊的请求头,这里将普适性的请求头作为基础配置。当需要特殊请求头时,将特殊请求头作为参数传入,覆盖基础配置


const service = axios.create({    ...    timeout: 30000,  // 请求 30s 超时      headers: {        get: {          'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'          // 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来        },        post: {          'Content-Type': 'application/json;charset=utf-8'          // 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来        }  },})
复制代码


封装请求方法


先引入封装好的方法,在要调用的接口重新封装成一个方法暴露出去


// get 请求export function httpGet({  url,  params = {}}) {  return new Promise((resolve, reject) => {    axios.get(url, {      params    }).then((res) => {      resolve(res.data)    }).catch(err => {      reject(err)    })  })}
// post// post请求export function httpPost({ url, data = {}, params = {}}) { return new Promise((resolve, reject) => { axios({ url, method: 'post', transformRequest: [function (data) { let ret = '' for (let it in data) { ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' } return ret }], // 发送的数据 data, // url参数 params
}).then(res => { resolve(res.data) }) })}
复制代码


把封装的方法放在一个api.js文件中


import { httpGet, httpPost } from './http'export const getorglist = (params = {}) => httpGet({ url: 'apps/api/org/list', params })
复制代码


页面中就能直接调用


// .vueimport { getorglist } from '@/assets/js/api'
getorglist({ id: 200 }).then(res => { console.log(res)})
复制代码


这样可以把api统一管理起来,以后维护修改只需要在api.js文件操作即可


请求拦截器


请求拦截器可以在每个请求里加上 token,做了统一处理后维护起来也方便


// 请求拦截器axios.interceptors.request.use(  config => {    // 每次发送请求之前判断是否存在token    // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况,此处token一般是用户完成登录后储存到localstorage里的    token && (config.headers.Authorization = token)    return config  },  error => {    return Promise.error(error)  })
复制代码


响应拦截器


响应拦截器可以在接收到响应后先做一层操作,如根据状态码判断登录状态、授权


// 响应拦截器axios.interceptors.response.use(response => {  // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据  // 否则的话抛出错误  if (response.status === 200) {    if (response.data.code === 511) {      // 未授权调取授权接口    } else if (response.data.code === 510) {      // 未登录跳转登录页    } else {      return Promise.resolve(response)    }  } else {    return Promise.reject(response)  }}, error => {  // 我们可以在这里对异常状态作统一处理  if (error.response.status) {    // 处理请求失败的情况    // 对不同返回码对相应处理    return Promise.reject(error.response)  }})
复制代码


小结


  • 封装是编程中很有意义的手段,简单的axios封装,就可以让我们可以领略到它的魅力

  • 封装 axios 没有一个绝对的标准,只要你的封装可以满足你的项目需求,并且用起来方便,那就是一个好的封装方案

实际工作中,你总结的 vue 最佳实践有哪些

从编码风格、性能、安全等方面说几条:


编码风格方面:


  • 命名组件时使用“多词”风格避免和HTML元素冲突

  • 使用“细节化”方式定义属性而不是只有一个属性名

  • 属性名声明时使用“驼峰命名”,模板或jsx中使用“肉串命名”

  • 使用v-for时务必加上key,且不要跟v-if写在一起


性能方面:


  • 路由懒加载减少应用尺寸

  • 利用SSR减少首屏加载时间

  • 利用v-once渲染那些不需要更新的内容

  • 一些长列表可以利用虚拟滚动技术避免内存过度占用

  • 对于深层嵌套对象的大数组可以使用shallowRefshallowReactive降低开销

  • 避免不必要的组件抽象


安全:


  • 不使用不可信模板,例如使用用户输入拼接模板:template: <div> + userProvidedString + </div>

  • 避免使用v-html:url:style等,避免htmlurl、样式等注入

vue 中使用了哪些设计模式

1.工厂模式 - 传入参数即可创建实例


虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode


2.单例模式 - 整个程序有且仅有一个实例


vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉


3.发布-订阅模式 (vue 事件机制)


4.观察者模式 (响应式数据原理)


5.装饰模式: (@装饰器的用法)


6.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略


用户头像

bb_xiaxia1998

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
什么样的vue面试题答案才是面试官满意的_Vue_bb_xiaxia1998_InfoQ写作社区