面试官:用Vue3 封装一个Modal,支持在模板和js代码中调用
参考链接:Vue3 模态类(Model)封装方案 - 实践参考链接:Vue3丨TS丨7 个思路封装一个灵活的 Modal 对话框
参考链接:Vue3 模态类(Model)封装方案 - 实践参考链接:Vue3丨TS丨7 个思路封装一个灵活的 Modal 对话框
参考链接:react+vue2+vue3 diff算法分析及比较原理分别是什么1. react-diff: 递增法移动节点:移动的节点称为α,将α对应的真实的DOM节点移动到,α在新列表中的前一个VNode对应的真实DOM的后面添加节点:在新列表中有全新的VNode节点,在旧列表中找不到的节点需要添加(通过find这个布尔值来查找)移除节点:当旧的节点不在新列表中时,我们就将其对应的DOM节点移除(通过key来查找确定是否删除)不足:从头到尾单边比较,容易增加比较次数2. vue2-diff: 双端比较DOM节点什么时候需要移动和如何移动,总结如下:头-头:不移动尾-尾:不移动头-尾: ...
源码:export function triggerEffects( dep: Dep | ReactiveEffect[], debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization const effects = isArray(dep) ? dep : [...dep] for (const effect of effects) { if (effect.computed) { triggerEffect(effect,...
Composition API 和 Vue 2.x 中的 Options API 有几个显著的不同点:组织代码的方式:Options API: 使用选项对象来组织组件的选项,例如 data、methods、computed、watch 等,将相关功能分散在不同的选项中。Composition API: 使用函数来组织代码,可以根据逻辑关系将相关代码放在一起,提高了代码的可读性和可维护性。代码复用:Options API: 通过 mixins、extends 等方式实现代码复用,但可能导致命名冲突、逻辑不清晰等问题。Composition API: 使用函数来定义逻辑,可以更灵活地实现代码...
当谈论 Vue 3 中的性能优化时,我们可以更加深入地探讨每个方面的具体实现和优势:虚拟 DOM 优化:Vue 3 中的虚拟 DOM 经过重构和优化,内部数据结构更简洁高效,减少了不必要的对象创建和比较操作,从而提高了渲染性能。引入了静态树提升技术,即在编译阶段识别出静态节点,将其标记为静态,并在渲染时跳过对这些节点的比较和更新,从而减少了渲染开销。编译优化:Vue 3 的编译器经过重构,采用了更加高效的编译策略,可以更快地将模板编译为渲染函数。引入了模板静态分析技术,通过静态分析模板,识别出其中的静态节点和动态节点,减少了不必要的计算和更新操作,提高了编译效率和性能。Tree-shak...
Composition API:Vue 3 引入了 Composition API,这是一个基于函数的 API,使得组件逻辑更加灵活和可复用。Vue 2 使用的是选项式 API,适合简单的组件逻辑,但是对于复杂的组件,选项式 API 可能会导致代码结构混乱和难以维护。Composition API 可以将相关的逻辑组织在一起,提高了代码的可读性和可维护性,同时也更容易进行单元测试和代码重用。Teleport(传送门):Vue 3 引入了 Teleport 组件,可以将组件的内容渲染到任意的 DOM 节点中,这在创建模态框、下拉菜单等组件时非常有用。Vue 2 中可以通过使用 portal...
在Vue项目中处理错误通常涉及以下几个方面:1. 全局错误处理可以使用Vue的全局错误处理函数来捕获整个应用范围内的错误。可以通过Vue的 config.errorHandler 或者 Vue.config.errorHandler 来配置全局错误处理函数。这个函数接收三个参数:错误对象、错误信息和Vue实例。你可以在这个函数中处理错误的记录、报警、展示等逻辑。Vue.config.errorHandler = function (err, vm, info) { // 处理错误 console.error('全局错误:', err, info); };2. 组件内错误处...
路由配置问题: SPA 使用前端路由来控制页面导航,而不是通过传统的页面跳转。如果 Nginx 配置不正确,无法正确处理前端路由,就会导致部分页面无法访问,出现404错误。需要在 Nginx 的配置中设置对于前端路由的转发规则,确保所有页面 都被正确导向到入口文件(比如 index.html),由前端路由来处理。
权限控制在前端项目中通常涉及接口权限、路由权限、菜单权限和按钮权限等方面。下面我将详细说明每个方面的权限控制实现方法:接口权限控制在前端项目中,接口权限控制通常指的是根据用户角色或权限级别限制用户对特定接口的访问权限。以下是实现接口权限控制的一般步骤:后端接口权限设计: 后端根据业务需求设计接口权限,通常在接口的请求头或请求参数中携带用户的认证信息或角色信息。前端接口请求拦截: 前端通过axios等工具拦截所有接口请求,在请求发送前进行权限验证,验证通过后才发送请求,否则拒绝发送请求或者跳转到错误页面。处理请求结果: 在接收到接口的响应结果后,根据后端返回的状态码或响应数据进行相应的处理...
为什么用SSR优势:SEO优化: 由于搜索引擎爬虫在渲染页面时可以直接获取到HTML内容,因此能够更好地理解页面内容,有利于SEO优化。首屏加载性能: SSR能够提供更快的首屏加载速度,因为用户在接收到HTML内容后就可以开始渲染页面,而不需要等待JavaScript的下载和执行。更好的用户体验: 用户在等待JavaScript下载和执行的过程中可能会感到页面加载速度慢,使用SSR能够提供更好的用户体验,尤其是对于低网速或低性能设备的用户。有利于浏览器缓存: 由于SSR返回的是完整的HTML页面,可以更容易地利用浏览器缓存来提升页面加载速度。使用SSR会有什么问题服务器负载增加: SSR...
什么是虚拟dom虚拟 DOM(Virtual DOM)是一个 JavaScript 对象,它是对真实 DOM 的一种轻量级表示。虚拟 DOM 是由 React 框架引入的概念,后来被其他框架如 Vue、Angular 等广泛采用。虚拟 DOM 的存在有以下几个主要原因:性能优化:DOM 操作是相对昂贵的操作,频繁地进行 DOM 更新会导致性能下降。而虚拟 DOM 可以在内存中进行操作,通过批量更新真实 DOM,减少了对真实 DOM 的频繁操作,从而提升了性能。跨平台兼容性:虚拟 DOM 的概念使得前端框架可以在不同的平台上工作,因为底层的 DOM 操作被框架封装了起来,与平台无关。方便的...
表单防止重复提交// 1.设置v-throttle自定义指令 Vue.directive('throttle', { bind: (el, binding) => { let throttleTime = binding.value; // 节流时间 if (!throttleTime) { // 用户若不设置节流时间,则默认2s throttleTime = 2000; } let cbFun; el.addEventListener('click', event => { if (!cbFun) { //...
Vue.js 中常用的修饰符有以下几种:1. .prevent:阻止默认事件的触发。<a v-on:click.prevent="handleClick">点击我不会跳转</a>2. .stop:阻止事件冒泡。<div v-on:click.stop="handleClick">点击我不会触发父元素的点击事件</div>3. .once:只触发一次事件,之后移除监听器。<button v-on:click.once="handleClick">点击我只会触发一次<...
缓存与更新Vue 中可以通过 <keep-alive> 组件来缓存组件。<keep-alive> 会缓存其内部的组件树,而不是销毁它们。当组件在 <keep-alive> 内部切换时,不会触发销毁和重新创建,而是会触发相应的生命周期钩子。要使用 <keep-alive> 缓存组件,只需将需要缓存的组件包裹在 <keep-alive> 标签内部即可。例如:<template> <div> <keep-alive> <component :is="curre...
省流:使对象变成响应式,类似于Vuex,比Vuex更轻量定义state// 引入vue import Vue from 'vue // 创建state对象,使用observable让state对象可响应 export let state = Vue.observable({ name: '张三', 'age': 38 }) // 创建对应的方法 export let mutations = { changeName(name) { state.name = name }, setAge(age) { state.age = age } }直接使用&...
在 Vue 中,有三种类型的插槽:默认插槽(Default Slot):如果组件没有具名插槽,那么任何没有被包裹在具名插槽中的内容都会被传入到组件的默认插槽中。默认插槽在父组件中以普通的 HTML 或其他 Vue 组件的形式被传入。具名插槽(Named Slot):具名插槽允许您在父组件中使用特定的插槽名称,以便将内容传递到子组件的指定插槽中。这种方式让您可以更精细地控制父组件中的内容如何分发到子组件的不同插槽中,提高了组件的灵活性和可重用性。作用域插槽(Scoped Slot):作用域插槽允许子组件将数据传递到父组件中,并且可以在父组件中使用该数据进行渲染。它们允许父组件在插槽内容中使...
在Vue中,Mixin 是一种可重用的组件选项,它允许你在多个组件之间共享一些通用的功能或逻辑。Mixin 将一组选项合并到一个组件中,可以包括 data、methods、computed、watch 等选项。应用场景包括但不限于:代码复用: 如果有一些功能在多个组件中需要使用,可以将这些功能提取为一个Mixin,并在需要的组件中引入使用,从而避免代码重复。跨组件通用逻辑: 当多个组件需要共享一些通用的逻辑时,可以将这些逻辑提取到Mixin中,以便在多个组件中复用。扩展框架功能: 可以使用Mixin扩展Vue框架的功能,比如添加全局的方法、指令、过滤器等。增强组件功能: 可以使用Mixi...
以下代码打印什么?<template> <div class="demo"> <p class="name">{{ name }}</p> <button @click="modify">修改</button> </div> </template> <script lang="ts" setup> const name = ref("111"); const...
原理在 Vue 源码中,nextTick 方法的实现是基于异步任务队列和微任务队列的机制。下面是其大致实现原理:首先,Vue 使用了一个数组 callbacks 来存储 nextTick 方法传入的回调函数。当调用 nextTick 方法时,将传入的回调函数推入 callbacks 数组中。Vue 利用异步任务队列(如 setTimeout 或 setImmediate)或微任务队列(如 Promise 或 MutationObserver)的机制来确保回调函数在 DOM 更新之后执行。在异步任务队列或微任务队列中,Vue 会执行一个任务函数,该任务函数遍历 callbacks 数组,并...
原代码<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Simple Vue</title> </head> <body> <div id=&quo...
1. Props/Events(父子组件通信):父组件通过 Props 向子组件传递数据,子组件通过 Events 向父组件发送消息。父组件:<template> <ChildComponent :message="parentMessage" @notify="handleNotify" /> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { component...
Vue2在 Vue.js 中编写插件通常需要遵循以下步骤:创建插件:创建一个 JavaScript 文件,编写你的插件代码。定义插件:在插件代码中,定义一个对象或者函数作为你的插件。实现插件功能:在插件对象或者函数中实现你的插件功能,可以包括全局组件、指令、过滤器、混入等。注册插件:使用 Vue.use() 方法注册你的插件。下面是一个简单的示例,演示了如何编写一个 Vue 插件:// 定义插件 const MyPlugin = { install(Vue, options) { // 添加全局方法或者属性 Vue.myGlobalMethod = function ...
当动态给 Vue 的 data 添加一个新的属性时,页面不会刷新的原因是因为 Vue 不会自动检测到新属性的添加并触发视图更新。Vue 实例在初始化时会对 data 中的属性进行响应式处理,但对于在实例创建后动态添加的属性,并不会被 Vue 实例所追踪。解决这个问题的方法是使用 Vue.set 方法或者 this.$set 方法来添加新属性。这两个方法可以确保新添加的属性被 Vue 实例正确地响应式追踪,从而触发视图更新。另外,如果是在模板中使用了动态添加的属性,Vue 也不会自动更新视图,需要手动触发重新渲染。可以通过修改已经存在的响应式属性来触发重新渲染,或者使用 this.$for...
为什么是函数?在 Vue.js 中,组件的 data 属性如果直接使用对象的形式,会导致多个组件实例 共享同一个数据对象 ,从而造成数据的污染和混乱。为了避免这种情况,Vue.js 推荐将 data 属性定义为一个函数,每次创建组件实例时,都会调用这个函数返回一个新的数据对象,从而保证每个组件实例都拥有独立的数据对象,互不影响。具体来说,当 data 属性是一个函数时,Vue.js 在初始化组件实例时会调用这个函数,并将返回的对象作为组件实例的数据对象,确保每个组件实例都拥有自己的数据对象,不会相互影响。这样可以有效地避免多个组件实例共享数据对象带来的问题,提高了组件的封装性和复用性。什...
v2 中:v-for 优先级比v-if高,同时使用浪费性能v3 中:v-if优先级比v-for高,同时使用可能会报错,例如:<!-- 这会抛出一个错误,因为属性 todo 此时 没有在该实例上定义 --> <li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo.name }} </li>在外先包装一层 <template> 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):<template v-for=&qu...
<body> hello,world <input type="text" id="model"> <p id="word"></p> </body> <script> const model = document.getElementById("model") const word = document.getElementById("word") var obj= {}; const ...
原理轮播的原理就是通过translateY/translateX移动轮播容器+过渡达到轮播项上下左右轮播效果的,为了达到无缝循环效果,这里在轮播容器的末尾追加第一项内容,如:【“1”,“2”,“3”,“4”】这四项是我想轮播的内容,此时在容器末尾还追加了“1”,当轮播到“4”时,“4”与“1”之间的切换就达到了无缝效果,在切换到末尾的“1”时,等待过渡结束后取消过渡,立即切换到开头的“1”,这样就达到了将末尾切换到开始的循环.代码<template> <div style="height: 200px; overflow: hidden">...
v-if 和 v-show 是 Vue.js 中用于条件渲染的两个指令,它们有以下不同点:1. 渲染方式:v-if:根据条件表达式的值来决定是否渲染元素。如果条件为 false,则不会在 DOM 中渲染该元素,如果条件为 true,则会将该元素插入到 DOM 中。v-show:根据条件表达式的值来决定是否显示元素。无论条件为 true 还是 false,该元素始终会渲染到 DOM 中,但是当条件为 false 时,该元素的 display 属性会被设置为 none,从而隐藏元素。2. DOM 操作:v-if:在条件表达式的值发生变化时,根据新的条件值来销毁或创建 DOM 元素。因此,当条...
Vue.directive('permission', { // 指令的定义 inserted(el, binding, vnode) { // 获取权限值 const permission = binding.value; // 假设有一个检查权限的函数 checkPermission(permission),如果没有权限则移除元素 if (permission !== 'ok') { el.parentNode.removeChild(el); } } });使用:<template> <butto...
在 Vue2 中自定义指令可以通过定义一系列钩子函数来实现对元素的控制和操作。以下是几个常用的自定义指令钩子函数及其作用:1. bind 钩子函数:bind 钩子函数会在指令第一次绑定到元素时调用,只调用一次。在 bind 钩子中,你可以执行一次性的初始化操作,如绑定事件监听器、设置初始值等。2. inserted 钩子函数:inserted 钩子函数会在被绑定元素插入到父节点时调用。在 inserted 钩子中,你可以执行一些操作,如执行 DOM 操作、获取元素尺寸等。这个时候可以确保元素已经被插入到 DOM 中。3. update 钩子函数:update 钩子函数会在包含指令的组件的...
Vue 中的 computed 和 watch 是两种用于监听数据变化的方式,它们有一些区别,主要体现在以下几个方面:1. 计算属性 vs. 监听属性:computed 是一种计算属性,它会根据其所依赖的响应式数据进行计算,并且具有缓存机制,只有在其依赖项发生变化时才会重新计算。watch 是一种监听属性,它用于监听特定数据的变化,并且可以在数据变化时执行自定义的回调函数。2. 用法和语法:在模板中使用 computed 属性时,你可以直接像使用普通属性一样访问它,Vue 会自动计算并返回计算属性的值。watch 属性需要在组件的选项中定义一个对象,其键是要监听的数据,值是一个回调函数,...
在Vue中,computed属性是一种依赖于响应式数据的计算属性。它们会根据它们所依赖的响应式数据进行计算,并且具有缓存机制,只有在其依赖项发生变化时才会重新计算,这样可以避免不必要的重复计算。computed属性的实现涉及到Vue响应式系统的内部原理,主要包括以下几个关键点:1. 依赖收集: 当定义一个 computed 属性时,Vue 会通过 defineComputed 函数将这个属性定义到组件的实例对象上。在这个过程中,Vue 会通过 Object.defineProperty 或 Proxy 将这个 computed 属性添加到组件的实例对象中,并为其设置 getter 和 s...
Vue.nextTick是Vue.js提供的一个方法,用于在下次 DOM 更新循环结束之后执行延迟回调。它的原理涉及Vue的异步更新队列和JavaScript的事件循环机制。具体来说,Vue.nextTick的原理如下:1. Vue的异步更新队列: 当数据变化时,Vue并不会立即更新DOM,而是将DOM更新操作放入一个队列中。这个队列会在适当的时候执行,以保证在同一个事件循环中对DOM进行批量更新,提高性能并避免不必要的重复计算和渲染。2. JavaScript事件循环机制: 在浏览器环境中,JavaScript是单线程执行的,它通过事件循环机制来处理异步任务。事件循环由多个任务队列组成...
在Vue.js中,当你使用诸如push、pop、splice等数组变异方法时,Vue会拦截这些方法的调用,并且在执行完数组操作后,通知Vue更新相关的视图。Vue对数组方法进行变异的基本原理是通过劫持数组对象的原型链来实现的。当Vue实例的数据被初始化时,它会遍历数据对象,为对象的每个属性设置 getter 和 setter。但是,对于数组而言,这种方式并不适用,因为数组的方法(如push、pop等)是直接作用在数组本身上,而不是数组中的某个属性。为了解决这个问题,Vue使用了一种称为"观察数组"的策略。在支持的JavaScript引擎中,Vue会将数组的原型指向一个经过包装的特殊对象,...
渲染大量数据时,可以采取以下几种优化策略:1. 虚拟列表:使用虚拟滚动技术,只渲染可见区域的内容,而不是将所有数据一次性渲染到页面上。这样可以显著提高页面性能,减少渲染时间和内存消耗。2. 分页加载:将大量数据分成多页进行加载,每次只加载当前页的数据,避免一次性加载大量数据导致页面卡顿和性能下降。3. 数据缓存:如果数据不经常变化,可以考虑将数据进行缓存,减少重复获取和渲染数据的次数。4. 异步加载:在渲染大量数据时,可以考虑使用异步加载的方式,将数据分批加载到页面上,避免一次性加载大量数据导致页面卡顿。5. Object.freeze 冻结对象,避免vue劫持
O(n^3) 表示的是算法的时间复杂度,其中 n 表示输入数据的规模。在这里,n 表示树的深度或节点数量。在比较两棵树时,一种可能的假设是每个节点都需要与另一棵树中的每个节点进行比较。如果两棵树的深度都为 n,那么在最坏的情况下,比较操作的次数将达到 n^2,因为需要对两棵树的每个节点进行比较。此外,如果考虑到树的每个节点可能都需要递归比较其子节点,那么在最坏情况下,每个比较操作可能都需要 O(n) 的时间。因此,总的比较操作的时间复杂度将是 O(n^3)。简而言之,O(n^3) 表示的是一种在最坏情况下的估算,考虑了比较操作的数量和每次比较操作的时间复杂度。
vue的生命周期:beforeCreate created beforeMount mounted beforeDestory destoryed beforeUpdate updated父组件和子组件钩子执行顺序1. 加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted父组件挂载完毕肯定是等里面的子组件都挂载完毕后才算父组件挂载完毕了,所以父组件的mounted在最后。2. 子组件更新过程(子...
在 Vue 2.x 中,Vue 的响应式系统主要依赖于 Object.defineProperty 来实现对数据的劫持和监听。然而,Object.defineProperty 存在一些缺陷,导致了 Vue 在某些情况下的性能和功能上的限制,主要包括以下几点:1. 无法监测数组的变化:Object.defineProperty 只能劫持对象的属性,而不能直接劫持数组的变化。当直接修改数组的索引或者长度时,Vue 无法自动检测到这种变化,需要通过特定的方法(如 push、pop、splice 等)来修改数组,才能触发 Vue 的响应式更新。2. 只能劫持对象已有的属性:Object.defi...
官方文档链接当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model 会比较棘手:<input v-model="obj.message">假设这里的 obj 是在计算属性中返回的一个属于 Vuex store 的对象,在用户输入时,v-model 会试图直接修改 obj.message。在严格模式中,由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。用“Vuex 的思维”去解决这个问题的方法是:给 <input> 中绑定 value,然后侦听 input 或者 change 事件,在事...
为什么不能修改?为了保证数据的单向流动,便于对数据进行追踪,避免数据混乱。怎么检测的?if (process.env.NODE_ENV !== 'production') { var hyphenatedKey = hyphenate(key); if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( ("\"" + hyphenatedKey + "...
Vuex 中的 mutation 和 Redux 中的 reducer 都是用来修改状态的纯函数,它们的设计初衷是为了保证状态的可预测性和可维护性,不应该包含异步操作。主要原因有以下几点:1. 纯函数特性:mutation 和 reducer 都必须是纯函数,即给定相同的输入,必须始终产生相同的输出,而且不应该有副作用。如果允许异步操作,会导致函数的执行结果不可预测,破坏了纯函数的特性。2. 单一数据源:Vuex 和 Redux 都遵循单一数据源的原则,即整个应用的状态都被存储在一个单一的对象中。如果允许在 mutation 或 reducer 中进行异步操作,可能会导致状态的不一致性,...
虚拟 DOM(Virtual DOM)和操作原生 DOM 相比,往往在性能上有一定的优势,但并不意味着在所有情况下都比原生 DOM 操作快。以下是我对这个问题的想法:1. 批量更新和高效更新:虚拟 DOM 可以通过批量更新来减少 DOM 操作次数,它会收集多次更新操作,然后一次性地将更新应用到实际的 DOM 上,减少了浏览器重排(reflow)和重绘(repaint)的次数,从而提高了性能。2. 跨平台兼容性:虚拟 DOM 是框架层面的抽象,能够跨平台使用,无论是在浏览器端还是在服务器端,都可以通过统一的接口进行 DOM 操作,这种灵活性和跨平台的特性使得虚拟 DOM 在一些需要同时支持...
v-model 是 Vue 中用于实现双向数据绑定的指令。它的原理可以分为两个部分:1. 语法糖:v-model 实际上是一个语法糖,它绑定了 value 属性和 input 事件。在表单元素(如 input、select、textarea)上使用 v-model,Vue 会自动生成对应的 value 绑定和 input 事件监听。2. 数据绑定:v-model 绑定了组件实例的数据,通过将输入框的值与数据属性双向绑定,实现了用户输入的实时反映到数据上。当用户在输入框中输入内容时,input 事件会触发,将输入框的值更新到组件的数据属性上;同时,数据属性的变化也会实时更新到输入框中,实现...
Vue 的双向数据绑定是其核心特性之一,它使得数据和视图之间的同步变得更加简单和高效。在 Vue 中,双向数据绑定的实现主要依赖于响应式系统和指令。1. Model 如何改变 View: 当 Model 发生变化时,Vue 会自动检测到这些变化,并且更新对应的 View。这个过程是通过 Vue 的响应式系统来实现的。当我们在 Vue 实例中声明了一个数据属性时,Vue 会将这个属性转化为可观察的对象,然后利用 Object.defineProperty() 来劫持这个属性的 getter 和 setter 方法。当数据属性被修改时,setter 方法会通知 Vue,然后 Vue 就会...
不写key时就地复用节点:在比较新旧两个节点是否是同一个节点的过程中会判断成新旧两个节点是同一个节点,因为 a.key 和 b.key 都是 undefined。所以不会重新创建节点和删除节点;所以可能在某种程度上(创建和删除节点方面)会有渲染性能上的提升;但是只是针对无状态的组件来说;对于有状态的组件,如果复用可能会出现一些未知的bug;写key时维持组件的状态,保证组件的复用。因为有 key 唯一标识了组件,不会在每次比较新旧两个节点是否是同一个节点的时候直接判断为同一个节点,而是会继续在接下来的节点中找到 key 相同的节点去比较,能找到相同的 key 的话就复用节点,不能找到的话...
最近评论