Vue3 中组件的使用(上)

news2025/7/19 17:52:36

目录

  • 前言:
  • 一、什么是组件
  • 二、注册组件
    • 1. 全局注册
    • 2. 局部注册
  • 二、传递数据【父 -> 子】
    • 1. 字符串数组的形式
    • 2. 对象的形式
  • 三、组件事件【子 -> 父】
    • 1. 字符串数组式声明自定义事件
    • 2. 【子组件】触发组件事件
    • 3. 【父组件】监听子组件自定义事件
    • 4. 组件事件例子
  • 总结:

前言:

在编写vue里的SPA(Single Page Application单页面应用)时,我们始终绕不开组件的使用,Vue3 里有一些重要更新,在这里分享给大家。


一、什么是组件

组件(Component)是 Vue.js 最强大的功能之一。

组件可以扩展 HTML 元素,封装可重用的代码。

组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
请添加图片描述

组件就相当于页面的零件,当做正常的标签使用,不过能够进行自定义的数据传输和事件监听。
组件内也能使用其他的组件,任意处都能够使用。


二、注册组件

一个 Vue 组件在使用前需要先被 “注册”,这样 Vue 才能在渲染模板时找到其对应的实现;组件注册有两种方式:全局注册、局部注册


1. 全局注册

可使用 app.component(name, Component)注册组件的方法,在此应用的任意组件的模板中使用

  • name:注册的名字
  • Component:需要注册的组件
// 在 main.js 中注册全局组件
import { createApp } from 'vue'
import App from './App.vue'
// 1:引入需要被注册的组件
import Login from './components/Login.vue' 

const app = createApp(App)

// 2:全局注册组件
app.component('MLogin', Login)

app.mount('#app')
// 我们使用注册的组件
<template>
    <h3>登录系统</h3>
    <!-- 使用全局注册的组件 -->
    <MLogin />
</template>

2. 局部注册

局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用

在组合式 API 中的 <script setup> 内,直接导入的组件就可以在模板中直接可用,无需注册。

<script setup>
// 1:引入需要注册的组件,无需注册
import LoginVue from './components/Login.vue';
</script>

<template>
    <h3>登录系统</h3>
    <!-- 2:使用全局注册的组件 -->
    <LoginVue />
</template>

二、传递数据【父 -> 子】

如果父组件向子组件进行传递数据,那么我们需要在子组件中声明 props 来接收传递数据的属性,可采用字符串数组式或对象式来声明 props
父组件向子组件传递数据,在使用组件
let 的标签上采用属性方式传递的 props 值,可使用 v-bind:: 来绑定属性
组件中 props 中的数据是只读的,不可直接更改,只能通过父组件进行更改

声明与使用

  1. 在选项式 API
    1. 我们可以提供 props 选项来声明接收传递的数据
    2. 在 JS 中可使用 this.$props 来访问声明的自定义的属性
    3. 在视图模板中,可直接访问 props 中声明的自定义属性
  2. 在组合式 API
    1. 我们可以采用 defineProps 宏来声明接收传递的数据
    2. 在 JS 中可使用 defineProps 返回的对象来访问声明的自定义的属性
    3. 在视图模板中,可直接访问 defineProps 中声明的自定义属性

1. 字符串数组的形式

// 字符串数组的形式
<script setup>
  
// 使用 defineProps 宏来声明
defineProps(['flat', 'title']) 
  
</script>

例子:

// 父组件
<script setup>
import { ref } from 'vue';
import ButtonVue from './components/Button.vue';

let isError = ref(false) // 主题
let isFlat = ref(false) // 阴影
let btnText = ref('普通按钮') // 按钮文本
</script>

<template>
    主题:<input type="checkbox" v-model="isError">
    阴影:<input type="checkbox" v-model="isFlat">
    按钮文本:<input type="text" v-model="btnText">
    <hr>
    <!-- 父向子传值,可采用属性的方式赋值 -->
    <ButtonVue :title="btnText" :error="isError" :flat="isFlat"/>
</template>
// 子组件
<script setup>
// 声明接收父组件传递的属性值:自定义属性
let propsData = defineProps(['title', 'error', 'flat'])

function showPropsData() {
    // 在 JS 中,需要通过 defineProps 返回对象来访问 props 的内容
    console.log(propsData)
    console.log(propsData.title)
    console.log(propsData.error)
    console.log(propsData.flat)
}

function changeErrorProps() {
    // 不能直接修改 props 的数据,因为是只读的
    propsData.error = !propsData.error
}
</script>


<template>
    <!-- 在视图模板上,可直接使用 props 中的属性 -->
    <button :class="{ error, flat }" @click="showPropsData" @mousedown.right="changeErrorProps">
        {{ title }}
    </button>
</template>


<style>
button {
    border: none;
    padding: 12px 25px;
}

.error {
    background-color: rgb(197, 75, 75);
    color: white;
}

.flat {
    box-shadow: 0 0 10px grey;
}
</style>

2. 对象的形式

对象形式声明的 props,可以对传来的值进行校验,如果传入的值不满足类型要求,会在浏览器控制台中抛出警告来提醒使用者
对象形式声明的 propskeyprop 的名称,值则为约束的条件

对象中的属性:

type:类型,如 StringNumberBooleanArrayObjectDateFunctionSymbol
default:默认值;对象或者数组应当用工厂函数返回
required:是否必填,布尔值
validator:自定义校验,函数类型

<script>
// 对象的形式
    defineProps({
        // 基础类型检查
        // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
        propA: Number,
        // 多种可能的类型
        propB: [String, Number],
        // 必传,且为 String 类型
        propC: {
            type: String,
            required: true
        },
        // Number 类型的默认值
        propD: {
            type: Number,
            default: 100
        },
        // 对象类型的默认值
        propE: {
            type: Object,
            // 对象或数组的默认值
            // 必须从一个工厂函数返回。
            // 该函数接收组件所接收到的原始 prop 作为参数。
            default(rawProps) {
                return { message: 'hello' }
            }
        },
        // 自定义类型校验函数
        propF: {
            validator(value) {
                // The value must match one of these strings
                return ['success', 'warning', 'danger'].includes(value)
            }
        },
        // 函数类型的默认值
        propG: {
            type: Function,
            // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
            default() {
                return 'Default function'
            }
        }
    })
</script>

例子:

// 父组件
<script setup>
import { ref } from 'vue';
import ButtonVue from './components/Button.vue';

let isError = ref(false) // 主题
let isFlat = ref(false) // 阴影
let btnText = ref('普通按钮') // 按钮文本
</script>

<template>
    主题:<input type="checkbox" v-model="isError">
    阴影:<input type="checkbox" v-model="isFlat">
    按钮文本:<input type="text" v-model="btnText">
    <hr>
    <!-- 父向子传值,可采用属性的方式赋值 -->
    <ButtonVue :title="btnText" :error="isError" :flat="isFlat"/>
</template>
// 子组件
<script setup>
// 声明接收父组件传递的属性值:自定义属性
let propsData = defineProps({
    title: {
        type: String,
        required: true
    },
    error: Boolean,
    flat: Boolean,
    tips: {
        type: String,
        default: '我是一个普通的按钮'
    }
})

function showPropsData() {
    // 在 JS 中,需要通过 defineProps 返回对象来访问 props 的内容
    console.log(propsData)
    console.log(propsData.title)
    console.log(propsData.error)
    console.log(propsData.flat)
}

function changeErrorProps() {
    // 不能直接修改 props 的数据,因为是只读的
    propsData.error = !propsData.error
}
</script>


<template>
    <!-- 在视图模板上,可直接使用 props 中的属性 -->
    <button :title="tips" :class="{ error, flat }" @click="showPropsData" @mousedown.right="changeErrorProps">
        {{ title }}
    </button>
</template>


<style>
button {
    border: none;
    padding: 12px 25px;
}

.error {
    background-color: rgb(197, 75, 75);
    color: white;
}

.flat {
    box-shadow: 0 0 10px grey;
}
</style>

注意:

  1. 所有 prop 默认都是可选的,除非声明了 required: true
  2. Boolean 外的未传递的可选prop将会有一个默认值 undefined
  3. Boolean 类型的未传递 prop 将被转换为 false
  4. prop 的校验失败后,Vue 会抛出一个控制台警告【在开发模式下】
  5. 注意 prop 的校验是在组件实例被创建之前
    1. 在选项式 API 中,实例的属性(比如 datacomputed 等) 将在 defaultvalidator 函数中不可用
    2. 在组合式 API 中,defineProps 宏中的参数不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中

特别提醒:

关于 Boolean 类型转换:
为了更贴近原生 boolean attributes 的行为,声明为 Boolean 类型的 props 有特别的类型转换规则
如声明时:defineProps({ error: Boolean })
传递数据时:
- <MyComponent error/>:相当于 <MyComponent :error="true" />
- <MyComponent />:相当于 <MyComponent :error="false" />


三、组件事件【子 -> 父】

有的时候,父组件在使用子组件时,子组件如何给父组件传值呢?

  1. 子组件声明自定义的事件
  2. 子组件中触发自定义事件(可传值)
  3. 父组件使用子组件时监听对应的自定义事件,并执行父组件中的函数(获取子组件传递的值)

1. 字符串数组式声明自定义事件

  1. 在选项式 API 中,子组件可通过 emits 选项来声明自定义的事件
  2. 在组合式 API 中,子组件可通过 defineEmits() 宏来声明自定义的事件

字符串数组式声明自定义事件

采用字符串数组可以声明简单的自定义事件:

<script setup>
    defineEmits(['inFocus', 'submit'])
</script>

对象式声明自定义事件

采用对象式声明自定义事件,还可以进行校验传递的参数是否符合预期要求
对象式声明自定义事件中,属性名为自定义事件名,属性值则是是否验证传递的参数:

  1. 属性值为 null 则不需要验证
  2. 属性值为函数时,参数为传递的数据,函数返回 true 则验证通过,返回 false 则验证失败,验证失败可以用警告语句提示开发者【注意:无论是 true 还是 false 都会继续执行下去的,父组件都会获取到传递的值】
<script setup> 
defineEmits({
    autoEvent1: null, // 无需校验
    // 需要校验,param 可以是多个参数,返回布尔值来表明事件是否合法
    autoEvent2: (param) => {
        // true 则通过
        // false 则不通过,可以在控制台输入警告语句
    }
})
</script>

2. 【子组件】触发组件事件

在选项式 API 中,可通过组件当前实例 this.$emit(event, ...args) 来触发当前组件自定义的事件
在组合式 API 中,可调用 defineEmits 宏返回的 emit(event, ...args) 函数来触发当前组件自定义的事件
其中上方两个参数分别为:

  • event:触发事件名,字符串类型
  • ...args:传递参数,可没有,可多个
<script setup>

// 自定义事件,并返回 emit 函数
const emit = defineEmits(['changeAge'])

function emitAgeEvent() {
    // 触发自定义事件 changeAge,并传递参数 1,20
    emit('changeAge', 1, 20)
}
</script>

<template>
    <button @click="emitAgeEvent">触发自定义事件</button>
    <hr>
    <!-- 触发自定义事件 changeAge,并传递参数 30 -->
    <button @click="emit('changeAge', 30)">触发自定义事件</button>
</template>

3. 【父组件】监听子组件自定义事件

使用 v-on:event="callback" 或者 @event="callback" 来监听子组件是否触发了该事件

  1. event:事件名字(camelCase 形式命名的事件,在父组件中可以使用 kebab-case 形式来监听)
  2. callback:回调函数,如果子组件触发该事件,那么在父组件中执行对应的回调函数,回调函数声明参数可自动接收到触发事件传来的值
<script setup>
import { ref } from 'vue';

import ButtonVue from './components/Button.vue';

let startAge = ref(0)
let endAge = ref(0)

// 子组件触发事件的回调函数
function addAge(start_age, end_age) {
    console.log('----------------');
    console.log(start_age)
    console.log(end_age)
    startAge.value = start_age
    endAge.value = end_age
}
</script>

<template>
    <h3>
        开始年龄:{{ startAge }}
    </h3>
    <h3>
        结束年龄:{{ endAge }}
    </h3>
    
    <!-- 使用引入的组件,并通过属性传递数据 -->
    <ButtonVue @change-age="addAge" />
</template>

4. 组件事件例子

字符串数组式声明自定义事件

// 父组件
<script setup>
import { reactive } from 'vue';
import StudentVue from './components/Student.vue';

let student = reactive({
    name: 'Jack',
    age: 18,
    sex: '男'
})

// 获取子组件传递值
function getNewAge(newAge) {
    console.log('年龄的新值:' + newAge)
    student.age = newAge
}
function getNewAgeAndName(newAge, newName) {
    console.log('年龄的新值:' + newAge)
    console.log('名字的新值:' + newName)
    student.age = newAge
    student.name = newName
}
function getNewStudent(stu){
    console.log('学生新值:');
    console.log(stu);
    student.age = stu.age
    student.name = stu.name
    student.sex = stu.sex
}
</script>

<template>
    {{ student }}
    <hr>
    <StudentVue 
                @change-student="getNewStudent"
                @change-age-and-name="getNewAgeAndName" 
                @change-age="getNewAge" />
</template>
// 子组件
<script setup>
// 自定义事件
let emit = defineEmits(['changeAge', 'changeAgeAndName', 'changeStudent'])

function emitEventAge() {
    // 选项式通过 this.$emit 触发自定义事件,并传值
    emit('changeAge', 30)
}

</script>

<template>
    <button @click="emitEventAge">更改年龄</button>
    <br>
    <br>
    <button @click="emit('changeAgeAndName', 10, 'Annie')">
        更改年龄和名字
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: 40, name: 'Drew', sex: '男' })">
        更改学生(验证通过)
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: -10, name: 'Tom', sex: '男' })">
        更改学生(验证失败)
    </button>
</template>

对象式声明自定义事件

// 父组件
<script setup>
import { reactive } from 'vue';
import StudentVue from './components/Student.vue';

let student = reactive({
    name: 'Jack',
    age: 18,
    sex: '男'
})

// 获取子组件传递值
function getNewAge(newAge) {
    console.log('年龄的新值:' + newAge)
    student.age = newAge
}
function getNewAgeAndName(newAge, newName) {
    console.log('年龄的新值:' + newAge)
    console.log('名字的新值:' + newName)
    student.age = newAge
    student.name = newName
}
function getNewStudent(stu){
    console.log('学生新值:');
    console.log(stu);
    student.age = stu.age
    student.name = stu.name
    student.sex = stu.sex
}
</script>

<template>
    {{ student }}
    <hr>
    <StudentVue 
                @change-student="getNewStudent"
                @change-age-and-name="getNewAgeAndName" 
                @change-age="getNewAge" />
</template>
// 子组件
<script setup>
// 自定义事件
let emit = defineEmits({
    changeAge: null, // 无需验证
    changeAgeAndName: null, // 无需验证
    changeStudent: stu => {
        if (stu.age <= 0) {
            console.warn('年龄不得小于等于0')
            // false:验证不通过,会有警告语句,父组件依旧可以获取该值
            return false
        }
        // true:验证通过
        return true
    }
})

function emitEventAge() {
    // 选项式通过 this.$emit 触发自定义事件,并传值
    emit('changeAge', 30)
}

</script>

<template>
    <button @click="emitEventAge">更改年龄</button>
    <br>
    <br>
    <button @click="emit('changeAgeAndName', 10, 'Annie')">
        更改年龄和名字
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: 40, name: 'Drew', sex: '男' })">
        更改学生(验证通过)
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: -10, name: 'Tom', sex: '男' })">
        更改学生(验证失败)
    </button>
</template>

总结:

欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003


以上就是 Vue3 中组件的使用(上),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog

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

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

相关文章

【大数据】记一次hadoop集群missing block问题排查和数据恢复

问题描述 集群环境总共有2个NN节点&#xff0c;3个JN节点&#xff0c;40个DN节点&#xff0c;基于hadoop-3.3.1的版本。集群采用的双副本&#xff0c;未使用ec纠删码。 问题如下&#xff1a; bin/hdfs fsck -list-corruptfileblocks / The list of corrupt files under path…

AI算法创新赛-人车目标检测竞赛总结04

队伍&#xff1a;AI000038 小组成员&#xff1a;杨志强&#xff0c;林松 1. 算法介绍 1.1 相关工作 当前流行的目标检测算法主要分为三种&#xff0c;一阶段算法&#xff1a;SSD&#xff0c;FCOS&#xff0c;Scaled&#xff0c;YOLO系列等&#xff1b;二阶段算法&#xff1a…

宝塔搭建实战php悟空CRM前后端分离源码-后端server篇(一)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 有个朋友发消息跟我说&#xff0c;能不能让我录制一期一套开源的悟空CRM系统&#xff0c;然后网上搜了下&#xff0c;搭建起来测试后&#xff0c;感觉还不错&#xff0c;是一套前后端分离的CRM系统&#xff0c;前…

Java浅析电信数据采集

技术&#xff1a;Java等摘要&#xff1a;电信运营系统中&#xff0c;电信计费系统是主要的支撑系统&#xff0c;占有重要地位。对于电信计费系统是电信运营商的核心竞争力之一这一观点愈来愈被业界认同。电信计费系统中的数据蕴含着企业经营态势、客户群分布特征及消费习惯、各…

什么是隔离式数字输入?

隔离式数字输入与数字隔离器虽然它们听起来很相似&#xff0c;但隔离式数字输入和数字隔离器之间实际上存在一些值得注意的差异。看完这篇文章&#xff0c;希望大家能轻松分辨出两种隔离功能的区别。 内部结构 数字隔离器具有提供电流隔离数字信号路径的基本&#xff08;或经…

网易的“草长莺飞二月天”:增长稳健,加码研发,逐浪AI

2月23日&#xff0c;网易发布了2022年第四季度财报。 这是网易与暴雪分道扬镳后的首份财报&#xff0c;加上近期AIGC热度扩散至游戏、教育等各个领域&#xff0c;网易第四季度业绩及其对于GPT等热门技术的探索受到市场关注。 根据财报&#xff0c;第四季度&#xff0c;网易营…

从单管单色到单管RGB,这项MicroLED工艺不可忽视

微显示技术商Porotech&#xff0c;在CES 2023期间展示了最新的MicroLED显示模组。近期&#xff0c;AR/VR光学领域的知名博主Karl Guttag深度分析了该公司的微显示技术&#xff0c;并指出Porotech带来了他见过最有趣的MicroLED技术。Guttag表示&#xff1a;Porotech是本届CES上给…

Airbyte的同步复制模式

ELT 哲学的核心原则&#xff0c;即数据在提取和加载阶段移动时应保持不变&#xff0c;以便始终可以在目标中访问原始数据。由于目标中存在数据的未修改版本&#xff0c;因此将来可以重新转换该版本&#xff0c;而无需从源系统重新同步数据。 基于此哲学&#xff0c;我们看看Air…

已经准备上千道软件测试面试题了,建议大家收藏!!!还有视频详解!

2023华为软件测试笔试面试真题&#xff0c;抓紧收藏不然就看不到了_测试小鬼的博客-CSDN博客_华为软件测试工程师面试题1、对计算机软件和硬件资源进行管理和控制的软件是&#xff08;D&#xff09;A.文件管理程序B.输入输出管理程序C.命令出来程序D.操作系统2、在没有需求文档…

C++类和对象:类的定义、类对象的存储、this指针

目录 一. 对于面向过程和面向对象的认识 二. 类 2.1 struct关键字定义类 2.1.1 C语言中的struct关键字 2.1.2 C中的struct关键字 2.2 class关键字 2.1 使用class关键字定义类 三. 类的访问限定及封装 3.1 类的访问权限及访问限定符 3.1.1 访问权限 3.1.2 访问限定…

3款百里挑一的国产软件,逆天好用,装了就舍不得卸载

推荐3款让你偷懒&#xff0c;让你上头的提效电脑软件&#xff0c;个个功能强大&#xff0c;让你远离加班&#xff01; 很多几个小时才能做好的事情&#xff0c;用上它们&#xff0c;只需要5分钟就行&#xff01;&#xff01; 1、JNPF快速开发平台 JNPF 是一款精巧耐用的软件…

Linux 练习一(思维导图 + 练习过程)

文章目录一、Linux 用户管理及文件操作第一段练习记录&#xff1a;主要对用户进行删除添加设置密码等操作第二段练习记录&#xff1a;主要包括权限设置和查找命令第三段练习记录&#xff1a;关于文件的命令练习第四段练习记录&#xff1a;查找命令及查看内存命令的使用二、Linu…

Linux c:使用二级指针传参,交换两个字符串的函数测试

代码&#xff1a; #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> int swap1(char **p1, char **p2) { char * temp NULL; temp *p1; *p1 *p2; *p2…

C语言和C++的区别和联系,大多数人都说错了

前言 C语言和C到底是什么关系&#xff1f; 首先C和C语言本来就是两种不同的编程语言&#xff0c;但C确实是对C语言的扩充和延伸&#xff0c;并且对C语言提供后向兼容的能力。对于有些人说的C完全就包含了C语言的说法也并没有错。 C一开始被本贾尼斯特劳斯特卢普&#xff08;Bj…

【JDK8新特性之Stream流-Stream流常用的API以及案例实操】

JDK8新特性之Stream流&#xff0c;不知道你在投递简历的时候有没有看到JD(工作岗位要求去描述)上写到熟悉JDK中Stream流的相关使用。如果没有的话&#xff0c;接下来就和我一起学习一下吧 1.原始集合处理数据的弊端->Stream流优势之处&#xff0c;案例演示 自定义一个集合&…

通过操作Cortex-A7核,串口输入相应的命令,控制LED灯进行工作增加编程要求

2.编程要求&#xff1a; 1&#xff09;结构体封装 typedef struct{ char* cmd_arr; //命令行字符串 gpio_t* gpiox;//GPIO组号 unsigned int pin; //引脚编号 status_t status; //LED灯状态 void(*gpio_write_pin)(gpio_t* gpiox,unsigned int pin,status_t status); }cmd_t; 2…

【GlobalMapper精品教程】054:标签(标注)功能案例详解

同ArcGIS标注一样,globalmapper提供了动态标注的功能,称为标签,本文详解标签的使用方法。 文章目录 一、标签配置二、创建标签图层三、标签图层选项1. 标签字段2. 标签样式3. 标签格式4. 标签语言5. 标签优先级一、标签配置 在配置页面的【矢量显示】→标签选项卡下,有标签…

《高性能MySQL》读书笔记(上)

目录 MySQL的架构 MySQL中的锁 MySQL中的事务 事务特性 隔离级别 事务日志 多版本并发控制MVCC 影响MySQL性能的物理因素 InnoDB缓冲池 MySQL常用的数据类型以及优化 字符串类型 日期和时间类型 数据标识符 MySQL的架构 默认情况下&#xff0c;每个客户端连接都…

Java高级编程之Lambda表达式

Lambda表达式 1&#xff0c;语法 利用Lambda 可以更简洁的实现匿名内部类与函数声明与调用&#xff1b;另外&#xff0c;基于Lambda 提供stream 流式处理极大简化对集合的操作 public static void main(String[] args) {//1.标准Lambda使用方式,其中MathOperation为定义的一个…

React 跨域的配置

1、为什么会出现跨域&#xff1f; 浏览器遵循同源政策&#xff08;同源策略三要素&#xff1a;协议相同、域名相同、端口相同&#xff09; 2、配置跨域代理 使用中间件 http-proxy-middleware&#xff08;安装依赖&#xff09; npm install http-proxy-middleware 创建setupP…