├── README.md └── images ├── DevTools.png ├── custom-directives.svg ├── flow.png ├── vuelifecycle.png └── vuex-app-structure.png /README.md: -------------------------------------------------------------------------------- 1 | # VueJS 面试题 2 | 3 | Original English version: [vuejs-interview-questions](https://github.com/sudheerj/vuejs-interview-questions) 4 | 5 | 列出了 300 道 VueJS 面试题 6 | 7 | > 如果你喜欢这个项目点击 :star:,Pull Requests 是非常赞赏的。 8 | 9 | ## 内容列表 10 | 11 | | 序号 | 问题 | 12 | |------|---------------------------------------------------------------------------------------------------------------| 13 | | 1 | [VueJS 是什么?](#1-vuejs-是什么) | 14 | | 2 | [VueJS 的主要功能是什么?](#2-vuejs-的主要功能是什么) | 15 | | 3 | [VueJS 的生命周期方法是什么?](#3-vuejs-的生命周期方法是什么) | 16 | | 4 | [条件指令是什么?](#4-条件指令是什么) | 17 | | 5 | [v-show 和 v-if 指令有什么不同?](#5-v-show-和-v-if-指令有什么不同) | 18 | | 6 | [v-for 指令的目的是什么?](#6-v-for-指令的目的是什么) | 19 | | 7 | [vue 实例是什么?](#7-vue-实例是什么) | 20 | | 8 | [如何实现条件组元素?](#8-如何实现条件组元素) | 21 | | 9 | [如何复用有 key 属性的元素?](#9-如何复用有-key-属性的元素) | 22 | | 10 | [为什么不能在同一个元素上同时使用 v-if 和 v-for 指令?](#10-为什么不能在同一个元素上同时使用-v-if-和-v-for-指令) | 23 | | 11 | [为什么使用 for 指令时需要 key 属性?](#11-为什么使用-for-指令时需要-key-属性) | 24 | | 12 | [什么是数组检测突变的方法?](#12-什么是数组检测突变的方法) | 25 | | 13 | [什么是数组检测非突变方法?](#13-什么是数组检测非突变方法) | 26 | | 14 | [检测数组变化有什么注意事项?](#14-检测数组变化有什么注意事项) | 27 | | 15 | [检测对象变化有什么注意事项?](#15-检测对象变化有什么注意事项) | 28 | | 16 | [如何在一个范围内使用 v-for 指令?](#16-如何在一个范围内使用-v-for-指令) | 29 | | 17 | [如何在模板上使用 v-for 指令?](#17-如何在模板上使用-v-for-指令) | 30 | | 18 | [如何使用事件处理程序?](#18-如何使用事件处理程序) | 31 | | 19 | [Vue 提供的事件修饰符是什么?](#19-Vue-提供的事件修饰符是什么) | 32 | | 20 | [什么是 key 修饰符?](#20-什么是-key-修饰符) | 33 | | 21 | [如何自定义 key 修饰符别名?](#21-如何自定义-key-修饰符别名) | 34 | | 22 | [支持什么系统 keys 修饰符?](#22-支持什么系统-keys-修饰符) | 35 | | 23 | [支持什么鼠标按钮修饰符?](#23-支持什么鼠标按钮修饰符) | 36 | | 24 | [如何实现双向绑定?](#24-如何实现双向绑定) | 37 | | 25 | [model 支持什么修饰符?](#25-model-支持什么修饰符) | 38 | | 26 | [组件是什么并给个例子?](#26-组件是什么并给个例子) | 39 | | 27 | [props 是什么?](#27-props-是什么) | 40 | | 28 | [何时需要一个单独的根元素?](#28-何时需要一个单独的根元素) | 41 | | 29 | [父子组件如何通过事件通信?](#29-父子组件如何通过事件通信) | 42 | | 30 | [怎样在自定义输入框组件上实现 model?](#30-怎样在自定义输入框组件上实现-model) | 43 | | 31 | [什么时 slots?](#31-什么时-slots) | 44 | | 32 | [组件中的全局注册是什么?](#32-组件中的全局注册是什么) | 45 | | 33 | [为什么你需要本地注册?](#33-为什么你需要本地注册) | 46 | | 34 | [本地注册和全局注册在模块系统中有什么区别?](#34-本地注册和全局注册在模块系统中有什么区别) | 47 | | 35 | [什么是可接受的 prop 类型?](#35-什么是可接受的-prop-类型) | 48 | | 36 | [props 后面的数据流是什么?](#36-props-后面的数据流是什么) | 49 | | 37 | [什么是非 prop 属性?](#37-什么是非-prop-属性) | 50 | | 38 | [props 有哪些可用的验证?](#38-props-有哪些可用的验证) | 51 | | 39 | [如何为组件自定义 model 指令?](#39-如何为组件自定义-model-指令) | 52 | | 40 | [提供给 transitions 什么可能的方式?](#40-提供给-transitions-什么可能的方式) | 53 | | 41 | [什么是 vue router 和它的特性?](#41-什么是-vue-router-和它的特性) | 54 | | 42 | [使用 vue router 路由器的步骤是什么并给出一个例子?](#42-使用-vue-router-路由器的步骤是什么并给出一个例子) | 55 | | 43 | [什么是动态路由匹配?](#43-什么是动态路由匹配) | 56 | | 44 | [如何使路由参数的变化为响应式?](#44-如何使路由参数的变化为响应式) | 57 | | 45 | [什么是路线匹配优先级?](#45-什么是路线匹配优先级) | 58 | | 46 | [什么是嵌套路由?](#46-什么是嵌套路由) | 59 | | 47 | [什么是单文件组件?](#47-什么是单文件组件) | 60 | | 48 | [单个文件组件是否违反了关注分离?](#48-单个文件组件是否违反了关注分离) | 61 | | 49 | [单文件组件解决了哪些问题?](#49-单文件组件解决了哪些问题) | 62 | | 50 | [什么是过滤器?](#50-什么是过滤器) | 63 | | 51 | [创建过滤器有什么不同方法?](#51-创建过滤器有什么不同方法) | 64 | | 52 | [如何链接过滤器?](#52-如何链接过滤器) | 65 | | 53 | [是否可以传递参数给过滤器?](#53-是否可以传递参数给过滤器) | 66 | | 54 | [什么是插件及它的各种服务?](#54-什么是插件及它的各种服务) | 67 | | 55 | [如何创建一个插件?](#55-如何创建一个插件) | 68 | | 56 | [如何使用插件?](#56-如何使用插件) | 69 | | 57 | [什么是混合?](#57-什么是混合) | 70 | | 58 | [什么是全局混合?](#58-什么是全局混合) | 71 | | 59 | [如何在 CLI 中使用混合?](#59-如何在-CLI-中使用混合) | 72 | | 60 | [混合中的合并策略是什么?](#60-混合中的合并策略是什么) | 73 | | 61 | [什么是自定义选项合并策略?](#61-什么是自定义选项合并策略) | 74 | | 62 | [什么是自定义指令?](#62-什么是自定义指令) | 75 | | 63 | [如何注册局部指令?](#63-如何注册局部指令) | 76 | | 64 | [指令提供的钩子函数是什么?](#64-指令提供的钩子函数是什么) | 77 | | 65 | [指令钩子函数的参数是什么?](#65-指令钩子函数的参数是什么) | 78 | | 66 | [如何将多个值传递给一个指令?](#66-如何将多个值传递给一个指令) | 79 | | 67 | [什么是指令钩子中的函数速记?](#67-什么是指令钩子中的函数速记) | 80 | | 68 | [与模板相比 render 函数的好处是什么?](#68-与模板相比-render-函数的好处是什么) | 81 | | 69 | [什么是 render 函数?](#69-什么是-render-函数) | 82 | | 70 | [解释 createElement 的参数结构?](#70-解释-createElement-的参数结构) | 83 | | 71 | [如何在组件中重复虚拟节点?](#71-如何在组件中重复虚拟节点) | 84 | | 72 | [列出 render 函数中与模板等效的项?](#72-列出-render-函数中与模板等效的项) | 85 | | 73 | [什么是功能组件?](#73-什么是功能组件) | 86 | | 74 | [VueJS 和 ReactJS 有什么相似之处?](#74-VueJS-和-ReactJS-有什么相似之处) | 87 | | 75 | [VueJS 和 ReactJS 有什么不同之处?](#75-VueJS-和-ReactJS-有什么不同之处) | 88 | | 76 | [VueJS 与 ReactJS 相比有什么优势?](#76-VueJS-与-ReactJS-相比有什么优势) | 89 | | 77 | [ReactJS 与 VueJS 相比有什么优势?](#77-ReactJS-与-VueJS-相比有什么优势) | 90 | | 78 | [VueJS 和 AngularJS 有什么不同之处?](#78-VueJS-和-AngularJS-有什么不同之处) | 91 | | 79 | [什么是动态组件?](#79-什么是动态组件) | 92 | | 80 | [keep alive 标签的目的是什么?](#80-keep-alive-标签的目的是什么) | 93 | | 81 | [什么是异步组件?](#81-什么是异步组件) | 94 | | 82 | [异步组件工厂的结构是什么?](#82-异步组件工厂的结构是什么) | 95 | | 83 | [什么是内联模板?](#83-什么是内联模板) | 96 | | 84 | [什么是 X 模板?](#84-什么是-X-模板) | 97 | | 85 | [什么是递归组件?](#85-什么是递归组件) | 98 | | 86 | [如何解决组件间的循环依赖?](#86-如何解决组件间的循环依赖) | 99 | | 87 | [如何确保应用程序时 CSP?](#87-如何确保应用程序时-CSP) | 100 | | 88 | [full 和 runtime-only 之间在构建时的区别时什么?](#88-full-和-runtime-only-之间在构建时的区别时什么) | 101 | | 89 | [列出不同的 VueJS 构建类型?](#89-列出不同的-VueJS-构建类型) | 102 | | 90 | [如何在 webpack 中配置 VueJS?](#90-如何在-webpack-中配置-VueJS) | 103 | | 91 | [VueJS 编译器的用途是什么?](#91-VueJS-编译器的用途是什么) | 104 | | 92 | [Dev Tools 及其用途是什么?](#92-Dev-Tools-及其用途是什么) | 105 | | 93 | [VueJS 的浏览器支持是什么?](#93-VueJS-的浏览器支持是什么) | 106 | | 94 | [如何使用各种 CDN?](#94-如何使用各种-CDN) | 107 | | 95 | [如何强制更新?](#95-如何强制更新) | 108 | | 96 | [VueJS 的 once 指令时什么用途?](#96-VueJS-的-once-指令时什么用途) | 109 | | 97 | [如何访问根实例?](#97-如何访问根实例) | 110 | | 98 | [VueJS 的十大组织?](#98-VueJS-的十大组织) | 111 | | 99 | [renderError 的用途是什么?](#99-renderError-的用途是什么) | 112 | | 100 | [如何访问父实例?](#100-如何访问父实例) | 113 | | 101 | [什么是 Vuex?](#101-什么是-Vuex) | 114 | | 102 | [状态管理模式的主要组成部分是什么?](#102-状态管理模式的主要组成部分是什么) | 115 | | 103 | [如何在 Vuex 中表示单向数据流?](#103-如何在-Vuex-中表示单向数据流) | 116 | | 104 | [什么是 vue loader?](#104-什么是-vue-loader) | 117 | | 105 | [如何在 webpack 中配置 vue loader?](#105-如何在-webpack-中配置-vue-loader) | 118 | | 106 | [什么是 asset url 转换规则?](#106-什么是-asset-url-转换规则) | 119 | | 107 | [如何使用 vue loader 处理预处理器?](#107-如何使用-vue-loader-处理预处理器) | 120 | | 108 | [什么是 CSS 作用域?](#108-什么是-CSS-作用域) | 121 | | 109 | [是否可能将 local 和 global styles 混在一起?](#109-是否可能将-local-和-global-styles-混在一起) | 122 | | 110 | [如何使用 deep 选择器?](#110-如何使用-deep-选择器) | 123 | | 111 | [在 scoped css 中父级样式是否泄漏到子组件中?](#111-在-scoped-css-中父级样式是否泄漏到子组件中) | 124 | | 112 | [如何使用 scoped css 设计动态生成的内容?](#112-如何使用-scoped-css-设计动态生成的内容) | 125 | | 113 | [VueJS 中支持 CSS 模块吗?](#113-VueJS-中支持-CSS-模块吗) | 126 | | 114 | [我能为所有模板使用运行时构建吗?](#114-我能为所有模板使用运行时构建吗) | 127 | | 115 | [如何在 VueJS 中使用 CSS 模块?](#115-如何在-VueJS-中使用-CSS-模块) | 128 | | 116 | [我能使用 CSS 模块预处理器吗?](#116-我能使用-CSS-模块预处理器吗) | 129 | | 117 | [能否为 CSS 模块使用自定义注入名称?](#117-能否为-CSS-模块使用自定义注入名称) | 130 | | 118 | [什么是 vue loader 中的热重载?](#118-什么是-vue-loader-中的热重载) | 131 | | 119 | [热重载的默认行为是什么?](#119-热重载的默认行为是什么) | 132 | | 120 | [如何显式禁用热重载?](#120-如何显式禁用热重载) | 133 | | 121 | [如何使用热重载?](#121-如何使用热重载) | 134 | | 122 | [什么是热重载中的状态保存规则?](#122-什么是热重载中的状态保存规则) | 135 | | 123 | [如何使用 vue-loader 创建函数组件?](#123-如何使用-vue-loader-创建函数组件) | 136 | | 124 | [如何在函数组件中访问全局属性?](#124-如何在函数组件中访问全局属性) | 137 | | 125 | [如何在 VueJS 中执行测试?](#125-如何在-VueJS-中执行测试) | 138 | | 126 | [如何为 CSS 应用 linting?](#126-如何为-CSS-应用-linting) | 139 | | 127 | [如何使用 eslint 插件?](#127-如何使用-eslint-插件) | 140 | | 128 | [什么是 eslint-loader?](#128-什么是-eslint-loader) | 141 | | 129 | [什么是 CSS extraction?](#129-什么是-CSS-extraction) | 142 | | 130 | [什么是自定义语言块?](#130-什么是自定义语言块) | 143 | | 131 | [stylelint 的特点是什么?](#131-stylelint-的特点是什么) | 144 | | 132 | [vuex 应用构建的原则是什么?](#132-vuex-应用构建的原则是什么) | 145 | | 133 | [vuex 支持热重载吗?](#133-vuex-支持热重载吗) | 146 | | 134 | [vuex store 的热重载 API 的目的是什么?](#134-vuex-store-的热重载-API-的目的是什么) | 147 | | 135 | [如何测试 mutations?](#135-如何测试-mutations) | 148 | | 136 | [如何测试 getters?](#136-如何测试-getters) | 149 | | 137 | [node 中运行测试的过程是怎样的?](#137-node-中运行测试的过程是怎样的) | 150 | | 138 | [浏览器中运行测试的过程是怎样的?](#138-浏览器中运行测试的过程是怎样的) | 151 | | 139 | [vuex 中使用严格模式的目的是什么?](#139-vuex-中使用严格模式的目的是什么) | 152 | | 140 | [可以在生产环境使用严格模式吗?](#140-可以在生产环境使用严格模式吗) | 153 | | 141 | [什么是 vuex 插件?](#141-什么是-vuex-插件) | 154 | | 142 | [如何在插件中改变状态?](#142-如何在插件中改变状态) | 155 | | 143 | [vuex store 是什么?](#143-vuex-store-是什么) | 156 | | 144 | [vuex store 和普通的全剧对象有什么不同?](#144-vuex-store-和普通的全剧对象有什么不同) | 157 | | 145 | [不直接更新 state 的原因是什么?](#145-不直接更新-state-的原因是什么) | 158 | | 146 | [什么是单状态树?](#146-什么是单状态树) | 159 | | 147 | [如何安装 vuex?](#147-如何安装-vuex) | 160 | | 148 | [为 vuex 提供 promise?](#148-为-vuex-提供-promise) | 161 | | 149 | [如何在 vue 组建中显示 state?](#149-如何在-vue-组建中显示-state) | 162 | | 150 | [如何将 store 注入子组件?](#150-如何将-store-注入子组件) | 163 | 164 | ## 1. VueJS 是什么? 165 | 166 | **Vue.js** 是一个开源,用于构建用户界面的渐进式 JavaScript 框架。VueJS 的核心库只关注于`视图层`,并且易于装载和集成其他的库或现有的项目。 167 | 168 | ## 2. VueJS 的主要功能是什么? 169 | 170 | 以下是一些 VueJS 可用的主要功能 171 | 1. **虚拟 DOM:** 它使用的虚拟 DOM 类似于其他现有的框架,例如 ReactJS,Ember etc。虚拟内存是一个轻量级的在内存中原生 HTML DOM 的表示形式并且不影响原生 DOM 的更新。 172 | 2. **组件:** 在 VueJS 应用中用于创建可复用的自定义元素。 173 | 3. **模板:** VueJS 提供基于 HTML 的模板并将 DOM 和 Vue 实例的 data 绑定。 174 | 4. **路由:** 通过 vue-router 实现页面之间的导航。 175 | 5. **轻量:** VueJS 相较于其他框架是一个轻量级的库。 176 | 177 | ## 3. VueJS 的生命周期方法是什么? 178 | 179 | 生命周期钩子是一个让你看到你正在使用的库是如何在后台工作的窗口。通过这些钩子,你可以知道你的组件何时被创建、添加进 DOM、更新、及销毁。在详细介绍每一个生命周期钩子之前,让我们一起先看一下生命周期的图表。 180 | 181 |  182 | 183 | 1. **Creation(初始化):** Creation 钩子允许你在你的组件被添加进 DOM 之前执行行为。如果你需要在客户端和服务端渲染期间设置一些操作则需要使用这些钩子。不同于其他钩子,creation 在服务端渲染期间也会运行。 184 | 185 | 1. beforeCreate: 这个钩子会在你的组件初始化时执行。组件中的钩子监听数据 data 并初始化事件。这时 data 还不是响应式的,并且发生在组件生命周期中的事件还未被设置。 186 | 187 | ```javascript 188 | new Vue({ 189 | data: { 190 | count: 10 191 | }, 192 | beforeCreate: function () { 193 | console.log('Nothing gets called at this moment') 194 | // `this` 指向视图模型的实例 195 | console.log('count is ' + this.count); 196 | } 197 | }) 198 | // count is undefined 199 | ``` 200 | 201 | 2. created: 这个钩子会在 Vue 设置了事件并监听 data 之后被调用。这时事件是活跃状态并且能够使用响应式的 data 即使模板还未挂载或渲染。 202 | 203 | ```javascript 204 | new Vue({ 205 | data: { 206 | count: 10 207 | }, 208 | created: function () { 209 | console.log('count is: ' + this.count) 210 | } 211 | }) 212 | // count is: 10 213 | ``` 214 | 215 | **Note:** 记住这点, 你不能使用 DOM 或 挂载元素目标 (this.$el) 在 creation 钩子中。 216 | 217 | 2. **Mounting(DOM 插入):** Mounting 钩子是最常被用到的,它允许你在第一次渲染之后立即使用你的组件。 218 | 219 | 1. beforeMount: beforeMount 允许你在组件第一次渲染后立即使用组件。 220 | 221 | ```javascript 222 | new Vue({ 223 | beforeMount: function () { 224 | // `this` points to the view model instance 225 | console.log(`this.$el is yet to be created`); 226 | } 227 | }) 228 | ``` 229 | 230 | 2. mounted:这个是一个最常被使用的钩子,你可以完全使用响应式的组件、模板、和渲染好的 DOM (via. this.$el)。最常用的模式就是获取组件的数据。 231 | 232 | ```javascript 233 |
I’m text inside the component.
235 |{{counter}}
252 |{{counter}}
277 |Address
442 |Contact Details
443 | 444 | ``` 445 | 446 | ## 9. 如何复用有 key 属性的元素? 447 | 448 | Vue 总是尝试尽可能高效地渲染元素。因此它会试图用重用元素替代从零开始构建。但这种行为会在有些情况下导致一些问题。例如,如果你尝试在 `v-if` 和 `v-else` 块中渲染同样的 input 元素,它将会像下面这样在切换后保留先前的值, 449 | 450 | ```html 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | ``` 460 | 461 | 这种情况下,它不应该重用。我们可以像下面这样在 input 元素上使用 **key** 属性分离, 462 | 463 | ```html 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | ``` 473 | 474 | 上面的代码确保了两个输入框失独立的,且不会影响彼此。 475 | 476 | ## 10. 为什么不能在同一个元素上同时使用 v-if 和 v-for 指令? 477 | 478 | 建议不要使用 v-if 和 v-for 在同一个元素上。因为 v-for 指令比 v-if 优先级高。有两种情况下开发者会尝试这种组合, 479 | 480 | 1. 过滤列表的项。例如,如果你尝试使用 v-if 标记过滤列表, 481 | 482 | ```html 483 |The message is: {{ message }}
811 | ``` 812 | 813 | 记住,v-model 将忽略任何表单元素上的初始 `value`,`checked` 或 `selected` 属性。 814 | 因此总是使用 Vue 实例 data 作为真值来源。 815 | 816 | ## 25. model 支持什么修饰符? 817 | 818 | v-model 指令支持 3 种修饰符。 819 | 820 | **1. lazy:** 默认情况下,v-model 在输入框每次 input 事件后同步数据。你可以添加 lazy 修饰符使在 change 事件后同步。 821 | 822 | ```html 823 | 824 | 825 | ``` 826 | 827 | **2. number:** 如果你想将用户输入的自动格式转换为一个数字,你可以给 v-model 添加一个 number 修饰符。即使使用 type="number",HTML input 元素返回的值总是一个字符串。因此这个类型转换修饰符使很必要的。 828 | 829 | ```html 830 | 831 | ``` 832 | 833 | **3. trim:** 如果你想要将用户输入的空格自动修剪,你可以给 v-model 添加一个 trim 修饰符。 834 | 835 | ```html 836 | 837 | ``` 838 | 839 | ## 26. 组件是什么并给个例子? 840 | 841 | 组件是一个有名字的可重用 Vue 实例。接受与 new Vue 相同的选项,例如 data computed watch methods 和 生命周期钩子(除了 root 特有一些选项如 el)。以计数器组件为例, 842 | 843 | ```javascript 844 | // 定义一个叫 button-counter 的组件 845 | Vue.component('button-counter', { 846 | template: '' 847 | data: function () { 848 | return { 849 | count: 0 850 | } 851 | }, 852 | }) 853 | ``` 854 | 855 | 让我们在 new Vue 创建的 Vue 根实例中使用这个组件 856 | 857 | ```html 858 |
1275 |
1276 |
Welcome to Vue render functions
1882 |Home
" 2095 | }, 2096 | about: { 2097 | template: "About
" 2098 | }, 2099 | contact: { 2100 | template: "Contact
" 2101 | } 2102 | } 2103 | }) 2104 | ``` 2105 | 2106 | 现在你可以在当前页面使用动态组件 2107 | 2108 | ```html 2109 |Treated as component component owne content
2184 |child
2667 |