Vue 实现高级穿梭框 Transfer 封装

server/2024/11/10 11:12:21/

文章目录

  • 01 基础信息
    • 1.1. 技术栈
    • 1.2. 组件设计
      • a. 竖版设计稿
      • b. 横版设计稿
  • 02 技术方案
    • (1)初定义数据
    • (2)注意事项
    • (3)逻辑草图
  • 03 代码示例
    • 3.1. 组件使用
    • 3.2. 组件源码
      • ./TransferPlus/index.vue
      • ./TransferPlus/TransferTable.vue

01 基础信息

1.1. 技术栈

Element-UIVue2lodash

1.2. 组件设计

需求描述:

  1. 【待选择列表】 接收业务的表格数据,支持选择多项并将其添加到【已添加列表】 (勾选或删除操作,两边的列表是同步的);
  2. 【已添加列表】支持本地分页和本地简易搜索功能(已添加的列表数据需要实时同步给业务);

a. 竖版设计稿

穿梭框竖版设计稿

b. 横版设计稿

穿梭框横版设计稿

02 技术方案

(1)初定义数据

javascript">// 【待选择列表】外部传输源数据
// 【已添加列表】组件内部控制数据的分页、搜索和展示const props = {sourceList: [], // 源数据columnList: [], // 表格列配置(注:字段类型均为字符串)searchList: [], // 【已添加列表】搜索项(注:与表头对应)refreshTableData: (param)=>{}, // 回调函数total: 0, // 用于控制分页器
}const state = {targetList: [], // 目标数据searchList: [], // 【已添加列表】搜索项
}

(2)注意事项

  1. 【待选择列表】翻页选择时需要记录并回显已选择的行
  2. 【已添加列表】删除后需要继续留在当前页,即要判断删除的是否是最后一页中只有一条的数据
  3. 【待选择列表】更改选择后,【已添加列表】的筛选项或是状态项是否重置?或是维持不变?

(3)逻辑草图

逻辑草图

03 代码示例

3.1. 组件使用

外部可通过 ref 调用的方法:

  1. clearSelection():清空所有选择项;
  2. setPaginationParam({pageNum,pageSize},isFetch):设置源表格分页器参数,若 isFetch 为 true 则会自动调用 fetchSourceListisFetch 默认为 false );
  3. initializeComponent(isFetch):初始化组件,若 isFetch 为 true 则初始化后自动请求源表格数据( isFetch 默认为 false );
  4. this.$refs['transferPlus'].selectList:若要初始化 selectList 可以使用 ref 设置(记得外面包裹 this.$nextTick);

注意事项:

  1. 使用插槽自定义表格列时,是同时应用到两个列表中的;
  2. 组件会通过 selectionChange 事件告知您选择的列表结果;
  3. 特别地,组件一开始不会默认请求源表格数据,所以您需要在使用前自行调用 fetchSourceList 获取 sourceList 等来渲染组件的数据,组件只会在内部的分页状态等有更改的情况下自动调用 fetchSourceList 为您刷新渲染数据;
  4. usePaginationtrue,则组件自动为您控制分页器,但您必须设置好变量(sourceTotal)和源表格数据请求方法(fetchSourceList),并且为了防止您初始请求的分页参数和组件内部定义的默认初始分页参数不同,您可以设置 initSourcePageNuminitSourcePageSize 来同步内外初始化参数;
javascript"><template>  <TransferPlus ref="transferPlusRef":sourceList="sourceList" :tableColumnList="tableColumnList" usePagination tableHeight="240" :sourceTotal="sourceTotal" :tableLoading="tableLoading" @fetchSourceList="fetchSourceList" ><!-- "table_"后拼接的是你定义该列的prop --><template #table_tag="{ row, rowIndex }">{{ rowIndex + 1 }}{{row.tag}}</template><!-- 自定义源表格的搜索区域 --><template #source_search><el-input placeholder="请输入课程名称" v-model="queryInfo.title" class="search-input" clearable><el-button slot="append" icon="el-icon-search" @click="searchSourceList"></el-button></el-input></template></TransferPlus>
</template><script>import TransferPlus from '@/components/TransferPlus'export default {components: { TransferPlus },data() {sourceList: [],    tableColumnList: [{ label: '课程id', prop: 'id' },{ label: '课程名称', prop: 'title' },{ label: '课程类型', prop: 'tag' },],tableLoading: false,sourceTotal: 0,queryInfo: {pageNum: 1,pageSize: 10,title: '',tag: '',},}method:{async fetchSourceList (params={pageNum,pageSize}) {this.tableLoading = trueconst { pageNum, pageSize } = this.queryInfothis.queryInfo = {...this.queryInfo,pageNum: params?.pageNum || pageNum,pageSize: params?.pageSize || pageSize,}const res = await getList(this.queryInfo)this.sourceList = res.data.list || []this.sourceTotal = res.data.total || 0this.tableLoading = false},searchSourceList() {// 每次查询时只需要重置穿梭框的页码到 1,并配置自动调用搜索函数this.$refs['transferPlusRef'].setPaginationParam({ pageNum: 1 }, true)},}}</script><style scoped>.search-input {margin-bottom: 12px;width: 100%;height: 32px;}</style>

实现效果图:
实现效果图

3.2. 组件源码

./TransferPlus/index.vue

javascript"><!--  
组件使用方式如下:<TransferPlus :sourceList="sourceList" :tableColumnList="tableColumnList" usePagination tableHeight="240" :sourceTotal="sourceTotal" :tableLoading="tableLoading" @fetchSourceList="fetchSourceList" ><template #table_你定义该列的prop="{ columnProps }">{{ columnProps.$index + 1 }}{{columnProps.row.xxx}}</template></TransferPlus>method:{async fetchSourceList (params={pageNum,pageSize}) {this.tableLoading = trueconst res = await getList({ ...this.queryInfo, ...params })this.sourceList = res.data.listthis.sourceTotal = res.data.totalthis.tableLoading = false}}
外部可通过 ref 调用的方法:
1. clearSelection():清空所有选择项;
2. setPaginationParam({pageNum,pageSize},isFetch):设置源表格分页器参数,若 isFetch 为 true 则会自动调用 fetchSourceList( isFetch 默认为 false );
3. initializeComponent(isFetch):初始化组件,若 isFetch 为 true 则初始化后自动请求源表格数据( isFetch 默认为 false );
4. this.$refs['transferPlusRef'].selectList:若要初始化 selectList 可以使用 ref 设置(记得外面包裹 this.$nextTick);
注意事项:
1. 使用插槽自定义表格列时,是同时应用到两个列表中的;
2. 组件会通过 selectionChange 事件告知您选择的列表结果;
3. 特别地,组件一开始不会默认请求源表格数据,所以您需要在使用前自行调用 fetchSourceList 获取 sourceList 等来渲染组件的数据,组件只会在内部的分页状态等有更改的情况下自动调用 fetchSourceList 为您刷新渲染数据;
4. 若 usePagination 为 true,则组件自动为您控制分页器,但您必须设置好变量(sourceTotal)和源表格数据请求方法(fetchSourceList),并且为了防止您初始请求的分页参数和组件内部定义的默认初始分页参数不同,您可以设置 initSourcePageNum 和 initSourcePageSize 来同步内外初始化参数;-->
<template><div :class="direction === 'horizontal' ? 'transfer-horizontal' : ''"><!-- 【待选择列表】 --><div :class="['list-wrapping', { horizontal: direction === 'horizontal' }]"><div class="wrapping-header"><span>待选择列表</span><span>{{ selectLength }}/{{ sourceTotal || sourceList.length }}</span></div><div class="wrapping-content"><!-- 自定义搜索 --><slot name="source_search" /><TransferTableref="sourceTransferTableRef"v-model="selectList":tableList="sourceList":tableColumnList="tableColumnList":tableHeight="tableHeight":total="sourceTotal":initPageNum="initSourcePageNum":initPageSize="initSourcePageSize":usePagination="usePagination":tableLoading="tableLoading":uniqueKey="uniqueKey":selectable="selectable":pagerCount="pagerCount"@fetchTableList="handleFetchTableList"><!-- 使用穿梭表格的自定义列插槽 --><template v-for="(item, index) in tableColumnList" :slot="`inner_table_${item.prop}`" slot-scope="slotData"><span :key="index"><!-- 设置新的插槽提供给消费端自定义列 --><slot :name="`table_${item.prop}`" :columnProps="slotData.columnProps" :row="slotData.columnProps.row" :rowIndex="slotData.columnProps.$index">{{ slotData.columnProps.row[item.prop] || '-' }}</slot></span></template></TransferTable></div></div><!-- 【已添加列表】 --><div :class="['list-wrapping', { horizontal: direction === 'horizontal' }]"><div class="wrapping-header"><span>已添加列表</span><span>{{ selectLength }}</span></div><div class="wrapping-content"><template v-if="selectLength"><el-input placeholder="请输入内容" v-model="searchStr" class="search-input" clearable><el-select slot="prepend" v-model="searchKey" placeholder="请选择" class="search-select" @change="handleSearchKeyChange" value-key="prop"><el-option v-for="item in targetSearchList" :key="item.prop" :label="item.label" :value="item.prop"></el-option></el-select><el-button slot="append" icon="el-icon-search" @click="handleSearchStrChange"></el-button></el-input><TransferTableref="targetTransferTableRef":tableList="targetList":tableColumnList="tableColumnList":tableHeight="tableHeight"tableType="target":uniqueKey="uniqueKey":total="targetTotal":usePagination="usePagination":pagerCount="pagerCount"@removeSelectRow="handleRemoveSelectRow"@fetchTableList="getTargetTableList"><!-- 使用穿梭表格的自定义列插槽 --><template v-for="(item, index) in tableColumnList" :slot="`inner_table_${item.prop}`" slot-scope="slotData"><span :key="index"><!-- 设置新的插槽提供给消费端自定义列 --><slot :name="`table_${item.prop}`" :columnProps="slotData.columnProps" :row="slotData.columnProps.row" :rowIndex="slotData.columnProps.$index">{{ slotData.columnProps.row[item.prop] || '-' }}</slot></span></template></TransferTable></template><div class="empty-box" v-else><el-image class="empty-image" :src="require('@/assets/empty_images/data_empty.png')" /></div></div></div></div>
</template><script>import TransferTable from './TransferTable.vue'import { throttle, differenceBy, filter, isNil, noop } from 'lodash'export default {components: { TransferTable },props: {// 源数据sourceList: {type: Array,default: () => [],},// 表格列配置列表tableColumnList: {type: Array,default: () => [], // {label,prop,align}[]},// 表格数据是否加载中tableLoading: {type: Boolean,default: false,},// 表格高度tableHeight: {type: String | Number,default: 240,},// 【已添加列表】搜索项(注:与表格列配置对应,且仅能搜索字段类型为 String)searchList: {type: Array,default: () => [], // {label,prop}[]},// 源表格总数据的条数sourceTotal: {type: Number,default: 0,},// 源表格初始 pageNum(用于同步消费端初始化请求时的分页参数,进而帮助控制分页器)initSourcePageNum: {type: Number,default: 1,},// 源表格初始 pageSize(用于同步消费端初始化请求时的分页参数,进而帮助控制分页器)initSourcePageSize: {type: Number,default: 10,},// 使用分页器usePagination: {type: Boolean,default: false,},// 唯一标识符(便于定位到某条数据进行添加和移除操作)uniqueKey: {type: String,default: 'id',},// 穿梭框展示方式direction: {type: String,default: 'vertical', // horizontal 左右布局, vertical 上下布局},selectable: {type: Function,default: noop(),},// 页码按钮的数量,当总页数超过该值时会折叠(element规定:大于等于 5 且小于等于 21 的奇数)pagerCount: {type: Number,default: 7,},},data() {return {selectList: [], // 已选择的列表targetList: [], // 已添加列表的回显数据searchKey: '',searchStr: '',targetPageNum: 1,targetPageSize: 10,targetTotal: 10,}},computed: {targetSearchList() {return this.searchList.length ? this.searchList : this.tableColumnList},selectLength() {return this.selectList?.length || 0},},watch: {selectList(newVal) {this.getTargetTableList()this.$emit('selectionChange', newVal)},},mounted() {this.searchKey = this.targetSearchList[0].propthis.targetPageNum = 1this.targetPageSize = 10},methods: {handleFetchTableList(params) {this.$emit('fetchSourceList', params)},handleRemoveSelectRow(rowItem) {this.selectList = differenceBy(this.selectList, [rowItem], this.uniqueKey)},handleSearchStrChange() {// 每次查询时只需要重置穿梭框的页码到 1,并配置自动调用搜索函数this.$refs['targetTransferTableRef'].setPaginationParam({ pageNum: 1 }, true)},handleSearchKeyChange() {// 更新搜索 Key 之后,需要清空搜索字符串this.searchStr = ''this.$refs['targetTransferTableRef'].setPaginationParam({ pageNum: 1 }, true)},getTargetTableList(params = null) {const targetTableList = filter(this.selectList, (item) => {if (this.searchStr) {const itemValueToString = isNil(item[this.searchKey]) ? '' : JSON.stringify(item[this.searchKey])return itemValueToString.includes(this.searchStr)} else {return true}})this.targetTotal = targetTableList.lengthif (params) {this.targetPageNum = params.pageNumthis.targetPageSize = params.pageSize}// 前端分页const startIndex = (this.targetPageNum - 1) * this.targetPageSizeconst endIndex = this.targetPageNum * this.targetPageSizethis.targetList = targetTableList.slice(startIndex, endIndex)},clearSelection() {// 清空所有选择项(用于消费端设置的 ref 调用)this.selectList = []this.targetPageNum = 1this.targetPageSize = 10this.searchKey = this.targetSearchList[0].prop},setPaginationParam({ pageNum, pageSize }, isFetch) {// 设置源表格分页器参数(用于消费端设置的 ref 调用)//  若 isFetch 为 true,则自动调用消费端传进来的回调搜索方法this.$refs['sourceTransferTableRef'].setPaginationParam({ pageNum, pageSize }, isFetch)},initializeComponent(isFetch) {// 初始化组件(用于消费端设置的 ref 调用)//  若 isFetch 为 true,则自动调用消费端传进来的回调搜索方法this.clearSelection()this.setPaginationParam({ pageNum: this.initSourcePageNum || 1, pageSize: this.initSourcePageSize || 10 }, isFetch)},},}
</script><style lang="scss" scoped>.transfer-horizontal {display: flex;}.list-wrapping {margin-bottom: 12px;border-radius: 2px;border: 1px solid #d9d9d9;background: #fff;overflow: hidden;}.horizontal {flex: 1;margin-right: 20px;margin-bottom: 0px;&:last-child {margin: 0px;}}.wrapping-header {width: 100%;padding: 10px 20px;height: 40px;display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #d9d9d9;background: #f5f5f5;color: #333;font-size: 14px;line-height: 20px;}.wrapping-content {padding: 12px;width: 100%;}.search-input {margin-bottom: 12px;max-width: 500px;height: 32px;}.search-select {width: 120px;}.empty-box {display: flex;align-items: center;justify-content: center;width: 100%;height: 100%;margin: 40px 0px;}.empty-image {width: 150px;height: 150px;}:deep(.search-input .el-input-group__prepend) {background-color: #fff;}:deep(.el-select .el-input .el-select__caret) {color: #3564ff;}
</style>

./TransferPlus/TransferTable.vue

javascript"><template><div><!-- 表格区域 --><el-tableref="transferTable"v-loading="tableLoading":border="true":data="tableList"size="mini":stripe="true":height="tableHeight || 'auto'":row-class-name="getTableRowClassName":header-cell-style="{background: '#F1F1F1',}"@select="handleSelect"@select-all="handleSelectAll"><el-table-column type="index" align="center"></el-table-column><el-table-column type="selection" width="50" v-if="tableType === 'source'" :selectable="selectable"></el-table-column><el-table-column v-for="(item, index) in tableColumnList" :key="item.prop || index" :label="item.label" :prop="item.prop" :align="item.align || 'left'" :width="item.width || 'auto'" show-overflow-tooltip><template #default="columnProps"><slot :name="`inner_table_${item.prop}`" :columnProps="columnProps"><span>{{ columnProps.row[item.prop] }}</span></slot></template></el-table-column><el-table-column fixed="right" label="操作" width="70" align="center" v-if="tableType === 'target'"><template slot-scope="scope"><el-button @click="handleRemoveRowItem(scope.row, scope.$index)" type="text" icon="el-icon-delete" size="medium"></el-button></template></el-table-column></el-table><!-- 分页器区域 --><div v-if="usePagination" class="pagination-box"><!-- 实现两侧分布的分页器布局:使用两个分页器组件 + 不同 layout 组成 --><el-pagination background :current-page="pageNum" :layout="layoutLeft" :page-size="pageSize" :pager-count="pagerCount" :total="total" @current-change="handleCurrentChange" @size-change="handleSizeChange" /><el-pagination background :current-page="pageNum" :layout="layoutRight" :page-size="pageSize" :pager-count="pagerCount" :total="total" @current-change="handleCurrentChange" @size-change="handleSizeChange" /></div></div>
</template><script>import { differenceBy, uniqBy, noop } from 'lodash'export default {props: {// 已勾选的数组value: {type: Array,default: () => [],require: true,},// 表格数据tableList: {type: Array,default: () => [],},// 表格列配置列表tableColumnList: {type: Array,default: () => [], // {label,prop,align}[]},// 表格数据是否加载中tableLoading: {type: Boolean,default: false,},// 表格高度tableHeight: {type: String | Number,default: 240,},// 表格数据类型tableType: {type: String,default: 'source', // source 源列表,target 目标列表},// 【已添加列表】搜索项(注:与表格列配置对应,且仅能字段类型为 String)searchList: {type: Array,default: () => [], // {label,prop,align}[]},// 分页后表格总数据的条数total: {type: Number,default: 0,},// 初始 pageNuminitPageNum: {type: Number,default: 1,},// 初始 pageSizeinitPageSize: {type: Number,default: 10,},// 使用分页器usePagination: {type: Boolean,default: false,},// 唯一标识符(便于定位到某条数据进行添加和移除操作)uniqueKey: {type: String,default: 'id',},// Function 的返回值用来决定这一行的 CheckBox 是否可以勾选selectable: {type: Function,default: noop(),},// 页码按钮的数量,当总页数超过该值时会折叠(element规定:大于等于 5 且小于等于 21 的奇数)pagerCount: {type: Number,default: 7,},},data() {return {layoutLeft: 'total',layoutRight: 'sizes, prev, pager, next',pageNum: 1,pageSize: 10,preSelectList: [], // 上一次选择的数据(点击分页器就清空)stashSelectList: [], // 暂存数据,便于点击页码后,还能保存前一页的数据isNeedToggle: true, // 是否需要勾选该页已选择项(用于换页后的回显选择项)isTableChangeData: false, // 是否是当前表格造成选择项的变化(用于同步【待选择列表】的勾选项)}},computed: {currentPageSelectList() {const currentSelectList = []this.stashSelectList?.forEach((item) => {const currentRow = this.tableList?.find((row) => row[this.uniqueKey] === item[this.uniqueKey])if (currentRow) {currentSelectList.push(currentRow)}})return currentSelectList},},watch: {value(newVal) {this.stashSelectList = newVal || []// 只有在其他地方修改了选择表格数据后,才刷新覆盖勾选项(当前表格修改选择项是双向绑定的,所以不需要刷新覆盖勾选项),实现精准回显和两表格的联动if (!this.isTableChangeData) {this.handleToggleSelection()}// 当暂存的选择列表为空时,需要同步更新 preSelect 为空数组,以便下次选择时进行判断是增加选择项还是减少选择项if (!this.stashSelectList.length) {this.preSelectList = []}this.isTableChangeData = false},tableList() {if (this.isNeedToggle) {this.preSelectList = this.currentPageSelectListthis.handleToggleSelection()this.isNeedToggle = false}},},mounted() {this.pageNum = this.initPageNum || 1this.pageSize = this.initPageSize || 110// 解决右侧固定操作栏错位问题this.$nextTick(() => {this.$refs.transferTable.doLayout()})this.$emit('selectionChange', [])},methods: {getTableRowClassName({ rowIndex }) {if (rowIndex % 2 == 0) {return ''} else {return 'stripe-row'}},fetchTableList(pageNum = 1) {if (this.usePagination) {// 若不是页码更改触发,则默认将 pageNum 重置为 1this.pageNum = pageNumconst params = {pageNum: this.pageNum,pageSize: this.pageSize,}this.$emit('fetchTableList', params)} else {this.$emit('fetchTableList')}},setPaginationParam({ pageNum, pageSize }, isFetch = false) {// 设置分页器参数(用于消费端设置的 ref 调用)this.pageNum = pageNum || this.pageNumthis.pageSize = pageSize || this.pageSizethis.isNeedToggle = trueif (isFetch) {this.fetchTableList()}},handleSizeChange(val) {this.pageSize = valthis.isNeedToggle = truethis.fetchTableList()},handleCurrentChange(val) {this.isNeedToggle = truethis.fetchTableList(val)},handleStashSelectList(isAdd = true, list = []) {if (isAdd) {// 暂存数组中增加,并兜底去重this.stashSelectList = uniqBy([...this.stashSelectList, ...list], this.uniqueKey)} else {// 暂存数组中移除this.stashSelectList = differenceBy(this.stashSelectList, list, this.uniqueKey)}this.isTableChangeData = truethis.$emit('input', this.stashSelectList)this.$emit('selectionChange', this.stashSelectList)},handleSelect(selectList, row) {// 判断是否是增加选择项const isAddRow = this.preSelectList.length < selectList.lengththis.handleStashSelectList(isAddRow, [row])// 更新当前页记录的上次数据this.preSelectList = [...selectList]},handleSelectAll(selectList) {// 判断是否是全选(需要考虑两个数组长度相等的情况)const isAddAll = this.preSelectList.length <= selectList.length// 更新当前页记录的上次数据this.handleStashSelectList(isAddAll, isAddAll ? selectList : this.preSelectList)this.preSelectList = [...selectList]},handleRemoveRowItem(rowItem, rowIndex) {const remainderPage = this.total % this.pageSize ? 1 : 0const pageNumTotal = parseInt(this.total / this.pageSize) + remainderPageconst isLastPageOnlyOne = rowIndex === 0 && this.pageNum === pageNumTotal// 判断删除的是否是最后一页中只有一条的数据if (isLastPageOnlyOne && this.pageNum > 1) {// 若是,则 pageNum 需要往前调整一页,因为删除后最后一页不存在this.handleCurrentChange(this.pageNum - 1)}this.$emit('removeSelectRow', rowItem)},handleToggleSelection() {this.$nextTick(() => {// 先清除所有勾选状态this.$refs.transferTable.clearSelection()if (this.currentPageSelectList.length) {// 再依次勾选当前页存在的行this.currentPageSelectList.forEach((item) => {this.$refs.transferTable.toggleRowSelection(item, true)})}})},},}
</script><style scoped>/* 表格斑马自定义颜色 */:deep(.el-table__row.stripe-row) {background: #f9f9f9;}/* 表格操作栏按钮取消间距 */:deep(.el-button) {padding: 0px;}/* 表格操作栏按钮固定大小 */:deep(.el-icon-delete::before) {font-size: 14px !important;}.pagination-box {display: flex;justify-content: space-between;}
</style>

http://www.ppmy.cn/server/119292.html

相关文章

EasyExcel 快速入门

目录 一、 EasyExcel简介 官网链接&#xff1a; 代码链接&#xff1a; 二、 EasyExcel快速上手 引入依赖&#xff1a; 设置Excel相关注解 编写对应的监听类&#xff1a; 简单写入数据&#xff1a; 简单读取数据&#xff1a; 不需要使用监听器&#xff1a; 需要使…

MySQL数据库迁移与备份实录

这里写目录标题 事情起因的概述查看磁盘空间使用情况为了进一步的明确宕机原因&#xff0c;查看MySQL日志信息进一步排查 如何针对磁盘空间不足进行挂载区域的修改以及数据的迁移与备份分析与梳理如何修改MySQL数据卷的挂载位置停止MySQL服务备份 MySQL 配置文件迁移 MySQL 数据…

基于springboot+vue图书管理系统的设计与实现

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;图书信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

基于剪切板的高速翻译工具

下载 关键代码 #include <curl/curl.h> std::wstring get_current_clipboard(HWND hwnd) {if (!OpenClipboard(hwnd)) {return L"";}HANDLE h = GetClipboardData(CF_UNICODETEXT);if (!h) {CloseClipboard();return L"";}wchar_t* data = (wchar_t…

【Python】练习:控制语句(二)第3关

第3关&#xff1a;函数基础实训 第一题&#xff08;※&#xff09;第二题第三题&#xff08;※&#xff09;第四题第五题 第一题&#xff08;※&#xff09; #第一题def sumInt(n):#请在下面编写代码# ********** Begin ********** #if type(n) is not int or n < 0:return …

C# 从字符串中分离文件路径、文件名及扩展名

C# 从字符串中分离文件路径、文件名及扩展名 对文件进行操作时&#xff0c;首先要获取文件路径信息&#xff0c;然后创建文件对象&#xff0c;通过IO流将数据读取大宋内存中并进行处理。在操作文件时&#xff0c;可能还需要提取文件的一些信息&#xff0c;比如&#xff0c;文件…

低代码平台中的数据源设计:构建高效应用的基础

什么是数据源&#xff1f; 在低代码开发平台中&#xff0c;数据源是指应用程序用来存储、检索和管理数据的地方。数据源可以是数据库、API、文件或其他数据存储解决方案。良好的数据源设计是构建高效、可扩展应用的基础。 数据源设计的关键原则 数据结构清晰&#xff1a;设计…

Spark实操学习

Spark学习 一、Spark-Shell编程1. 配置python3(三台服务器都要配置)2. 开始Spark编程3. spark-shell工具 二、Java项目测试1. 新建项目2. Spark-java代码测试 三、Scala项目测试1. 安装scala2. 安装包管理器sbt3. 在编译工具中安装scala工具4. 新建项目5. spark-scala代码测试 …