教你从零写vue穿梭框

  • 1. 前言
  • 2. 制作选择组件(select-input)
  • 2. 制作vue穿梭框组件(table-transfer)
  • 4. 将选择组件和穿梭框组件结合使用
    • 4.1 点击选择组件按钮,弹出穿梭框
    • 4.2 将select-input组件中的数据显示在弹框中的已选表格中
      • 4.2.1 全局引入lodash
      • 4.2.2 初始化input-select组件list数据和穿梭框的selectList(已选中的人员)
    • 4.3 将重新选择后的表格数据显示在select-input组件中
    • 4.3 单选模式
  • 5. 完整代码:
    • 5.1 select-input 组件代码:
    • 5.2 table-transfer 组件代码:
    • 5.3 结合select-input和table-transfer 完整代码:

1. 前言

最近项目中遇到一个需求:制作一个组件,左侧类似一个禁用的input输入框,右侧有一个选择按钮,点击后打开一个vue穿梭框,可以进行人员的选择,选择完成后,关闭弹框,选择人员的名单显示在input中。因为项目中多处用到,因此选择将其注册成全局组件。

2. 制作选择组件(select-input)

效果图:

Input.vue:

<template><div><div class="select-input"><span v-for="(item, index) in list" :key="index">{{index === list.length - 1 ? item[field] : item[field] + '、'}}</span></div><a-button type="link">选择</a-button></div>
</template><script>
export default {props: {// 数组list: {type: Array,default: () => {return [{name: '张三',no: 'P001',tel: '13876787675',department: '工程部'}]}},// 显示的数组字段field: {type: String,default: 'name'}},data() {return {}},created() {}
}
</script>
<style lang="less" scoped>
.select-input {display: inline-block;width: calc(100% - 70px);border: 1px solid #ccc;padding: 6px 11px;border-radius: 4px;height: 36px;
}
</style>

上面的input输入框,实际上只是个div设置了边框,并不具备真实的输入功能。
右侧的选择按钮作为备用,先放着,用于点击显示vue穿梭框使用。
为了演示效果,props.list设置了初始值,实际使用时应该设置为空数组[ ]。
index.js:

import Input from './Input.vue'
const SelectInput = {// install 为Vue实例上的一个方法install: function(Vue) {// 注册全局组件,此时MyBreadcrumb为使用的组件名称Vue.component('SelectInput', Input)}
}
// 导出组件
export default SelectInput

在main.js中全局挂载该组件:

import SelectInput from './components/select-input'
Vue.use(SelectInput)

之后在其他页面中通过标签<select-input></select-input>即可使用。

<template><a-row><a-col :span="5"><select-input></select-input></a-col></a-row>
</template><script>
export default {data() {return {}},created() {}
}
</script>
<style lang="less" scoped></style>

2. 制作vue穿梭框组件(table-transfer)

效果图:

一共两个表格,上面一个表格带有查询条件,是通过接口查询获取的所有人员数据;下面一个表格是已经选中的人员表格,通过中间的两个按钮,可以实现选中人员的增加和删除。

Transfer.vue:

<template><!-- 人员选择弹框 --><a-modal:title="title":visible="modalVisible"@ok="comfirm()"@cancel="cancel()":width="1400"cancelText="取消"okText="选择"><!-- 查询条件区域 --><a-form class="query-con" :label-col="labelCol" :wrapper-col="wrapperCol"><a-row type="flex"><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="姓名"><a-input v-model="query.name"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="员工编号"><a-input v-model="query.no"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="联系电话"><a-input v-model="query.tel"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="部门"><a-selectdefault-value="0"style="width: 120px"@change="handleChange"><a-select-optionv-for="(item, index) in department":key="index":value="item.value">{{ item.text }}</a-select-option></a-select></a-form-item></a-col><a-col :span="4" class="query-btn"><a-button type="primary">查询</a-button><a-button>重置</a-button></a-col></a-row></a-form><!-- 查询表格区域 --><a-table:row-selection="rowSelection":columns="columns":data-source="list":rowKey="rowKey":pagination="pagination"@change="changePage"></a-table><!-- 穿梭按钮区域 --><a-row class="query-btn" type="flex" justify="center"><a-button @click="addSelectedRow()" type="primary"><a-icon type="down" /></a-button><a-button @click="deleteSelectedRow()" type="primary"><a-icon type="up" /></a-button></a-row><!-- 选中表格区域 --><a-table:row-selection="rowSelection2":columns="columns":data-source="selectedList":rowKey="rowKey"></a-table></a-modal>
</template><script>
import _ from 'lodash'
export default {props: {// 弹框标题title: {type: String,default: '选择人员'},// 表格支持两种选择模式,复选框checkbox || 单选框radiotype: {type: String,default: 'checkbox'},// 选中表格列表selectedList: {type: Array,default: () => {// return []return [{name: '张三',no: 'P001',tel: '13876787675',department: '工程部'}]}},// 列表唯一标识rowKeyrowKey: {type: String,default: 'no'}},data() {return {labelCol: {span: 8},wrapperCol: {span: 16},// 弹框是否可见modalVisible: true,query: {name: '',no: '',tel: ''},selectedRowKeys: [],selectedRows: [],selectedRowKeys2: [],selectedRows2: [],department: [{value: '0',text: '工程部'},{value: '1',text: '运维部'},{value: '2',text: '财务部'},{value: '3',text: '人事部'}],// 待办列表表格列columns: [{title: '序号',dataIndex: 'index',key: 'index',align: 'center',width: 100,customRender: (text, record, index) => `${index + 1}`},{title: '姓名',dataIndex: 'name'},{title: '员工编号',dataIndex: 'no'},{title: '联系电话',dataIndex: 'tel'},{title: '部门',dataIndex: 'department'}],list: [{name: '张三',no: 'P001',tel: '13876787675',department: '工程部',disabled: true},{name: '李四',no: 'P002',tel: '13876787675',department: '工程部'},{name: '王五',no: 'P003',tel: '13876787675',department: '工程部'}],// 表格分页器配置pagination: {defaultCurrent: 1,defaultPageSize: 5,pageSizeOptions: ['2', '5', '10', '20', '50'],showSizeChanger: true,showQuickJumper: true,showTotal: total => {return `共 ${total} 条`},total: 0}}},created() {},methods: {// 显示选择人员弹框show() {this.modalVisible = true},// 点击选择按钮,抛出选中行comfirm() {// this.modalVisible = falsethis.$emit('comfirm', this.selectedList)},cancel() {this.modalVisible = false},handleChange(value) {console.log(`selected ${value}`)},changePage(pagination, filters, sorter, { currentDataSource }) {},// 将查询表格选中的行添加到选中表格中addSelectedRow() {for (let i = 0; i < this.selectedRows.length; i++) {// 先判断选中表格中是否已经有该行,如果有跳出本次循环let flag = falsefor (let j = 0; j < this.selectedList.length; j++) {if (this.selectedRows[i][this.rowKey] ===this.selectedList[j][this.rowKey]) {flag = true}}if (flag) {continue}const selectedRow = _.cloneDeep(this.selectedRows[i])console.log('hahah', selectedRow)// 如果是单选模式,需要先删除第一个元素,因为是prop元素,所以不能直接赋值if (this.type === 'radio') {this.selectedList.splice(0, 1)}this.selectedList.push(selectedRow)}},// 将选中表格的选中行删除deleteSelectedRow() {for (let i = 0; i < this.selectedRows2.length; i++) {for (let j = 0; j < this.selectedList.length; j++) {if (this.selectedRows2[i][this.rowKey] ===this.selectedList[j][this.rowKey]) {this.selectedList.splice(j, 1)break}}}}},computed: {// 查询表格选择框设置rowSelection() {return {type: this.type,// 选中变化事件onChange: (selectedRowKeys, selectedRows) => {this.selectedRowKeys = selectedRowKeysthis.selectedRows = selectedRows}}},// 选中表格选择框设置rowSelection2() {return {type: this.type,onChange: (selectedRowKeys, selectedRows) => {this.selectedRowKeys2 = selectedRowKeysthis.selectedRows2 = selectedRows}}}}
}
</script>
<style lang="less" scoped>
.query-con {.ant-form-item .ant-form-item-control-wrapper {display: block;box-sizing: border-box;width: 66.66666667%;}.ant-select {width: 100% !important;}.query-btn {display: flex;margin-top: 4px;.ant-btn {margin-left: 10px;}}
}
</style>

因为这个穿梭框组件是整个项目通用的人员选择弹框,所以我直接将查询条件和表格数据直接写进了组件中。为了更加方便理解,同学们在看这段代码时,可以先忽略或者注释查询条件区域的代码。
如果需要更加通用的表格穿梭框组件,可以将其中的columns和list抽离出来作为props的属性。
index.js:

import Transfer from './Transfer.vue'
const TableTransfer = {// install 为Vue实例上的一个方法install: function(Vue) {// 注册全局组件,此时MyBreadcrumb为使用的组件名称Vue.component('TableTransfer', Transfer)}
}
// 导出组件
export default TableTransfer

在main.js中全局挂载该组件:

import TableTransfer from './components/table-transfer'
Vue.use(TableTransfer)

之后在其他页面中通过标签<table-transfer></table-transfer>即可使用。

<template><a-row><!-- <a-col :span="5"><select-input></select-input></a-col> --><table-transfer></table-transfer></a-row>
</template><script>
export default {data() {return {}},created() {}
}
</script>
<style lang="less" scoped></style>

4. 将选择组件和穿梭框组件结合使用

4.1 点击选择组件按钮,弹出穿梭框

(1)在select-input组件中添加点击事件,并且暴露出去


(2)在页面中通过ref引用穿梭框的显示方法

4.2 将select-input组件中的数据显示在弹框中的已选表格中

4.2.1 全局引入lodash

在终端通过npm i lodash下载lodash
在main.js中全局引入:

import _ from 'lodash'
Vue.prototype._ = _

4.2.2 初始化input-select组件list数据和穿梭框的selectList(已选中的人员)



点击选择按钮:

4.3 将重新选择后的表格数据显示在select-input组件中



重新选择人员后,点击确认:

4.3 单选模式


在使用穿梭框时,只需要设置 type 为 radio 即可切换成单选模式

5. 完整代码:

5.1 select-input 组件代码:

<template><div class="select-input-con"><div class="select-input"><span v-for="(item, index) in list" :key="index">{{index === list.length - 1 ? item[field] : item[field] + '、'}}</span></div><a-button @click="showSelectModal()" type="link">选择</a-button></div>
</template><script>
export default {props: {// 数组list: {type: Array,default: () => {return []}},// 显示的数组字段field: {type: String,default: 'name'}},data() {return {}},created() {},methods: {showSelectModal() {this.$emit('showSelectModal')}}
}
</script>
<style lang="less" scoped>
.select-input-con {display: flex;align-items: center;.select-input {display: inline-block;width: calc(100% - 70px);border: 1px solid #ccc;padding: 6px 11px;border-radius: 4px;height: 36px;}
}
</style>

5.2 table-transfer 组件代码:

<template><!-- 人员选择弹框 --><a-modal:title="title":visible="modalVisible"@ok="comfirm()"@cancel="cancel()":width="1400"cancelText="取消"okText="选择"><!-- 查询条件区域 --><a-form class="query-con" :label-col="labelCol" :wrapper-col="wrapperCol"><a-row type="flex"><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="姓名"><a-input v-model="query.name"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="员工编号"><a-input v-model="query.no"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="联系电话"><a-input v-model="query.tel"></a-input></a-form-item></a-col><a-col :span="5"><a-form-item :wrapper-col="wrapperCol" label="部门"><a-selectdefault-value="0"style="width: 120px"@change="handleChange"><a-select-optionv-for="(item, index) in department":key="index":value="item.value">{{ item.text }}</a-select-option></a-select></a-form-item></a-col><a-col :span="4" class="query-btn"><a-button type="primary">查询</a-button><a-button>重置</a-button></a-col></a-row></a-form><!-- 查询表格区域 --><a-table:row-selection="rowSelection":columns="columns":data-source="list":rowKey="rowKey":pagination="pagination"@change="changePage"></a-table><!-- 穿梭按钮区域 --><a-row class="query-btn" type="flex" justify="center"><a-button @click="addSelectedRow()" type="primary"><a-icon type="down" /></a-button><a-button @click="deleteSelectedRow()" type="primary"><a-icon type="up" /></a-button></a-row><!-- 选中表格区域 --><a-table:row-selection="rowSelection2":columns="columns":data-source="selectedList":rowKey="rowKey"></a-table></a-modal>
</template><script>
import _ from 'lodash'
export default {props: {// 弹框标题title: {type: String,default: '选择人员'},// 表格支持两种选择模式,复选框checkbox || 单选框radiotype: {type: String,default: 'checkbox'},// 选中表格列表selectedList: {type: Array,default: () => {return []}},// 列表唯一标识rowKeyrowKey: {type: String,default: 'no'}},data() {return {labelCol: {span: 8},wrapperCol: {span: 16},// 弹框是否可见modalVisible: false,query: {name: '',no: '',tel: ''},selectedRowKeys: [],selectedRows: [],selectedRowKeys2: [],selectedRows2: [],department: [{value: '0',text: '工程部'},{value: '1',text: '运维部'},{value: '2',text: '财务部'},{value: '3',text: '人事部'}],// 待办列表表格列columns: [{title: '序号',dataIndex: 'index',key: 'index',align: 'center',width: 100,customRender: (text, record, index) => `${index + 1}`},{title: '姓名',dataIndex: 'name'},{title: '员工编号',dataIndex: 'no'},{title: '联系电话',dataIndex: 'tel'},{title: '部门',dataIndex: 'department'}],list: [{name: '张三',no: 'P001',tel: '13876787675',department: '工程部',disabled: true},{name: '李四',no: 'P002',tel: '13876787675',department: '工程部'},{name: '王五',no: 'P003',tel: '13876787675',department: '工程部'}],// 表格分页器配置pagination: {defaultCurrent: 1,defaultPageSize: 5,pageSizeOptions: ['2', '5', '10', '20', '50'],showSizeChanger: true,showQuickJumper: true,showTotal: total => {return `共 ${total} 条`},total: 0}}},created() {},methods: {// 显示选择人员弹框show() {this.modalVisible = true},// 点击选择按钮,抛出选中行comfirm() {// this.modalVisible = falsethis.$emit('comfirm', this.selectedList)},cancel() {this.modalVisible = false},handleChange(value) {console.log(`selected ${value}`)},changePage(pagination, filters, sorter, { currentDataSource }) {},// 将查询表格选中的行添加到选中表格中addSelectedRow() {for (let i = 0; i < this.selectedRows.length; i++) {// 先判断选中表格中是否已经有该行,如果有跳出本次循环let flag = falsefor (let j = 0; j < this.selectedList.length; j++) {if (this.selectedRows[i][this.rowKey] ===this.selectedList[j][this.rowKey]) {flag = true}}if (flag) {continue}const selectedRow = _.cloneDeep(this.selectedRows[i])console.log('hahah', selectedRow)// 如果是单选模式,需要先删除第一个元素,因为是prop元素,所以不能直接赋值if (this.type === 'radio') {this.selectedList.splice(0, 1)}this.selectedList.push(selectedRow)}},// 将选中表格的选中行删除deleteSelectedRow() {for (let i = 0; i < this.selectedRows2.length; i++) {for (let j = 0; j < this.selectedList.length; j++) {if (this.selectedRows2[i][this.rowKey] ===this.selectedList[j][this.rowKey]) {this.selectedList.splice(j, 1)break}}}}},computed: {// 查询表格选择框设置rowSelection() {return {type: this.type,// 选中变化事件onChange: (selectedRowKeys, selectedRows) => {this.selectedRowKeys = selectedRowKeysthis.selectedRows = selectedRows}}},// 选中表格选择框设置rowSelection2() {return {type: this.type,onChange: (selectedRowKeys, selectedRows) => {this.selectedRowKeys2 = selectedRowKeysthis.selectedRows2 = selectedRows}}}}
}
</script>
<style lang="less" scoped>
.query-con {.ant-form-item .ant-form-item-control-wrapper {display: block;box-sizing: border-box;width: 66.66666667%;}.ant-select {width: 100% !important;}.query-btn {display: flex;margin-top: 4px;.ant-btn {margin-left: 10px;}}
}
</style>

5.3 结合select-input和table-transfer 完整代码:

<template><a-row><a-col :span="5"><select-input:list="list"@showSelectModal="showSelectModal"></select-input></a-col><table-transfer:selectedList="selectedList"@comfirm="comfirm"type="radio"ref="staffmodal"></table-transfer></a-row>
</template><script>
export default {data() {return {list: [],selectedList: []}},created() {},methods: {showSelectModal() {// 深拷贝给已选择人员this.selectedList = this._.cloneDeep(this.list)this.$refs.staffmodal.show()},comfirm(selectList) {this.list = selectListthis.selectedList = []this.$refs.staffmodal.cancel()}}
}
</script>
<style lang="less" scoped></style>

教你从零写vue穿梭框相关推荐

  1. vue项目手写树形穿梭框

    背景:主流组件库提供的穿梭框并不能满足需求...手动封装扩展性更高 功能: 具备首次进入页面,分配左右侧穿梭框展示(左侧为树形,右侧为一维数组) 选中左侧-节点(子节点)通过 >按钮 可将选中节 ...

  2. vue 穿梭框 组件

    前言:由于项目需要,element ui 里面的穿梭框不满足需求,所以自己封装了一个穿梭框,此穿梭框为三个,可以两两穿梭. 如下图: 代码如下:如有bug ,欢迎指出: 其实数据的传输,最好用vuex ...

  3. 手把手教你从零写一个日志框架

    点击上方 "编程技术圈"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 每日英文 Sometimes you have to accept the ...

  4. 一个基于vue和element-ui的树形穿梭框组件

    el-tree-transfer 简介 因为公司业务使用vue框架,ui库使用的element-ui.在市面上找到一个好用的vue树形穿梭框组件都很难,又不想仅仅因为一个穿梭框在element-ui之 ...

  5. vue3+ts+ant-vue:手把手教你实现穿梭框简易版,配源码

    效果 通过脚手架创建项目(@vue/cli 4.5.11) vue create 项目名 配置需要注意 选择Ts(空格选中) 选择vue3.x 然后一路回车 到这了就完成vue3+ts配置 需要用到a ...

  6. Vue实现拖拽穿梭框功能四种方式

    一.使用原生js实现拖拽 点击打开视频讲解更加详细 <html lang="en"><head><meta charset="UTF-8&q ...

  7. vue+iview 自定义实现穿梭框

    vue+iview 自定义实现穿梭框 因业务需求iview穿梭框不满足业务需求自己写了个穿梭框.因本人是后端,请各位大佬看到了也可帮忙优化下.只实现了基本功能 表格及模态框代码 <Modal v ...

  8. php穿梭框多选,多选穿梭框总结 (vue + element)

    示例 介绍 实现省市区三级多选联动,可任选一个省级.市级.区级,加入已选框,也可以在已选框中删除对应的区域. 选择对应仓库,自动勾选仓库对应的省,取消就反选 选择同样地区,选择省级或市级,若该对象下面 ...

  9. Vue 搭配element-UI 实现可搜索穿梭框

    首先,如果还没有看过官方的例子的话,建议先浏览下官方的文档,本文主要介绍的是自己踩过的坑.在这基础上,假设您已经有了一定的vue.js的基础 官方地址: http://element.eleme.io ...

最新文章

  1. 软件测试培训教程:pytest与unittest区别
  2. Hexo瞎折腾系列(8) - 添加评论系统
  3. 操作系统对比和未来展望
  4. 关于MySQL查询优化 の 30条忠告
  5. Python基础之window常见操作
  6. file_operations结构体
  7. oracle 日期改字符格式,如何在oracle10g中将字符串日期转换为日期格式
  8. 一步一步SharePoint 2007之二十二:完美解决实现Form认证后无法再用SharePoint Designer编辑网站的问题...
  9. mybatis 3.2.3 maven dependency pom.xml 配置
  10. 我们一起学习WCF 第五篇数据协定和消息协定
  11. 管鲍计算机教室管理系统,管鲍多媒体电子教室
  12. win7计算机个性化设置,Win7系统如何进行个性化设置 Win7系统个性化设置方法【详解】...
  13. BMP(DIB)图片格式
  14. 微信小程序怎么开通店铺呢?
  15. CCNP之IGP学习笔记(2022)
  16. Trident API
  17. MATLAB技术沙龙之如何批量处理图像的大小
  18. 笔记 | 初探Kotlin协程
  19. “@” Java中的特殊符号——注解(Java中’@‘符号是什么意思?)
  20. 201871010123-吴丽丽《面向对象程序设计(Java)》第四周学习总结

热门文章

  1. js中null,underfined.object几个类型
  2. 39、count_rpkm_fpkm_TPM
  3. SpringBoot+RabbitMQ之延迟队列
  4. linux下NTP服务器配置及问题解决方法
  5. 模式匹配用到集合论、装箱解箱用到范畴论
  6. 微信小程序原生接入腾讯云im(单聊,列表,聊天界面,自定义消息,自动回复)
  7. Cheese Cheese! ――BeijingOpenParty 2009.07“Sea viewing at Summer gloaming(夏暮观海)”
  8. 闹元宵,迎开学!内官社区元宵节亲子活动甜甜出炉!
  9. 荒野行动系统推荐观战榜_看别人吃鸡也很有趣 荒野行动观战系统详细介绍
  10. 用httpclient开发的在线自动抢订火车票系统(铁老大不给力,哥给力)