整理了下经常在掘金看到的热门知识点(面试题),一些题目按自己思路重新做了解答。 以后还会持续更新,希望对掌握知识有一定帮助。 ps:如果有遗漏或错误,请评论区大声叱责,不胜感谢。
响应式系统
双向数据绑定
定义:是vue的一个语法糖,双向绑定是指通过指令v-model将视图层和数据层的对应数据进行绑定,实现互联。
优点:可以减少大量的代码绑定工作,提高开发效率。
使用:
- 项目中一般在表单中进行使用,将响应式变量的值绑定在表单元素的value上。
- 可以在自定义组件上使用,支持绑定多个model。
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
- vue3.4开始推荐使用defineModel宏,返回的值是一个 ref,可以像其他 ref 一样被访问以及修改。
实现双向绑定:
- 事件监听:监听页面所有可控组件的修改事件,触发事件就将数据赋值给data中对应的属性。
- 数据劫持 + 发布订阅模式:监听响应式对象的属性值改变,在改变后调用一个副作用函数,该函数会修改对应控件的值。
vue响应式原理
定义:响应式就是实现检测数据变化并作出响应。
意义:vue的MVVM框架就是利用响应式在VM层中帮助用户实现数据驱动视图,减少用户对dom的操作,提高开发效率。
实现原理:
- 相应式的实现本质是对数据的劫持,分为两步:①数据被修改时,调用对应的副作用函数。②副作用函数被执行时,读取对应属性的值。
- vue2中利用defineProperty修改对象的两个夹子方法getter和setter进行劫持。
- vue3中使用 Proxy + Reflect 的方式实现数据劫持,Proxy 可以深度拦截对一个对象的基本操作。
vue2响应式存在的问题:
- 对象可能存在嵌套,需要递归进行监听,内存开销较大。
- 不能筛选监听对象,会监听data中所有属性。
- data在初始化后,给其中的对象继续添加属性不会触发响应,必须使用Vue.set。
vue3响应式的优化:
框架角度:
- 使用Proxy劫持数据,轻松实现深层监听。
- Proxy提供更多的拦截方法如apply,deleteProperty等。
开发者角度:
- 更轻量化,抽取响应式api为单独的包,让用户实现有选择性地监听。
- 不需要担心对数组、map等对象的监听导致的问题。
编译器
template模版的编译
介绍:vue中使用complier编译模块将用户编写的template编译为js中可执行的render函数。
好处:允许开发者使用HTML编写视图,比手写render更加直观。
原理:
- 模板解析(parse):将模板代码转化为 AST(抽象语法树)。
- 组织优化(optimize):对 AST 进行静态分析,标记出其中的静态节点,方便后续虚拟 DOM 更新。
- 代码生成(generate):将 AST 转换成渲染函数render的可执行代码。
静态提升
是vue对模板解析的优化,把不带任何动态绑定认为是静态节点,对其进行区分以减少编译时的操作。
实现:
Vue2:
- 编译时会标记静态节点。
- patch方法比对时对静态节点做特殊处理。
vue3:
- 把静态节点提升到渲染函数之外不再进行比对。
- 有足够多连续的静态元素时,vue还会再压缩为一个只包含纯 HTML 字符串“静态 vnode”。
虚拟DOM
定义:虚拟DOM是对真实DOM的一个轻量化的引用,主要为了在编译器重新渲染组件时减少对真实dom的操作。
使用:在模板解析后,渲染器会将真实节点抽象成vnode并存储在vue实例上,如果已存在旧的vnode就会将二者进行比较。只需要找二者的差异并操作真实dom就能实现完整的更新。
补充:而且通过定义不同的渲染器,可以将虚拟dom渲染到不同平台上,提高框架的可拓展性。
diff算法
介绍:为了减少页面更新时的dom操作,通过比对新旧虚拟节点的差别,实现最小量更新。
执行流程:
当组件内响应式数据变更触发组件的更新函数时,更新函数会再次执行render函数得到最新的虚拟dom。使用patch函数比较新旧两个虚拟dom。将变化的地方找到并转化为对应的真实dom操作。
patch比较流程:
- 先判断是否是 key 相同以及 类型标签相同,不相同那么就直接替换。
- 再判断新老节点中是否有文本节点,或新老节点其中一个没有子节点,那么只需要进行简单的替换或删除操作。
- 如果新老节点根节点相同,且都有子节点。就使用updateChildren方法比较它们的子节点。
updateChildren方法:
简单diff
思想:先合并新旧节点,在删除多余节点。缺点:dom操作次数较多。
- 遍历一遍新节点,拿每个节点到旧节点中比较。
- 找到可复用的节点就保存,如果该节点下还有子节点进行深度比较。
- 找到需要移动的节点和需要插入的节点就挂载到真实dom上。
- 遍历一遍旧节点,卸载需要删除的节点。
双端diff(vue2)
- 大致流程是使用四个指针分别指向新老节点的头尾节点,从两端向中间遍历。
- 开启一个while循环,每次循环判断是否为四种理想情况:头头、尾尾、头尾、尾头。如果出现,就复用这对节点或进行简单移动。
- 如果四种理想情况都没有命中,就尝试非头部节点能否复用,将新列表的头部节点的key值代入旧节点列表遍历。如果可复用就移动,找不到对应的就新增。
- 遍历完成后,旧列表仍存在未使用的旧节点就进行删除。
快速diff(vue3)
- 思路是先从两端出发,找到可复用的前置和后置节点,再处理剩余的节点
- 理想情况:只有新列表或旧列表其中之一有剩余节点。
- 此时只需要 挂载剩余的新列表节点 或 删除剩余旧列表节点。
- 若为乱序情况,两个列表都有剩余节点的情况。
- 就根据新旧节点的位置变化构建最长递增子序列。
- 根据最长递增子序列计算可复用节点,挂载新增节点。
构建最长子序列过程:
- 构造一个source数组,用于存储新节点在旧序列的索引。
- 遍历旧序列,判断节点在新序列中是否有对应节点。map查找法:遍历新序列构建一个索引表,以节点的key值为键,索引为值。代入旧序列节点的key值判断能否可复用。
- 没有找到就卸载该节点,找到就记录在source数组中,并记录是否需要移动。
- 若有节点需要移动,就使用lis函数计算source数组的最长递增子序列seq。
- 根据seq序列操作真实节点,移动可复用节点,挂载需要新增节点。
最长递增子序列:是数值列表中最长的递增子序列,不一定连续,但数值上一定要在递增。
vue3 对diff 算法的优化
- 在可复用乱序节点的处理上。vue2是每次在遍历中发现可复用乱序节点,就遍历旧节点插入正确位置。vue3是掐头去尾后,先根据索引生成最长递增子序列再进行移动,减少了dom操作。
- vue3进行了编译期优化,使用patchFlag存储每个节点的更新策略。
key的原理
定义:key是vue给每一个vnode添加的唯一id,用于在diff算法比较新旧节点列表时用于识别 vnode。
使用:
- 一般在v-for时给每个子项添加key。
- 通过更改key值可以强制触发一个组件或元素替换,可以用于触发组件的生命周期钩子。
key值的意义:
- 在没有 key 的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。
- 如果传了 key,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。
- 复杂的子项或可能频繁变动的子项,最好添加key。
- 在vue2的diff比较中,会根据key值判断两个Vnode是否相同,不相同则替换。
- 若key没有赋值则默认为undefined,就需要再继续判断。
组件
生命周期
生命周期就是vue实例从创建到销毁的过程,vue在这个过程每个阶段都暴露了钩子函数,用于开发者添加业务代码。
生命周期的八个阶段:
- setup(vue3):composition API初始化完成。
- beforeCreate:实例初始化完成。
- created:初始化options API完成,可调用methods中的方法,访问和修改data数据,可通过computed和watch完成数据计算。常用于发起请求、初始化data数据等。
- 判断是否有预编译模板。有就读取,没有就实时编译。
- beforeMount:DOM初始化完成但未挂载。
- mounted:已完成DOM的挂载与渲染,可以访问dom元素。
- beforeUpdate:视图层进行更新(组件re-render 和 patch)前调用。可用于获取更新前各种状态。
- updated:视图层更新完成,可获取更新后状态。
- beforeDestroy/beforeUnmounted:实例被销毁前,此时实例属性与方法仍可访问。
- destroyed/Unmounted:实例还未完全销毁前,可用于一些定时器或订阅的取消。
其他生命周期:
- 使用keepAlive时还有 activated 和 deactivated。
- errorCaptured当捕获子孙组件错误时触发。
- renderTracked:vue3新增,开发模式下响应式依赖被追踪时调用。
- renderTriggered:vue3新增,开发模式下响应式依赖触发重新渲染时调用。
- serverPrefetch: vue3新增,实例在服务器上被渲染前调用。
实例挂载
实例挂载是一个递归的过程。挂载组件时,是父组件会先创建,然后子组件创建,但子组件会先挂载,父组件再挂载。
单个实例的挂载过程:
- 创建组件实例。
- 初始化状态和各种响应式数据。
- 进行渲染,转换虚拟dom为真实dom。
- 建立副作用函数的依赖监听,实现响应式。
组件间通信
- props/emit:父子直接通信。
- refs、$children:父组件获取子组件实例。
- parent:子组件获取父组件实例。
- $attrs: 实现爷孙之间传值。
- Vuex/Pinia:状态管理库,可以实现跨组件链通信。
- provide 和 inject:通常成对一起使用,可以让祖先组件对所有后代组件进行依赖注入,无论这个组件的层级有多深。
Computed和watch
Computed:接受一个 getter函数,返回一个只读的响应式 ref 对象。
watch:用于观察一个或多个响应对象并返回一个回调。侦测变化,执行回调。没有返回值,只关心观察值是否变化。
原理:
computed:
- 检测变化:当创建 Computed 时,vue做了实现延时监听,会生成一个 lazy 的 effect 包裹作为参数的 getter。effect副作用函数:主要用于监听数据变化,和Proxy搭配实现响应式。
- 计算:返回一个带有value为访问器属性的对象。当这个对象被访问时,就会执行effect计算。
watch:
- 检测变化:在一个副作用函数中访问要检测的响应式数据,这样响应式数据变化时,副作用函数会重新执行。
- 执行回调:在副作用函数的scheduler选项中保存一个回调函数,scheduler调度函数执行会代替副作用函数执行。
v-show和v-if
v-show:
- 基于css层面隐藏样式,将该元素display属性置为none,没有对dom元素的删除。
- 不会触发生命周期函数。
v-if:
- 组件会被卸载和重新编译,包括其中的子组件。
- 会触发create、mounted、destoryed等生命周期函数。
- 切换时性能消耗更高。
v-for和v-if
说明:v-if主要用于条件渲染。v-for的作用是根据数组渲染一个列表。
使用:有时候在需要不断循环,但每次循环都要判断 组件是否能被展示 时,会同时用到两者。
原理:
- vue2中,vue默认v-for优先级较高,同时使用时,每次渲染会先进行循环判断再进行条件判断。
- 而在vue3中,v-if的优先级更高,所以v-if 的条件判断将无法访问到 v-for 作用域内定义的变量别名:
优化:
- 推荐是用一个带v-if的template元素包裹需要v-for的元素。
- 或computed一个变量提前筛选掉不需要展示的项 。
为什么data属性是一个函数而不是一个对象?
因为vue为了防止多个组件实例共用一个data对象,所以用函数进行了封装。
对nexttick的理解
介绍
- nexttick是等待下一次 DOM 更新刷新的工具方法。
view的更新机制
- 当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的。
- Vue 会把组件更新函数缓存在一个队列中,等待一个时机进行批量更新。
- 这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。
- 所以我们对数据的修改不会立刻体现在DOM上,需要使用nexttick才能获取更新后的DOM状态。
使用场景
- 在状态改变后立即使用,可以稳定获取更新后的DOM状态。
- 可以传递一个回调函数作为参数。
- 或者 await nexttick返回的 Promise实现同步代码。
实现原理:
- vue内部实现了一个异步操作队列queue。
- 每当响应数据被修改时,就会把当前组件的更新函数push到queue队列中排队。
- 队列会生成一个刷新任务FlashJobs,存入事件循环的微任务(Promise.then)队列中,等待所有同步代码执行完毕后执行。
- nexttick方法会将回调函数挂载到更新函数的Promise返回值后,在刷新完毕后立刻执行。
mixin
定义:在vue2中是 创建可重用组件逻辑 的主要方式,在vue3中被组合式函数替代。
使用:
- 将 组件中可复用的逻辑,如 部分created代码或几个methods方法 抽离到一个 mixin对象 中。
- 局部混入:在需要的组件的mixins选项中作为mixin数组引入。
- 在执行时会将mixin中的逻辑和组件本身逻辑合并执行,而且会先执行mixin中的逻辑。
- 全局混入会在每个vue中执行。
slot
定义:插槽元素是作为一个占位符,用来标识父组件的提供的插槽内容在哪里渲染。
使用场景:项目中一般通过插槽提高组件拓展性,比如一个dialog组件,通过插槽就可以展示任意内容,而不需要进行组件重写。
深入介绍:
- 插槽又分为默认插槽,具名插槽,作用域插槽。
- 在组件中只有使用一个插槽时用默认插槽。
- 一个组件中包含多个插槽时要用 具名插槽,用于说明 哪个内容对应哪个插槽。
- 作用域插槽是指在插槽上通过类似传递props,让父组件用 v-slot 指令能使用 子组件传递的数据。
插槽的实现:
在渲染时,父组件中的插槽内容会被编译成一个插槽函数,将具体的插槽内容编译为VNode作为函数返回值。
子组件在 渲染时 调用函数 并 将已编译好的VNode一同渲染。
keep-alive
定义:是vue中的内置组件,用于缓存不活动的组件实例,避免频繁销毁和重建。
项目使用:
- 可以用在用户会频繁切换的组件中,也可以用来实现页面缓存
- 在路由表中,在mate中用isCache字段标识路由是否需要缓存。
- 在根组件中,用keepalive元素包裹router-view,并在includeprop 中判断是否缓存。
- 被缓存的组件有onActivated和onDeactivated两个钩子函数,在进入活跃状态和休眠状态触发。
原理:keepalive会将失活的组件移动到隐藏容器中,并用一个map缓存该组件实例的引用,等待重新活跃时再移出。
Vue3
Vue3和vue2比较
性能上:
- 模板编译上:静态提升和事件缓存。
- 渲染上:重写虚拟Dom实现,优化了diff算法。
- 使用proxy重写响应式系统。因为数组等非原始值的对象的defineOwnProperty内部方法与常规对象不同,
代码体积:
- 使用tree-shaking减少打包体积。
- 移除一些不常用的api。
- API按需引入,更轻量化。
代码组织上:
- composition API。
组件:
- 新增Teleport传送组件。
- 新增Fragment,支持一个组件有多个根组件。
Fragment
定义:是vue3中新增的一种vnode类型,可以实现多根节点组件。
对于Fragment类型的虚拟dom,模板中所有根节点都会存储在children中,而Fragment本身不渲染任何内容。
在Fragment被卸载时,会逐个卸载children中的子节点。
Composition API
定义:允许用户以setup钩子作为入口,通过引入Reactivity API、生命周期、依赖注入等方法集成编写函数。
优点:
- 根据逻辑集中相关代码,增强可读性。
- 避免多个mixin导致的 数据来源不清晰 和 命名冲突。
- 按需引入方法,更轻量化。
使用:
- 一般在setup中创建响应式数据,注册生命周期钩子,创建通用函数,处理业务逻辑。
- 在整个生命周期中,只在挂载时执行一次。
Tree shaking
Tree shaking通过清除多余代码来优化项目打包体积。
Tree shaking是基于ES6模板语法(import与exports),主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量
Tree shaking无非就是做了两件事:
- 编译阶段利用ES6 Module判断哪些模块已经加载
- 判断那些模块和变量未被使用或者引用,进而删除对应代码。
Teleport
定义:传送,用于将组件中某些逻辑上属于该组件,但需要在其他地方渲染的部分传送到组件外部。
项目使用:
- Teleport接收一个to prop来指定传送的目标,这个prop可以接收一个CSS选择器字符串或一个DOM元素对象。
- 可以用于实现视频网站的画中画的效果。如一些海报需要展示,当视口移出时就展示略缩图。
原理:如果组件在渲染时,组件选项type中存在_isTeleport,渲染器就会用process函数将该组件的渲染控制权完全交接出去,实现渲染逻辑的分离。
watchEffect
定义:立即运行一个函数并追踪它的依赖,在依赖改变时就再执行该函数。
和watch区别:
- watchEffect偏向于函数的执行结果,并不关注依赖变化的前后值。
- watch不会立即执行。
ref
定义:提供对原始值的代理。
原理:因为proxy无法拦截对原始值的操作,所以vue选择封装一个ref函数,将原始值作为value包裹在一个wrapper对象中,并使用reactive监听这个对象,实现对原始值的代理。
toRefs实现避免响应丢失:
在setup中使用展开运算符暴露reactive对象的每个属性时,会被转换为普通的对象导致相应丢失。
使用toRefs可以将每个属性都转换为ref对象。
自动脱ref:
为了避免在模板上开发时也要使用ref.value才能获取对象值,vue会改写ref对象的get方法,如果判断是ref,就直接返回value值。set同理。
reactive
定义:接收一个 非原始值 然后返回该 非原始值 的 响应式代理。
原理:内部是用 副作用函数effect + proxy代理的方式实现响应式。
项目中:
- 一般项目中用来监听对象、数组、Map等引用数据类型。
- 对响应式对象的所有属性的访问、修改都会被追踪。
插件
vue插件
定义:vue中插件通常用来为 Vue 添加全局功能。
使用:
- 插件必须暴露一个install方法,install方法接收一个vue构造器和option对象作为参数。
- 可以在install方法内通过 在Vue原型上注册方法 ,自定义一些参数,或在Vue上面挂载组件等方式实现全局添加功能。
- 一般在main.js使用vue.use注册,这个注册要在vue实例创建前完成。
项目使用:UI框架、vuex、vue-router等。
修饰符
定义:修饰符是用来对限定类型以及类型成员的声明。
vue中主要有
- 表单修饰符:.lazy,.number等,用于管理用户在Input元素上的输入。
- 事件修饰符:用于管理事件捕获
-
- .stop:阻止事件冒泡。
- .prevent:阻止默认行为。
- .self:仅元素自身触发时才触发事件。
- .once:事件仅触发一次。
- 鼠标按键修饰符/键值修饰符:用于给相应按键绑定触发事件。
- v-bind修饰符:对prop的属性进行操作。.async:对prop进行双向绑定;
自定义指令
定义:类似vue内部的指令如v-model,v-show等,vue为了方便复用对底层DOM的操作,也支持自定义指令。
vue2中使用:
- 用Vue.directive注册全局指令,在组件中,通过配置 directives 选项来注册自定义指令。
- 两种方法都需要一个 指令名 和 一个钩子函数作为参数,在钩子函数中会得到 被绑定的元素 作为参数。
vue3中:
- 兼容vue2的两种注册方法。
- 在setup中任何 以v前缀开头的驼峰命名法变量 都可以用作自定义指令。
项目使用:
- 表单提交:给提交按钮绑定一个节流函数防止重复提交。
- 权限校验:给组件绑定一个v-has实现每次展示都调用权限校验方法。
vue-router
vue-router是vue中用于控制路由切换的插件。
vue-router主要实现了:
- 通过hash或浏览器的history api拦截浏览器的跳转操作。
- router-view:在路由改变时匹配 routes,渲染对应的组件。
hash模式和history模式区别:
- hash模式url多个#/,配置方式略有差别。
- 浏览器的哈希发生变化时,页面不会重新加载,而是触发一个hashchange,监听该事件实现路由跳转。
- history模式是通过浏览器的history对象,操作浏览器的历史记录,并通过popstate事件捕获操作实现路由跳转。
Vue-router中如何实现懒加载
懒加载是指对于一些不需要实时展示的东西做异步加载。
作用是可以防止加载所需时间过长造成阻塞或者出现白屏。
实现:
- 使用ES6的箭头函数 + imprort方法实现动态引入。
- import配合 webpack的chunkFilename 或 vite的 rollupOptions 可以实现分块打包。
- 而vue的component如果接收到一个以promise形式返回组件的函数,则会缓存该函数,当路由匹配再执行。
vuex
定义:是vue的一个状态管理库,允许跨组件或页面共享状态。
vuex的涉及思想源于 Flux框架,目的是实现以单项数据流管理数据。
vuex主要分为四个部分:
- Action(动作):用于接收视图层发出的消息,可以包含异步操作,不允许直接操作state,但可以调用mutation。
- Mutation:仅支持同步操作,是修改state数据的唯一方法,目前被认为是冗余在pinia已弃用。
- State(单一状态树):作为唯一数据源。(mapState)
- getters:使用getters可以暴露一些state的属性。(mapGetters)
项目中使用:
- 开发多层嵌套组件时,避免繁琐的参数传递,使用vuex进行统一状态管理。
- 管理token和用户信息等全局数据。
Module:
定义:为了避免应用的所有状态集中到一个臃肿的对象上,Vuex允许将 store 分割成多个Module(模块)。
项目使用:
- 在创建store时将所有模块集成到一个对象引入modules选项中。
- action 和Getter 仍在同一命名空间,需要避免重名。
- 可以使用store实例的registerModule方法动态注册模块,用于创建一些区域性的模块。
- pinia实现了更彻底的模块化,store不再是单例模式,开发者可以自行选择store影响的范围。
Pinia
定义:是vue的一个状态管理库,允许跨组件或页面共享状态。
Store:定义是一个保存状态和业务逻辑的实体,用defineStore定义,可以传入一个带有 state、actions 与 getters 属性的 Option。
state(单一状态树):作为唯一数据源。支持直接修改和使用 $patch 修改。
getter:完全等同于 State 的计算属性。常用于暴露state中的数据
action:相当于组件中的 Methods,一般用于定义业务逻辑,根据业务修改state中的状态。
与vuex的区别:
- 删除了Mutation,避免繁琐操作。
- 轻量化,Pinia 大小只有 1kb 左右。
- 更支持组合式API。
- 模块化设计,可以让用户自己创建区域性的store或全局store。
单项数据流
定义:只允许从一个方向来修改状态。
vue中,父组件总是通过 props 向子组件传递数据,防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
优点:
- 状态改变更容易记录和跟踪。
- 单一的操作方式,让数据操作更直观和容易理解,可维护性强。
- 限制了状态修改的方式,让状态变得可预测,容易调试。
缺点:
- 代码量上升,数据流转过程变长,代码重复性变大
- 对状态独立管理的严格要求会让代码显得繁琐。
异步组件
定义:使用vue3的AsyncComponent实现异步组件。
项目中:在加载优先级较低,但体积较大的组件上使用。
原理:接受一个加载器并返回一个包装函数,包装组件根据加载器的状态,决定渲染占位组件还是加载完成的组件。
Vue性能优化
性能的两大指标:首屏加载速度和更新速度。
首屏加载速度:
- ssr提升首屏加载速度
- 路由懒加载:箭头函数+import 实现异步组件。
- 减少打包体积,treeShaking、使用 webpack 进行代码分块并懒加载等。
更新速度:
- vue3中的AsyncComponent可以支持定义异步组件。
- keepalive,优化页面切换。
- v-once:渲染完成后会将子元素视为静态内容并跳过。这可用于优化更新性能。
- v-memo:当组件重新渲染时,如果满足条件,就会跳过更新。用于手动规避不需要的更新。
- 虚拟滚动:vue-virtual-scroller。
- 手动清除dom引用和定时器,避免内存泄漏。
- 减少大型不可变数据的响应性开销
vue-loader
定义:vue对webpack loader的封装。
主要作用:
- 支持解析SFC格式组件。
- 为每个组件模拟出 scoped CSS。
- 提供对函数式组件的支持。
- 提供热重载功能。
- 提供组件内的loader支持。①允许为 Vue 组件的每个部分使用其它的 webpack loader。②将 和 中引用的资源当作模块依赖来处理;
vue风格指南
- 组件命名:根据耦合度决定是否包含父组件名字。
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
- 组件名称应以最高级别(通常是最通用)的单词开头,并以描述性修饰词结尾。
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue