当前位置: 首页 > news >正文

vue+ts 基础面试题 (二)

1. v-if / v-show 条件渲染

、示例:

<template><div><p v-if="isVisible">这个文本在 isVisible 为 true 时显示。</p><p v-else>否则显示这个文本。</p><button @click="toggleVisibility">切换显示</button></div>
</template><script setup>
import { ref } from 'vue';const isVisible = ref(true);function toggleVisibility() {isVisible.value = !isVisible.value;
}
</script>
<template><div><p v-show="isActive">这个文本在 isActive 为 true 时可见。</p><button @click="toggleActivity">切换活动状态</button></div>
</template><script setup>
import { ref } from 'vue';const isActive = ref(true);function toggleActivity() {isActive.value = !isActive.value;
}
</script>

二、对比

1. 性能差异

v-if:切换时涉及 DOM 操作 不适合频繁变化的场景。

v-show:切换时只修改 CSS,开销小。适合高频切换的场景。

2. 初始渲染

v-if:条件为假时,元素不会被渲染,节省初始资源。

v-show:元素总是被渲染,然后通过 CSS 隐藏,可能增加初始加载时间。

2.列表渲染 (v-for)

一、列表渲染基础语法

<ul><li v-for="item in items" :key="item.id">{{ item.text }}</li>
</ul>
  • items 是源数据数组,item 是当前迭代的别名。
  • :key 是必需的,推荐使用唯一标识(如 id),帮助 Vue 高效更新 DOM。

二、遍历对象

v-for 可遍历对象的属性,支持值、键名和索引:

<div v-for="(value, key, index) in object" :key="key">{{ index }}. {{ key }}: {{ value }}
</div>
  • value:属性值
  • key:属性名
  • index:遍历顺序索引

三、性能优化与注意事项

  • 始终提供 :key:避免使用索引作为 key,优先使用数据中的唯一标识。
  • 避免 v-forv-if 共用:Vue 会优先执行 v-for,可能导致不必要的计算。推荐使用计算属性过滤数据。
  • 复杂列表使用计算属性:若需过滤或排序,预先处理数据再渲染:
    computed: {filteredItems() {return this.items.filter(item => item.isActive);}
    }
    

四、动态更新列表

Vue 能检测数组变更方法(如 push()splice())并自动更新视图。直接通过索引修改数组或替换整个数组时,需使用 Vue.set 或展开语法:

// 替换数组
this.items = [...this.items, newItem];
// 修改特定项
this.items.splice(index, 1, newItem);

3.事件处理修饰符的作用

一、阻止默认行为

  • .prevent:阻止事件的默认行为(如表单提交后刷新页面)。
  • .stop:阻止事件冒泡(阻止事件向上级元素传播)。

二、键盘/鼠标事件修饰符

  • .enter.tab:仅当按下特定键时触发(如@keyup.enter)。
  • .left.right:限定鼠标左右键触发(如@click.right)。

三、事件触发频率控制

  • .once:事件仅触发一次(如@click.once)。
  • .debounce(需手动实现):防抖,延迟触发事件。

四、框架特有修饰符

  • Vue的.native:监听组件根元素的原生事件。
  • React的passive:优化滚动性能(如onScroll={handleScroll}配合{passive: true})。

代码示例

// Vue模板中使用修饰符
<template><form @submit.prevent="handleSubmit">  <button @click.stop="handleClick">点击</button></form>
</template>
注意事项
  • 修饰符可链式使用(如@click.stop.prevent)。
  • 部分修饰符需结合特定事件(如.enter仅对@keyup有效)。
  • 不同框架的修饰符语法可能不同,需查阅对应文档。

4.插槽的基本概念

一、默认插槽的使用

子组件 ChildComponent.vue

<template><div><h2>子组件标题</h2><slot></slot></div>
</template>

父组件使用:

<template><ChildComponent><p>这是父组件传递的内容</p></ChildComponent>
</template>

二、命名插槽的使用

子组件 LayoutComponent.vue

<template><div><header><slot name="header"></slot></header><main><slot></slot></main><footer><slot name="footer"></slot></footer></div>
</template>

父组件使用:

<template><LayoutComponent><template v-slot:header><h1>这是头部内容</h1></template><p>这是默认插槽的内容</p><template v-slot:footer><p>这是页脚内容</p></template></LayoutComponent>
</template>

三、作用域插槽的使用

子组件 TodoList.vue

<template><ul><li v-for="item in items" :key="item.id"><slot :item="item"></slot></li></ul>
</template><script>
export default {data() {return {items: [{ id: 1, text: '项目1' },{ id: 2, text: '项目2' }]}}
}
</script>

父组件使用:

<template><TodoList><template v-slot:default="slotProps"><span>{{ slotProps.item.text }}</span></template></TodoList>
</template>

四、插槽的简写语法

Vue3 提供了插槽的简写语法,v-slot:header 可以简写为 #header

<template><LayoutComponent><template #header><h1>简写头部内容</h1></template></LayoutComponent>
</template>

五、动态插槽名

<template><LayoutComponent><template #[dynamicSlotName]><p>动态插槽内容</p></template></LayoutComponent>
</template><script>
export default {data() {return {dynamicSlotName: 'header'}}
}
</script>

六、插槽的默认内容

子组件可以在 <slot> 标签内提供默认内容,当父组件没有提供插槽内容时会显示。

<template><button type="submit"><slot>提交</slot></button>
</template>
注意事项
  • Vue3 中废弃了 slotslot-scope 特性,统一使用 v-slot 语法
  • 默认插槽可以使用 v-slot:default 或直接省略
  • 作用域插槽的数据通过对象形式传递,可以使用解构语法
  • 在单个默认插槽的情况下,v-slot 可以直接用在组件标签上

5. 表单双向绑定方法

一、文本输入框(input/textarea)

<template><input v-model="message" placeholder="请输入内容"><p>输入的内容: {{ message }}</p>
</template><script setup>
import { ref } from 'vue'
const message = ref('')
</script>

二、复选框(checkbox)(布尔类型)

1. 单个复选框
<input type="checkbox" v-model="checked">
2. 多个复选框绑定数组:
<input type="checkbox" value="A" v-model="checkedNames">
<input type="checkbox" value="B" v-model="checkedNames">

三、单选按钮(radio)

<input type="radio" value="男" v-model="gender">
<input type="radio" value="女" v-model="gender">

四、下拉选择框(select)

1. 单选下拉框:
<select v-model="selected"><option disabled value="">请选择</option><option value="A">选项A</option>
</select>
2.多选下拉框(绑定数组):
<select v-model="selected" multiple><option value="A">选项A</option>
</select>

五、自定义组件 v-model

在 Vue3 中,自定义组件的 v-model 默认使用 modelValue 作为 prop,update:modelValue 作为事件:

子组件:

<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script><template><input:value="modelValue"@input="$emit('update:modelValue', $event.target.value)">
</template>

父组件使用:

<CustomInput v-model="message" />

六、v-model 修饰符

Vue3 提供了一些有用的修饰符:

  • .lazy - 在 change 事件后同步(而非 input 事件)
  • .number - 将输入转为数字
  • .trim - 自动去除首尾空白字符

示例:

<input v-model.lazy="msg">

6.组件注册方式

一、全局注册

全局注册的组件可以在应用中的任何地方使用,无需再次导入。通常在应用的入口文件(如 main.jsmain.ts)中进行注册。

import { createApp } from 'vue';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue';const app = createApp(App);
app.component('MyComponent', MyComponent);
app.mount('#app');

注册后,可以在任何组件的模板中直接使用 <MyComponent />

二、局部注册

局部注册的组件仅在当前组件中可用,需要在组件的 components 选项中声明。

<template><MyComponent />
</template><script>
import MyComponent from './components/MyComponent.vue';export default {components: {MyComponent}
};
</script>

三、自动全局注册

通过 require.contextimport.meta.glob 可以批量注册组件,适用于大量基础组件的自动化注册。

import { createApp } from 'vue';
import App from './App.vue';const app = createApp(App);const modules = import.meta.glob('./components/*.vue');
for (const path in modules) {const componentName = path.split('/').pop().replace(/\.\w+$/, '');app.component(componentName, defineAsyncComponent(() => modules[path]()));
}app.mount('#app');

四、动态组件注册

动态组件通过 <component :is="..."> 实现,配合 defineAsyncComponent 可以实现按需加载。

<template><component :is="currentComponent" />
</template><script>
import { defineAsyncComponent } from 'vue';export default {data() {return {currentComponent: null};},methods: {async loadComponent() {this.currentComponent = defineAsyncComponent(() =>import('./components/MyComponent.vue'));}}
};
</script>

五、插件注册

通过插件方式批量注册组件,适合组件库或大型项目。

// my-plugin.js
import MyComponent from './components/MyComponent.vue';export default {install(app) {app.component('MyComponent', MyComponent);}
};

在入口文件中使用插件:

import { createApp } from 'vue';
import App from './App.vue';
import MyPlugin from './my-plugin';const app = createApp(App);
app.use(MyPlugin);
app.mount('#app');

7.动态组件(component)的基本用法

一、基础用法

<template><component :is="currentComponent"></component>
</template><script setup>
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
import { ref } from 'vue'const currentComponent = ref('ComponentA')
</script>

二、组件切换与状态保持

动态组件在切换时会销毁旧组件实例,默认不保留状态。使用 <KeepAlive> 包裹可以缓存组件状态。

<template><KeepAlive><component :is="currentComponent"></component></KeepAlive>
</template>

三、传递 Props 与事件

动态组件可以像普通组件一样传递 props 和监听事件。

<template><component :is="currentComponent":someProp="value"@customEvent="handler"></component>
</template>

四、动态导入组件

结合 defineAsyncComponent 实现按需加载组件,优化性能。

import { defineAsyncComponent } from 'vue'const AsyncComponent = defineAsyncComponent(() =>import('./AsyncComponent.vue')
)

五、动态组件与 v-for

动态组件可与 v-for 结合渲染多个不同组件。

<template><componentv-for="(item, index) in items":key="index":is="item.component"></component>
</template>

六、注意事项

动态组件的 is 属性可以是注册的组件名、导入的组件对象或 Vue 组件选项对象。当使用字符串时需确保组件已正确注册。

组件切换时若需执行特定逻辑,可利用生命周期钩子或 onActivated/onDeactivated(与 <KeepAlive> 配合使用)。

8.异步组件加载指南

一、基础异步加载

使用动态导入语法实现按需加载:

import { defineAsyncComponent } from 'vue'const AsyncComponent = defineAsyncComponent(() =>import('./components/MyComponent.vue')
)

在模板中直接使用:

<template><AsyncComponent />
</template>

二、高级配置选项

支持加载状态处理和错误捕获:

const AsyncComponent = defineAsyncComponent({loader: () => import('./components/HeavyComponent.vue'),loadingComponent: LoadingSpinner,  // 加载中显示的组件errorComponent: ErrorDisplay,      // 错误时显示的组件delay: 200,                        // 延迟显示加载状态(ms)timeout: 3000,                     // 超时时间(ms)suspensible: false                 // 是否使用Suspense控制
})

三、Suspense 集成(推荐)

使用 Vue 3 内置的 <Suspense> 组件管理加载状态:

<template><Suspense><template #default><AsyncComponent /></template><template #fallback><div class="loading">加载中...</div></template></Suspense>
</template>

四、 路由级异步加载

结合 Vue Router 实现路由懒加载:

const routes = [{path: '/dashboard',component: () => import('./views/Dashboard.vue')}
]

五、性能优化技巧

  • 预加载策略:在空闲时预加载关键组件
    // 组件定义后预加载
    AsyncComponent.preload()
    
  • 代码分割:配合 Webpack 魔法注释
    defineAsyncComponent(() => import(/* webpackChunkName: "admin" */ './AdminPanel.vue')
    )
    

六、错误处理

全局捕获异步组件错误:

app.config.errorHandler = (err, instance, info) => {if (info === 'async component') {console.error('异步组件加载失败:', err)// 执行错误恢复逻辑}
}

七、使用场景建议

  1. 大型组件($>100\text{KB}$)
  2. 非首屏关键组件
  3. 条件渲染组件($v-if$ 控制的组件)
  4. 路由级组件

9.依赖注入 (provide/inject)

依赖注入是 Vue3 中实现跨层级组件通信的核心机制,通过 provideinject 实现祖先组件向后代组件直接传递数据/方法,避免逐层传递 props 的繁琐流程。

一、核心概念

1.provide

 在祖先组件中声明需共享的数据或方法,支持响应式数据

// 祖先组件
import { provide, ref } from 'vue'setup() {const count = ref(0)const updateCount = () => count.value++// 提供响应式数据和方法provide('countKey', count)provide('updateKey', updateCount)
}
2.inject

在后代组件中注入祖先提供的数据

// 后代组件
import { inject } from 'vue'setup() {const injectedCount = inject('countKey')const injectedUpdate = inject('updateKey')return { injectedCount, injectedUpdate }
}

二、特性详解

1.响应式传递

使用 ref/reactive 提供的数据会自动保持响应性: 

// 后代组件可直接使用
<button @click="injectedUpdate">{{ injectedCount }}</button>
2.注入默认

防止未提供数据时的错误: 

const data = inject('key', '默认值')
3.工厂函

动态生成默认值: 

const config = inject('config', () => ({ color: 'red' }))
4.Symbol 防冲

推荐用 Symbol 作为 key: 

// keys.js
export const COUNT_KEY = Symbol()// 祖先组件
provide(COUNT_KEY, ref(0))// 后代组件
inject(COUNT_KEY)

三、最佳实践

应用场景:全局配置(主题/语言),复杂表单状态管理,插件开发(如 UI 库)

// 主题提供者组件
provide('theme', { primaryColor: '#1890ff' })

注意事项

interface ThemeConfig {primaryColor: string
}
const theme = inject<ThemeConfig>('theme')
provide('data', readonly(sensitiveData))

四、对比 Vue2

特性Vue2Vue3
响应性需手动处理自动追踪
组合式 API不支持原生支持
TypeScript弱类型支持完整类型推断
默认值处理支持函数式默认值

 Provide/Inject 跨层级传值

在 Vue3 中,provideinject 是实现跨层级组件通信的核心 API,适用于祖先组件向任意后代组件传递数据的场景,无需逐层传递 props。

核心机制
  1. provide
    在祖先组件中使用,提供可被注入的数据或方法:

    <script setup>
    import { ref, provide } from 'vue'const count = ref(0)
    const increment = () => count.value++// 提供数据和方法
    provide('counter', {count,increment
    })
    </script>
    

  2. inject
    在任意后代组件中注入数据:

    <script setup>
    import { inject } from 'vue'// 注入祖先提供的数据
    const { count, increment } = inject('counter')
    </script>
    

关键特性
  1. 响应式数据
    通过 refreactive 提供响应式数据,注入后自动保持同步:

    provide('user', reactive({ name: 'Alice', age: 30 }))
    

  2. 默认值设置
    防止未提供数据时的错误:

    const data = inject('key', 'defaultValue')
    

  3. 工厂函数
    动态生成默认值:

    const config = inject('config', () => ({ timeout: 1000 }))
    

最佳实践
  1. Symbol 避免命名冲突

    const counterKey = Symbol()
    provide(counterKey, { count, increment })
    inject(counterKey)
    

  2. 组合式函数封装
    创建可复用的逻辑:

    // useCounter.js
    export function useCounter() {const count = ref(0)provide('counter', count) // 提供数据return { count }
    }export function useInjectCounter() {return inject('counter')
    }
    

  3. 类型安全 (TypeScript)
    使用泛型确保类型:

    interface Counter {count: Ref<number>increment: () => void
    }
    inject<Counter>('counter')!
    

对比 Props
特性Provide/InjectProps
传递方向祖先 → 任意后代父 → 子
层级深度任意深度仅直接子组件
维护成本低(无需中间组件传递)高(需逐层传递)
适用场景全局配置、主题、用户信息紧密耦合的父子通信
注意事项
  • 避免滥用:优先考虑 props/emits,仅在跨多层级时使用
  • 响应式解构:使用 toRefs 保持响应性
    const { count } = toRefs(inject('counter'))
    

  • 只读控制:通过 readonly 防止意外修改
    provide('data', readonly(reactive({ /*...*/ })))
    

通过合理使用 Provide/Inject,可显著简化深层嵌套组件的通信逻辑,同时保持代码的可维护性和响应式特性。

10.Provide/Inject 跨层级传值

在 Vue3 中,provideinject 是实现跨层级组件通信的核心 API,适用于祖先组件向任意后代组件传递数据的场景,无需逐层传递 props。

一、核心机制

1.provid

在祖先组件中使用,提供可被注入的数据或方法: 

<script setup>
import { ref, provide } from 'vue'const count = ref(0)
const increment = () => count.value++// 提供数据和方法
provide('counter', {count,increment
})
</script>
2.inject

在任意后代组件中注入数据: 

<script setup>
import { inject } from 'vue'// 注入祖先提供的数据
const { count, increment } = inject('counter')
</script>

二、关键特性

1.响应式数

通过 refreactive 提供响应式数据,注入后自动保持同步: 

provide('user', reactive({ name: 'Alice', age: 30 }))
2.默认值设

防止未提供数据时的错误: 

const data = inject('key', 'defaultValue')
3.工厂函数 

动态生成默认值:

const config = inject('config', () => ({ timeout: 1000 }))

三、最佳实践

1.Symbol 避免命名冲突
const counterKey = Symbol()
provide(counterKey, { count, increment })
inject(counterKey)
2.组合式函数封装

创建可复用的逻辑: 

// useCounter.js
export function useCounter() {const count = ref(0)provide('counter', count) // 提供数据return { count }
}export function useInjectCounter() {return inject('counter')
}
3.类型安全 (TypeScript)

使用泛型确保类型:

interface Counter {count: Ref<number>increment: () => void
}
inject<Counter>('counter')!

四、对比 Props

特性Provide/InjectProps
传递方向祖先 → 任意后代父 → 子
层级深度任意深度仅直接子组件
维护成本低(无需中间组件传递)高(需逐层传递)
适用场景全局配置、主题、用户信息紧密耦合的父子通信

五、注意事项

避免滥用:优先考虑 props/emits,仅在跨多层级时使用

响应式解构:使用 toRefs 保持响应性

const { count } = toRefs(inject('counter'))

只读控制:通过 readonly 防止意外修改

provide('data', readonly(reactive({ /*...*/ })))

http://www.dtcms.com/a/307435.html

相关文章:

  • 正向运动学(Forward Kinematics,简称FK)和逆向运动学(Inverse Kinematics,简称IK)
  • Java项目:基于SSM框架实现的校园活动资讯网管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
  • 分类-鸢尾花分类
  • 佳维视工业显示器在除尘与过滤设备中的应用
  • 7800系列三端固定式线性稳压器的典型应用电路
  • MakeInstaller: 一款麒麟操作系统安装包制作工具
  • 进阶向:YOLOv11模型轻量化
  • TGD第九篇:三维应用——视频边缘检测
  • 爱普生002墨水与004墨水基本参数及支持机型
  • 【10】大恒相机SDK C++开发 ——对相机采集的原图像数据IFrameData裁剪ROI 实时显示在pictureBox中,3种方法实现(效率不同)
  • 零基础构建MCP服务器:TypeScript/Python双语言实战指南
  • 某讯视频风控参数逆向分析
  • 《C#与.NET Core跨平台开发的融合架构与实践逻辑》
  • 基于STM32的智能温控通风系统设计
  • Web 开发 08
  • 前端核心技术Node.js(四)——express框架
  • 【JavaEE】(7) 网络原理 TCP/IP 协议
  • 前端下载的EXCEL文件无法打开的解决办法
  • 9.Linux 调优与性能检测
  • 前端框架Vue3(四)——组件通信及其他API
  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第一天(HTML5)
  • Java WEB技术-序列化和反序列化认识(SpringBoot的Jackson序列化行为?如何打破序列化过程的驼峰规则?如何解决学序列化循环引用问题?)
  • Amazon RDS for MySQL成本优化:RDS缓存降本实战
  • 三坐标测量机路径规划与补偿技术:如何用算法看见微米级误差?
  • 抖音集团基于Paimon的流式数据湖应用实践
  • 常见的中间件漏洞如tomcat,weblogic,jboss,apache靶场攻略
  • wpf之ContentPresenter
  • 《Java 程序设计》第 14 章 - JavaFX 基础
  • windows服务器 maven 配置环境变量,验证maven环境变量是否配置成功
  • AI在法律合同内容比对的应用实例