Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解
Element Plus 的 el-transfer
组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。
核心特性与用法
基本属性
-
v-model
:绑定右侧列表的值(key数组) -
data
:组件数据源,需包含key
和label
属性 -
props
:配置数据源的字段别名 -
filterable
:是否启用搜索功能 -
titles
:自定义左右两侧标题 -
button-texts
:自定义按钮文本 -
left-default-checked
/right-default-checked
:设置默认选中项
关键事件
-
change
:当右侧列表变化时触发 -
left-check-change
:左侧选中项变化时触发 -
right-check-change
:右侧选中项变化时触发
插槽
-
默认插槽:自定义列表项内容
-
left-footer
/right-footer
:自定义左右列表底部内容
filter-method 用法详解
1. 基本概念
filter-method
是 Element Plus Transfer 组件的一个属性,用于自定义穿梭框的搜索过滤逻辑。它接受一个函数,该函数有两个参数:
-
query
: 用户输入的搜索关键词 -
item
: 当前遍历的数据项
函数应返回布尔值:
-
true
: 保留该项 -
false
: 过滤掉该项
default 插槽用法详解
1. default 插槽基础用法
default 插槽允许完全自定义每个列表项的显示内容:
html
复制
下载
运行
<el-transfer><template #default="{ option }"><!-- 自定义内容 --><div>{{ option.label }}</div></template> </el-transfer>
使用示例
MaterialApplyDialog.vue
<script setup lang="ts" name="MaterialApplyDialog">
import { ref } from "vue";// 模态框显示标识
const dialogVisible = ref(false);
interface Option {key: number;label: string;disabled: boolean;
}const generateData = () => {const data: Option[] = [];for (let i = 1; i <= 500; i++) {data.push({key: i,label: `Option${i}`,disabled: i % 4 === 0});}return data;
};const data = ref<Option[]>(generateData());
const value = ref([]);// 打开模态框
const openDialog = async () => {dialogVisible.value = true;
};// 隐藏模态框
const closeDialog = () => {dialogVisible.value = false;
};// 过滤方法
const filterMethod = (keywords: string, item: Option) => {// 默认的过滤方法,使用关键字与选项对象的label属性进行匹配// return item.label.toLowerCase().includes(keywords.toLowerCase());// 自定义过滤方法,搜索以关键字结尾的选项,区分大小写return item.label.endsWith(keywords);
};// 确定
const onConfirmClick = async () => {// 关闭模态框closeDialog();
};defineExpose({openDialog
});
</script><template><el-dialogclass="receive-dialog"title="穿梭框应用示例"width="1200px"top="0vh"style="border-radius: 10px"v-model="dialogVisible":close-on-press-escape="true":close-on-click-modal="false":show-close="true"@close="closeDialog"><template #default><el-container class="container"><el-transferclass="custom-transfer"v-model="value":data="data":titles="[`待选内容`, `已选内容`]":button-texts="[`移除`, `添加`]":filterable="true":filter-placeholder="`请输入关键字搜索以其结尾的内容`":filter-method="filterMethod" /></el-container></template><template #footer><div><el-button class="dialog-btn" type="primary" @click="onConfirmClick">确定</el-button><el-button class="dialog-btn" @click="closeDialog">取消</el-button></div></template></el-dialog>
</template><style scoped lang="scss">
/* 穿梭框容器样式 */
.container {width: 100%;height: 80vh;
}
/* 穿梭框样式 - 已通过 Element Plus v2.7.4 测试 */
.custom-transfer {flex: 1;display: flex;justify-content: space-between; /* 首尾元素贴边,中间元素等距 *//* 面板样式 */:deep(.el-transfer-panel) {/**如果所在容器没有设置justify-content: space-between; 又需要穿梭框占满容器,需通过浏览器调试工具,获取到穿梭框容器宽度为1168px,按钮区域占用200px,则面板宽度应该设置为 (1168-200)/2 = 484px,如果所在容器已经设置justify-content: space-between; 又需要穿梭框占满容器,面板宽度可以不用精细计算*/width: 450px;height: 100% !important;display: flex;flex-direction: column;}/* 面板头部样式 */:deep(.el-transfer-panel__header) {background-color: #d3e2f1;display: flex;}/* 面板主体 */:deep(.el-transfer-panel__body) {flex: 1;display: flex;flex-direction: column;}/* 列表区域 - 关键滚动区域 */:deep(.el-transfer-panel__list) {flex: 1;overflow-y: auto;}/* 按钮区域样式 */:deep(.el-transfer__buttons) {display: flex;flex-direction: row; /* 水平排列 */justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */padding: 0 10px;}/* 按钮样式 */:deep(.el-transfer__buttons .el-button) {margin: 0 10px;width: 70px;padding: 8px 15px;/* 蓝色渐变背景 */// background: linear-gradient(135deg, #409eff 0%, #3375b9 100%);// border: none;// color: white;// box-shadow: 0 2px 5px rgba(64, 158, 255, 0.3);}/* 按钮方向指示 */:deep(.el-transfer__buttons .el-button:first-child::after) {content: "<=";}:deep(.el-transfer__buttons .el-button:last-child::after) {content: "=>";}/* 按钮文字提示 */:deep(.el-transfer__buttons .el-button span) {display: none; /* 隐藏按钮文字 */}
}
.dialog-btn {width: 100px;
}
</style>
应用效果:
项目实例
MaterialApplyDialog.vue
特点:
1、自定义过滤方法 filter-method
2、数据项属性别名 props
3、插槽 default
4、插槽 left-footer
5、输入框控制数字输入
6、遍历数组元素检查数据合法性,聚焦元素,全选元素内容
7、结合实际情况调整样式
<script setup lang="ts" name="ReagentApplyDialog">
import { branchWarehouseApplyGenerateForReagentService } from "@/api/branchWarehouse";
import { useReagentOptionList } from "@/hooks/useReagentOptionList";
import { formatToNumber } from "@/utils/formatter";
import { Search } from "@element-plus/icons-vue";
import type { TransferInstance } from "element-plus";
import { ElMessage } from "element-plus";
import { debounce } from "lodash-es";
import { nextTick, ref } from "vue";
import type { IReagentOption } from "../types";// 模态框显示标识
const dialogVisible = ref(false);
// 试剂选项列表,组合式函数 hook
const { reagentOptionList, fetchReagentOptionList, resetReagentOptionData } = useReagentOptionList();
// 搜索内容
const searchVal = ref("");
// 已选试剂id集合
const selectedOptionIds = ref<number[]>([]);
// 穿梭框实例对象
const transferRef = ref<TransferInstance | null>(null);// 打开模态框
const openDialog = async () => {initPageData();await nextTick();dialogVisible.value = true;
};// 隐藏模态框
const closeDialog = () => {dialogVisible.value = false;initPageData();
};// 过滤方法
const filterMethod = (keywords: string, item: IReagentOption) => {// 默认的过滤方法,使用关键字与选项对象的label属性进行匹配return item.reagentName.toLowerCase().includes(keywords.toLowerCase());// 自定义过滤方法,搜索以关键字结尾的选项,区分大小写// return item.reagentName.endsWith(keywords);
};// 确定
const onConfirmClick = async () => {// 检查数据合法性if (!checkValid()) {return;}let selectedOptions = selectedOptionIds.value.map((id) => reagentOptionList.value.find((option) => option.id === id)).filter((option): option is IReagentOption => !!option); // 过滤掉 undefined 并缩小类型// 生成申领单if (selectedOptions.length > 0) {await branchWarehouseApplyGenerateForReagentService(selectedOptions);}// 关闭模态框closeDialog();
};// 检查数据合法性
const checkValid = () => {if (selectedOptionIds.value.length === 0) {ElMessage.warning("请选择试剂");return false;}// 循环遍历已选试剂for (let i = 0; i < selectedOptionIds.value.length; i++) {let option = reagentOptionList.value.find((option) => option.id === selectedOptionIds.value[i]);if ((option?.applyAmount ?? 0) === 0 || (option?.applyAmount ?? 0) > option?.amount!) {if ((option?.applyAmount ?? 0) === 0) ElMessage.warning("请输入申领数量!");else ElMessage.error("申领数量不能大于库存数量!");document.getElementById(`input-apply-amount-${option?.id}`)?.focus();(document.getElementById(`input-apply-amount-${option?.id}`) as HTMLInputElement)?.select();return false;}}return true;
};// 搜索,加装防抖器,防抖处理(leading: true,立即执行、maxWait: 3000,3秒内至少执行一次)
const onSearchClick = debounce(async () => {// 清空已选试剂id集合selectedOptionIds.value = [];// 发送网络请求,获取试剂选项列表await fetchReagentOptionList(searchVal.value);},1000,{ leading: true, trailing: true, maxWait: 3000 }
);// 页面初始化
const initPageData = () => {// 清空左侧过滤框transferRef.value?.clearQuery("left");// 清空右侧过滤框transferRef.value?.clearQuery("right");// 清空搜索框searchVal.value = "";// 清空已选试剂id集合selectedOptionIds.value = [];// 重置试剂选项数据resetReagentOptionData();
};defineExpose({openDialog
});
</script><template><el-dialogclass="receive-dialog"title="试剂耗材申领"width="1200px"top="0vh"style="border-radius: 10px"v-model="dialogVisible":close-on-press-escape="true":close-on-click-modal="false":show-close="true"@close="closeDialog"><template #default><el-container class="container"><el-transferref="transferRef"class="custom-transfer"v-model="selectedOptionIds":data="reagentOptionList":props="{key: `id`,label: `reagentName`}":titles="[`待选试剂`, `已选试剂`]":button-texts="[`移除`, `添加`]":filterable="reagentOptionList.length > 12":filter-placeholder="`请输入关键字搜索试剂`":filter-method="filterMethod"><!-- 自定义列表数据项的内容 --><template #default="{ option }"><div class="transfer-list-option"><div class="transfer-list-option-left"><el-tag type="primary">{{ (option as IReagentOption).reagentName }}</el-tag><el-tag type="info" v-if="(option as IReagentOption).batchNo">{{(option as IReagentOption).batchNo}}</el-tag></div><div class="transfer-list-option-right"><el-tag type="warning">{{ (option as IReagentOption).validityDate }}</el-tag><el-tag class="transfer-list-option-right-amount" type="success">{{(option as IReagentOption).amount}}</el-tag><el-inputv-if="selectedOptionIds.includes((option as IReagentOption).id)":id="`input-apply-amount-${(option as IReagentOption).id}`"class="input-apply-amount"style="width: 85px; text-align: center"v-model="(option as IReagentOption).applyAmount"placeholder="输入申领数量"size="small"clearable@input="(option as IReagentOption).applyAmount = Number(formatToNumber($event, 0))" /></div></div></template><!-- 自定义左侧列表底部的内容 --><template #left-footer><div class="transfer-left-footer"><el-input v-model="searchVal" placeholder="请输入试剂名称" clearable @keydown.enter="onSearchClick"><template #prepend>查找试剂:</template><template #append><el-button :icon="Search" @click="onSearchClick" /></template></el-input></div></template><!-- 自定义右侧列表底部的内容 --><!-- <template #right-footer><div><span>可以自定义右侧列表底部的内容</span></div></template> --></el-transfer></el-container></template><template #footer><div><el-button class="dialog-btn" type="primary" @click="onConfirmClick">确定</el-button><el-button class="dialog-btn" @click="closeDialog">取消</el-button></div></template></el-dialog>
</template><style scoped lang="scss">
/* 穿梭框容器样式 */
.container {width: 100%;height: 80vh;
}
/* 穿梭框样式 - 已通过 Element Plus v2.7.4 测试 */
.custom-transfer {flex: 1;display: flex;justify-content: space-between; /* 首尾元素贴边,中间元素等距 *//* 面板样式 */:deep(.el-transfer-panel) {/**如果所在容器没有设置justify-content: space-between; 又需要穿梭框占满容器,需通过浏览器调试工具,获取到穿梭框容器宽度为1168px,按钮区域占用200px,则面板宽度应该设置为 (1168-200)/2 = 484px,如果所在容器已经设置justify-content: space-between; 又需要穿梭框占满容器,面板宽度可以不用精细计算*/width: 550px;height: 100% !important;display: flex;flex-direction: column;}/* 面板头部样式 */:deep(.el-transfer-panel__header) {background-color: #f5f7fa;display: flex;}/* 面板主体 */:deep(.el-transfer-panel__body) {flex: 1;display: flex;flex-direction: column;}/* 列表区域 - 关键滚动区域 */:deep(.el-transfer-panel__list) {flex: 1;overflow-y: auto;}/* 列表选项 */:deep(.el-transfer-panel__item) {flex: 1;display: flex;align-items: center; /* 垂直居中 */margin: 0;padding-right: 15px;height: 32px;}/* 列表选项 - 最后一个选项 */:deep(.el-transfer-panel__item:last-child) {padding-right: 15px;}/* 按钮区域 */:deep(.el-transfer__buttons) {display: flex;flex-direction: column-reverse; /* 垂直反序排列 */justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */padding: 0;}/* 按钮 */:deep(.el-transfer__buttons .el-button) {margin: 20px 10px;width: 40px;padding: 8px 15px;/* 蓝色渐变背景 */// background: linear-gradient(135deg, #409eff 0%, #3375b9 100%);// border: none;// color: white;// box-shadow: 0 2px 5px rgba(64, 158, 255, 0.3);}/* 按钮文字 */:deep(.el-transfer__buttons .el-button span) {display: none; /* 隐藏按钮文字 */}/* 按钮内容 */:deep(.el-transfer__buttons .el-button:first-child::after) {content: "<="; /* 设置按钮显示内容为 <= */}:deep(.el-transfer__buttons .el-button:last-child::after) {content: "=>"; /* 设置按钮显示内容为 => */}.transfer-list-option {flex: 1;display: flex;flex-direction: row; /* 水平排列 */align-items: center; /* 垂直居中 */height: 32px;&-left {flex: 1;display: flex;justify-content: start; /* 贴左边 */align-items: center; /* 垂直居中 */max-width: 220px;}&-right {flex: 1;display: flex;justify-content: end; /* 贴右边 */align-items: center; /* 垂直居中 */&-amount {width: 40px;}.input-apply-amount {width: 85px;// 输入框的内容居中& :deep(.el-input__inner) {text-align: center;}}}.el-tag {font-size: 14px;}}.transfer-left-footer {display: flex;height: 100%;}
}
.dialog-btn {width: 100px;
}
</style>
应用效果:
相关文章:

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...