前端基础面试题·第四篇——Vue(其二)

news2025/10/21 21:27:59

1.Vue中路由传参

1.params传参

  • params 传参是通过URL路径来传递参数,这种方式传递的参数是必选的。
  • 这种传参方式需要在路由配置时在路由路径位置提前指定参数。
  1. 路由配置
const router = new VueRouter({
  routes: [
    {
      path: '/user/:id', // 这里的:id就是参数
      name: 'user',
      component: User
    }
  ]
})
  1. 路由跳转
// 使用 router.push 跳转
router.push({ name: 'user', params: { id: '123' }})

// 使用 router-link 组件
<router-link :to="{ name: 'user', params: { id: '123' }}">User</router-link>

// 使用路径传参
router.push(`/user/${id}`)
  1. 接收参数
    params传递参数可以用过页面路由对象route的params属性访问到。
<!-- template -->
<template>
	<div>{{ $route.params.id}}</div>
</template>
<!-- script setup -->
<script setup>
	import { useRoute } from "vue-router"
	const route = useRoute()
	console.log(route.params.id)
</script>

2.query传参

  • query 传参是通过URL的查询字符串来传递参数,这种方式传递的参数是可选的。
  • 这种方式不需要提前配置路由路径,直接在路由跳转时在路径或者配置中传递参数即可。
  1. 路由跳转
// 使用 router.push 跳转
this.$router.push({ path: '/search', query: { keyword: 'vue' }})

// 使用 router-link 组件
<router-link :to="{ path: '/search', query: { keyword: 'vue' }}">Search</router-link>

// 使用路径传参
router.push(`/user/?id=${id}`)

  1. 接收参数
    这种方式传递的参数会挂载到页面路由对象route的query对象上。
<!-- template -->
<template>
	<div>{{ $route.query.id}}</div>
</template>
<!-- script setup -->
<script setup>
	import { useRoute } from "vue-router"
	const route = useRoute()
	console.log(route.query.id)
</script>

2. hash和history路由区别

  1. hash路由地址上在路径后面带#号,history路由地址上不带#号.
  2. 在刷新界面时,hash路由会加载对应页面,history路由会报404错误,因此需要在前端服务器作出特殊的配置,让其在404错误时直接跳转到首页。(这里出现404错误的原因是当访问页面时,页面路由只有在vuerouter初始化后才有效,因此在这之前是访问不到页面的,需要通过服务器将此时的页面指定到入口页面来初始化vuerouter是页面路由生效)
  3. hash会支持低版本浏览器,history只支持高版本浏览器,因为其是HTML5新增的API。
  4. hash路由不会重新加载页面,history路由会重新加载页面。
  5. history会有历史记录, HTML5新增了pushState和replaceState方法,可以改变url,但是不会刷新页面,也不会产生历史记录。
  6. history是需要服务端配合的,hash路由不需要。

3.watch与computed的区别

这里的对比主要是以Vue3的script setup为主

  1. 主要功能不同:
  • computed是计算属性,watch时监听,监听data中的数据变化。
  • computed主要是用于以某一个响应式数据为基础来计算出一个新的数据使用。当依赖的数据变化之后,会根据计算结果重新计算值。watch主要用于来侦听某一个响应式数据,当数据变化时来执行一些特定的操作。computed更加注重数据,不建议在内部做一些副作用或者与数据计算无关的操作。
  1. 参数不同
  • computed接受一个参数,参数可以是一个getter函数,该函数内部需要至少使用一个响应式函数来计算,并返回计算值(必须要有返回值)。参数也可以是一个配置对象 ,配置对象包含get,set两个方法,get方法与上面的getter函数作为参数要求是一样的。
  • watch函数接收三个参数,第一个参数可以为getter函数或者一个响应式对象,或者是一个包含响应式对象的数据。第二个参数是一个副作用函数,用于在watch数据变化后重新执行。第三个参数传入一个配置对象。第二个参数传入的函数会被自动挂载三个参数,第一个参数为更新后的新值,第二个参数为更新前的旧值,第三个参数是一个函数onCleanup,用户两次变化之间执行清理工作。
  1. 执行效果不同
  • computed函数在初始化的时候就会执行一次,并且会计算出一个结果,将这个结果缓存下来,如果下次数据变化后结果和上一次结果相同,则将上一次的结果返回。
  • watch是一个惰性api,在初始化时不会执行,只有当数据变化后才会执行,通过也不会有缓存机制。
  1. 返回值不同
  • computed函数返回一个ref对象,计算结果就是其value属性,同时在模板中使用时也会自动解包。(本质上是生成一个computedRef对象,并且将传入的getter生成一个effect,首先在函数中调用efferct.run()执行一次获得结果,将结果挂载到ref上,在之后的每一次数据变化都会判断计算结果是否与上一次结果相同,如果不同再重新执行effect.run函数。
  • watch 函数返回一个stop函数,该函数在调用之后就会销毁内部的effect与依赖之间的关联,停止watch的监听。
  1. 其他
  • watch函数第三个参数配置对象可以传入一个immediate: true来实现和computed相似的初始化即执行一次。
  • watch函数第三个参数配置对象可以传入一个deep: true来实现深度监听。
  • watch函数第三个参数配置对象可以传入一个once: true来只执行一次。

4.Vue中的插槽使⽤

1. 插槽

slot 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
插槽本身就是从父组件中传入的,因此可以访问父组件中所有的数据,其作用域与父组件作用域相同。

  • 如果在外部没有传入任何内容的情况下,插槽可以设置,默认内容。
<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

2. 具名插槽

有时在一个组件中包含多个插槽出口是很有用的。举例来说,在一个 BaseLayout 组件中,有如下模板:

<div class="container">
  <header>
    <!-- 标题内容放这里 -->
  </header>
  <main>
    <!-- 主要内容放这里 -->
  </main>
  <footer>
    <!-- 底部内容放这里 -->
  </footer>
</div>

对于这种场景,slot 元素可以有一个特殊的 attribute name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 slot 出口会隐式地命名为“default”。
要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 template 元素,并将目标插槽的名字传给该指令:

<BaseLayout>
  <template v-slot:header>
    <!-- header 插槽的内容放这里 -->
  </template>
</BaseLayout>

v-slot可以简写为#

当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非template 节点都被隐式地视为默认插槽的内容。所以上面也可以写成:

3. 条件插槽

有时你需要根据插槽是否存在来渲染某些内容。

你可以结合使用 $slots 属性与 v-if 来实现。

<template>
  <div class="card">
    <div v-if="$slots.header" class="card-header">
      <slot name="header" ></slot>
    </div>
    
    <div v-if="$slots.default" class="card-content">
      <slot></slot>
    </div>
    
    <div v-if="$slots.footer" class="card-footer">
      <slot name="footer"></slot>
    </div>
  </div>
</template>

"$slots"是一个对象,这个对象上挂载了所有插槽的名称和内容。

4. 动态插槽名

态指令参数在 v-slot 上也是有效的,即可以定义下面这样的动态插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

5. 作用域插槽

在上面的渲染作用域中我们讨论到,插槽的内容无法访问到子组件的状态。
然而在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。
我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:

<!-- <MyComponent> 的模板 -->
<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>

当需要接收插槽 props 时,默认插槽和具名插槽的使用方式有一些小区别。下面我们将先展示默认插槽如何接受 props,通过子组件标签上的 v-slot 指令,直接接收到了一个插槽 props 对象:

<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

v-slot=“slotProps” 可以类比这里的函数签名,和函数的参数类似,我们也可以在 v-slot 中使用解构:

<MyComponent v-slot="{ text, count }">
  {{ text }} {{ count }}
</MyComponent>

具名作用域插槽
具名作用域插槽的工作方式也是类似的,插槽 props 可以作为 v-slot 指令的值被访问到:v-slot:name=“slotProps”。当使用缩写时是这样:

<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</MyComponent>

注意: slot元素的name属性是Vue一个特殊的保留字段,不会作为值传递给插槽。
如果具名插槽和默认插槽都存在,则在默认插槽中如果想使用作用域插槽则必须使用默认名为default的具名插槽,同时在template标签上使用v-slot:default来获取作用域插槽的值。
无渲染组件
一个组件使用作用域插槽,有外部组件来控制其页面样式,同时该组件内部通过一定的逻辑处理需要的数据并通过2作用域插槽传递出去,外部组件使用时可以直接获取到需要的数据源而只关心页面样式,内部组件只需要关心数据处理,而不需要关心页面样式。这样的组件我们称之为无渲染组件。

总结

  1. 子组件使用slot,父组件可以向其传递模板内容,称之为插槽。
  2. 插槽可以通过name属性来命名,具名插槽可以同时存在多个。使用时需要用template标签包裹内容,在其上使用v-slot指令 来指定插槽的名称,也可以使用#来简写。(v-slot:插槽名)
  3. 作用域插槽可以向子组件传递数据,同时接收子组件传递过来的数据。使用时在子组件通过slot绑定属性传递数据,父组件中通过v-slot指令来接收数据。
  4. 默认作用域插槽可以在组件上使用v-slot来接收数据对象,剧名作用域插槽(只要有一个具名)需要在template标签上使用v-slot指令来接收数据对象。
  5. 具名和默认插槽同时使用时需要将默认插槽命名为default。
  6. 具名插槽在子组件中可以使用 s l o t s 来访问是否存在对应的插槽名,也可以使用 slots来访问是否存在对应的插槽名,也可以使用 slots来访问是否存在对应的插槽名,也可以使用scopedSlots来访问插槽内容。
  7. 具名插槽的名称可以使用动态指令参数来定义。

5. Vue响应式

1.ref

ref函数可以用来创建一个响应式的数据,该数据会暴露一个.value属性,我们可以使用这个属性来访问或修改该值。

import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

如果想要在组件模板中访问,我们就需要将该数据声明到setup函数中并返回

import { ref } from 'vue'

export default {
  // `setup` 是一个特殊的钩子,专门用于组合式 API。
  setup() {
    const count = ref(0)

    // 将 ref 暴露给模板
    return {
      count
    }
  }
}
<div>{{ count }}</div>

ref函数可以接受任何类型的值作为参数,ref的响应性具有深层响应特性,简单来说就是改变传入对象的深层属性时,也会触发重新渲染,这是由于ref内部原理中使用了ES6的Proxy代理对象,可以监听对象的属性变化,同时每一次监听到变化后会保存当前依赖,如果访问到深层属性,就会遍历深层属性然后生成代理。
注意: 这里的深层代理与Vue2的深层代理完全不同,谁留的深层代理只有访问到该变量的生成属性才会遍历生成代理,如果没访问深层属性,本质上代理就只有一层。
如果不想慎用深层代理,可以使用shallowRef函数来创建浅层响应式数据。

shallowRef: 这个函数功能上与ref类似,但只会代理一层,即只有value属性改变时才会触发更新,如果value属性是一个对象,改变该对象的属性不会触发更新。

const state = shallowRef({ count: 1 })

// 不会触发更改
state.value.count = 2

// 会触发更改
state.value = { count: 2 }

额外的 ref 解包细节

1. 如果将ref函数赋值给一个响应式对象的属性,则在访问时就会自动解包

  const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // 0 不需要再手动解包
state.count = 1
console.log(count.value) // 1

如果在使用中用一个新的ref来替换掉了state.count,访问时也会直接访问到新值。同时外层的这个响应式对象必须是深层的,如果是一个浅层的就无法自动解报。

2. 当ref数据作为原生数组或者原生map的元素时,不会解包

  const books = reactive([ref('Vue 3 Guide')])
  // 这里需要 .value
  console.log(books[0].value)

  const map = reactive(new Map([['count', ref(0)]]))
  // 这里需要 .value
  console.log(map.get('count').value)
  1. ref在模板中访问时,h会自动解包
  • 在框架内部会对其进行解包,我们直接书写变量名就行。
  • 只有顶级的ref对象才会解包,如果ref对象被赋值到其他的变量属性上,这是访问改变属性上无法得到该数据.
 const count = ref(0)
 const object = { id: ref(1) }
{{ count + 1 }} // 正常显示,因为顶层
{{ object.id + 1 }} // 无法解包,因为不是顶层

这时候我们就需要使用.value来访问,或者我们也可以使用解构语法将数据解构出来使用。

const { id } = object // 这样在模板中使用就会是正常的

2. reactive

reactive函数用来创建一个响应式的数据,该数据是一个代理对象,我们可以使用这个对象的属性来访问或修改该值。

import { reactive } from 'vue'
const state = reactive({ count: 0 })
console.log(state.count) // 0
state.count++
console.log(state.count) // 1

这个函数创建的响应式对象那个就和普通的对象那个没有什么区别,但Vue会拦截这个对象的所有属性,监听变化。
当ref传入的值是一个对象时,在内部就会调用这个方法来创建响应式数据。
所以跟ref一样,这个函数也是会深层代理。

注意: 如果我们不想要深层代理,可以使用shallowReactive函数来创建浅层响应式数据。这个函数也只会浅层监听。

注意: 虽然reactive返回的对象基本上和原对象没什么区别,但由于是代理,两者之间是相互独立的,如果修改了原对象的属性,代理对象不会改变。对一个原始对象调用reactive函数总是会得到一个相同的代理对象,当传入的原始对象那个已经有代理对象时,会直接返回该代理对象。

这里是由于Vue在创建代理对象是都会为每一个代理对象上绑定一个__v_isReactive属性,一但第二次代理该对象,就会判断搞对象那个是否有这个属性,如果有就说明该对象已经被代理过。

局限: reactive函数使用ES6的proxyAPI,但是这个api只能够代理对象数据,无法代理原始数据。 还有就是我们在使用时不可以为响应式对象重新赋值,一但重新赋值就会是去上一次的代理。如果我们该响应式对象结构或者将该属性传递个函数中,就会失去响应式。

因此: Vue官方更建议使用后ref函数来创建响应式数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2198021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

主机加固的关键要素:服务器防病毒

在数字化浪潮中&#xff0c;网络安全已成为企业不可忽视的一环。尤其是安全运维人员&#xff0c;他们肩负着保护企业数据不受侵害的重任。MCK主机加固解决方案&#xff0c;正是为了应对这一挑战而生。 网络安全的严峻现实 不久前&#xff0c;一家知名企业因勒索病毒攻击而被迫…

MVC、MVP和MVVM之间的区别

MVC&#xff08;Model-View-Controller&#xff09; 角色划分&#xff1a; Model&#xff1a;负责处理数据和业务逻辑&#xff0c;通常包括数据的存储、检索和更新等操作。 View&#xff1a;负责展示用户界面&#xff0c;接收用户输入&#xff0c;并将用户操作传递给 Controll…

如何在Visual Studio 2019中创建.Net Core WPF工程

如何在Visual Studio 2019中创建.Net Core WPF工程 打开Visual Studio 2019&#xff0c;选择Create a new project 选择WPF App(.Net Core) 输入项目名称和位置&#xff0c;单击Create 这样我们就创建好了一个WPF工程 工程文件说明 Dependencies 当前项目所使用的依赖库&…

java面向对之象类的继承与多态

目录 1.类的继承 图解 案例:创建一个动物类和一个猫类 1.代码 1)动物类 2)猫类 3.测试类 2.效果 2.父类方法的重写 案例:如何重写父类的方法 1.代码 1&#xff09;Animal类 2&#xff09;Dog类 3&#xff09;测试类 2.效果 3.super关键字 案例:如何在子类中调用父类的方…

如何使用 Puppeteer 和 Browserless 运行自动化测试?

Puppeteer&#xff1a;什么是 Puppeteer 及其功能 Puppeteer 是一个 Node.js 库。使用 Puppeteer&#xff0c;您可以在所有基于 Chromium 的浏览器上测试您的网站&#xff0c;包括 Chrome、Microsoft Edge Chrome 和 Chromium。此外&#xff0c;Puppeteer 可用于网页抓取、自动…

PDF处理技巧:Windows电脑如何选择合适的 PDF 编辑器

您可以阅读本文以了解用于在 PC 上编辑 PDF 的顶级免费软件&#xff0c;而无需花费任何费用即可轻松进行快速编辑、拆分、合并、注释、转换和共享您的 PDF。 PDF 或可移植文档文件是由 Adobe 创建的一种多功能文件格式。它可以帮助您轻松可靠地交换文档&#xff0c;无论相关方…

电脑端视频通过PCIE到FPGA端转UDP网络视频输出,基于XDMA+PHY芯片架构,提供3套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案我这里已有的以太网方案 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频PCIE视频采集QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存UDP视频组包发送UDP协议栈MAC数据缓冲FIFO组Tri Mode E…

基于php+uniapp微信小程序的电子书阅读系统snxr5

目录 项目介绍技术栈和环境说明具体实现截图php技术介绍文件解析微信开发者工具HBuilderXuniapp开发技术简介解决的思路性能/安全/负载方面数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 项目介绍 &#xff08;1&#xff09;用户在安卓APP页面…

微信小程序启动不起来,报错凡是以~/包名/*.js路径的文件,都找不到,试过网上一切方法,最终居然这么解决的,【避坑】命运的齿轮开始转动

app.json "resolveAlias": {"~/*": "/*"},文件代码也没有问题&#xff0c;网上的方法试过来了&#xff0c;大模型AI也问过遍&#xff0c;熬夜到凌晨2点半&#xff0c;最不可思议的是居然是因为微信开发者工具版本的问题&#xff0c;我真的是笑死…

深入了解Oracle OCP认证,开启数据库专业之旅

使用Oracle数据库的公司内部&#xff0c;经常有员工们在讨论OCP认证(Oracle Certified Professional&#xff0c;Oracle认证专家)&#xff0c;这是甲骨文Oracle公司提供的一种专业认证&#xff0c;认证用于使用者在Oracle技术领域的专业知识和技能。 在这里&#xff0c;有一点…

Qt小bug — LINK : fatal error LNK1158: 无法运行“rc.exe“

Qt小bug —— LINK &#xff1a;fatal error LNK1158&#xff1a;无法运行"rc.exe" 环境 Qt 5.14.2 MSVC 2015 x64 现象 解决 在电脑上找到rc.exe 和rcdll.dll &#xff08;一般在C:\Program Files(x86)\Windows Kits*\bin\x64下面&#xff09;拷贝到 C:\Qt\Qt5…

高并发 - 1.进程和线程

1.进程 1.基本概念 1.进程&#xff08;Process&#xff09;&#xff1a;程序的一次启动执行(程序在执行过程中分配和管理资源的基本单位&#xff0c;操作系统资源分配的最小单位)2.程序&#xff1a;存放在硬盘中的可执行文件&#xff0c;主要包括代码指令和数据3.一个进程是一个…

常见的负载均衡

1.常见的负载均衡服务 负载均衡服务是分布式系统中用于分配网络流量和请求的关键组件&#xff0c;它可以帮助提高应用程序的可用性、可扩展性和响应速度。以下是一些常用的负载均衡服务&#xff1a; Nginx&#xff1a;一个高性能的Web服务器和反向代理&#xff0c;广泛用于实现…

【基于YOLOv5的反光衣检测预警系统】可检测图片、视频、摄像头,支持GPU加速检测以及语音播报预警

文章目录 演示视频系统界面项目环境系统界面功能项目框架介绍项目代码获取 ➷点击跳转至文末完整项目代码下载处☇ 演示视频 【基于YOLOv5的反光衣检测预警系统】可检测图片、视频、摄像头&#xff0c;支持GPU加速检测以及语音播报预警 系统界面 项目环境 项目运行所需环境为…

机器学习可视化教程——混淆矩阵与回归图

机器学习可视化教程——混淆矩阵与回归图 关于作者 作者&#xff1a;小白熊 作者简介&#xff1a;精通python、matlab、c#语言&#xff0c;擅长机器学习&#xff0c;深度学习&#xff0c;机器视觉&#xff0c;目标检测&#xff0c;图像分类&#xff0c;姿态识别&#xff0c;语…

大模型从入门到应用——LangChain:模型(Models)-[大型语言模型(LLMs):基础知识!

LangChain系列文章&#xff1a; 基础知识快速入门 安装与环境配置链&#xff08;Chains&#xff09;、代理&#xff08;Agent:&#xff09;和记忆&#xff08;Memory&#xff09;快速开发聊天模型 模型&#xff08;Models&#xff09; 基础知识大型语言模型&#xff08;LLMs&a…

MATLAB APPdesigner中的日期选择器怎样实时显示时间

文章目录 1.问题描述2.代码设置代码示例解释 1.问题描述 我们在做MATLAB的时候&#xff0c;一般需要在APP界面中加上时间显示&#xff0c;像下图中的右上角&#xff0c;在组件中有日期选择器&#xff0c;但是这个并不是实时显示的&#xff0c;我们还需要自己进行设置。 2.代码…

python pyinstaller打包exe遇到报错:RuntimeError: input(): lost sys.stdin

在使用python中的pyinstaller命令打包exe遇到报错:RuntimeError: input(): lost sys.stdin 一、问题复现 import datetimedef record_log():project_name = input("请输入项目名称:")l

毕设分享 基于python的搜索引擎设计与实现

文章目录 0 简介1 课题简介2 系统设计实现2.1 总体设计2.2 搜索关键流程2.3 推荐算法2.4 数据流的实现 3 实现细节3.1 系统架构3.2 爬取大量网页数据3.3 中文分词3.4 相关度排序第1个排名算法&#xff1a;根据单词位置进行评分的函数第2个排名算法&#xff1a;根据单词频度进行…

硬件开发笔记(三十一):TPS54331电源设计(四):PCB布板12V转5V电路、12V转3.0V和12V转4V电路

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142757509 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…