当前位置:   article > 正文

vue3.x + elementPlus 封装组件之transfer 穿梭框

vue3.x + elementplus 封装组件之transfer 穿梭框

老规矩----前面文章的步骤创建文件导入js等

封装代码

  1. <template>
  2. <!-- target-order="unshift"必须设置,如果不设置的话后台穿的value值得顺序会被data重置 - -->
  3. <el-transfer
  4. :id="idDom"
  5. target-order="unshift"
  6. style="text-align: left; display: inline-block"
  7. :model-value="transferData.value"
  8. filterable
  9. :filter-method="transferData.menuFilterMethod"
  10. :left-default-checked="leftChecked"
  11. :right-default-checked="rightChecked"
  12. :render-content="renderFunc"
  13. :titles="titles"
  14. :button-texts="buttonTexts"
  15. :format="{
  16. noChecked: '${total}',
  17. hasChecked: '${checked}/${total}',
  18. }"
  19. :data="dataListT"
  20. @change="handleChange"
  21. @left-check-change="leftCheckChange"
  22. @right-check-change="rightCheckChange"
  23. >
  24. <template #default="{ option }">
  25. <span
  26. class="item"
  27. @dragstart="drag($event, option)"
  28. >{{ option.label || option.title }}</span>
  29. <!-- {{ option.key }} - -->
  30. </template>
  31. <template #left-footer>
  32. <el-tooltip
  33. class="box-item"
  34. effect="dark"
  35. content="返回左边勾选中的数据"
  36. placement="top"
  37. >
  38. <el-button class="transfer-footer btn-mixins el-button-s" size="small" @click.stop="saveLeft">确定</el-button>
  39. </el-tooltip>
  40. </template>
  41. <template #right-footer>
  42. <el-tooltip
  43. class="box-item"
  44. effect="dark"
  45. content="返回右边勾选中的数据"
  46. placement="top"
  47. >
  48. <el-button class="transfer-footer btn-mixins el-button-s" size="small" @click.stop="saveRight">确定</el-button>
  49. </el-tooltip>
  50. </template>
  51. </el-transfer>
  52. </template>
  53. <script>
  54. import Sortable from 'sortablejs'
  55. import { reactive, ref, onMounted } from 'vue'
  56. const transferData = reactive({
  57. value: [], // 默认选中的个数索引
  58. draggingKey: '', // 拖动的数据
  59. menuFilterMethod(query, item) {
  60. // return item.menuListdata.indexOf(query) > -1
  61. const regStr = query.replace(/\*/g, '.*')
  62. const reg = new RegExp(regStr)
  63. return reg.test(item.label)
  64. }
  65. })
  66. // 默认数据测试展示
  67. const generateData = (_) => {
  68. const data = []
  69. for (let i = 1; i <= 15; i++) {
  70. data.push({
  71. key: i,
  72. label: `备选项 ${i}`,
  73. disabled: i % 4 === 0
  74. })
  75. }
  76. return data
  77. }
  78. // 数据初始化和拖拽初始化
  79. const initEffect = (props, ctx) => {
  80. let dataListT = props.dataList.length ? props.dataList : generateData()
  81. const init = () => {
  82. // const transferRef = document.getElementById(props.idDom)
  83. const transfer = document.getElementById(props.idDom)
  84. const leftPanel = transfer.getElementsByClassName('el-transfer-panel')[0].getElementsByClassName('el-transfer-panel__body')[0]
  85. const rightPanel = transfer.getElementsByClassName('el-transfer-panel')[1].getElementsByClassName('el-transfer-panel__body')[0]
  86. const rightEl = rightPanel.getElementsByClassName('el-transfer-panel__list')[0]
  87. Sortable.create(rightEl, {
  88. animation: 100,
  89. onEnd: (evt) => {
  90. const { oldIndex, newIndex } = evt
  91. const temp = transferData.value[oldIndex]
  92. if (!temp || temp === 'undefined') {
  93. return
  94. } // 解决右边最后一项从右边拖左边,有undefined的问题 //这里和网上的有点不一样,网上搜到的结果排序是,当前拖拽的元素和拖拽位置的元素互换位置,但是实际上在使用el-transfer有两个问题 //1.右侧排序value的数组顺序来源于后台穿的数组顺序,实际如果不设置target-order="unshift"的话,展示会按照左侧的数据列顺序展示,导致拖拽排序时顺序乱七八糟 //2.实际拖拽排序看到的效果是当前拖拽元素拖拽到其他地方,其他地方的元素会下移,而不是调换顺序
  95. // 去除空字符串
  96. for (var i = 0; i < transferData.value.length; i++) {
  97. if (
  98. transferData.value[i] === '' ||
  99. transferData.value[i] === null ||
  100. typeof transferData.value[i] === 'undefined'
  101. ) {
  102. transferData.value.splice(i, 1)
  103. i = i - 1
  104. }
  105. }
  106. const arr_temp = [].concat(transferData.value) // 创建一个新的临时数组,用以操作后不变更原数组
  107. arr_temp.splice(newIndex, 0, arr_temp.splice(oldIndex, 1)[0]) // 在b位置插入从a位置截取的元素
  108. transferData.value = arr_temp
  109. ctx.emit('update:call-back', transferData.value)
  110. }
  111. })
  112. const leftEl = leftPanel.getElementsByClassName('el-transfer-panel__list')[0]
  113. Sortable.create(leftEl, {
  114. animation: 100,
  115. onEnd: (evt) => {
  116. const { oldIndex, newIndex } = evt
  117. dataListT.splice(newIndex, 0, dataListT.splice(oldIndex, 1)[0])
  118. // 保存的新的数组用于数据渲染
  119. const newArray = dataListT.slice(0)
  120. dataListT = newArray
  121. }
  122. })
  123. leftPanel.ondragover = (ev) => {
  124. ev.preventDefault()
  125. }
  126. leftPanel.ondrop = (ev) => {
  127. ev.preventDefault()
  128. const index = transferData.value.indexOf(transferData.draggingKey)
  129. if (index !== -1) {
  130. transferData.value.splice(index, 1)
  131. }
  132. }
  133. rightPanel.ondragover = (ev) => {
  134. ev.preventDefault()
  135. }
  136. rightPanel.ondrop = (ev) => {
  137. ev.preventDefault()
  138. if (transferData.value.indexOf(transferData.draggingKey) === -1) {
  139. transferData.value.push(transferData.draggingKey)
  140. }
  141. }
  142. }
  143. return { init, dataListT }
  144. }
  145. // 左边确定按钮 把左边默认展示的传递过去
  146. const leftBtnEffect = (props, ctx) => {
  147. const leftDataChecked = ref([])
  148. leftDataChecked.value = props.leftChecked
  149. // props.leftChecked.forEach(e => {
  150. // if (!e.disabled) {
  151. // leftDataChecked.value.push(e)
  152. // }
  153. // })
  154. const leftCheckChange = (value) => {
  155. // console.log(value)
  156. leftDataChecked.value = value
  157. }
  158. // console.log(leftDataChecked.value)
  159. // 左侧确定事件
  160. const saveLeft = () => {
  161. ctx.emit('changeTransferLeft', leftDataChecked)
  162. }
  163. return { leftDataChecked, leftCheckChange, saveLeft }
  164. }
  165. // 右边确定按钮 把右边默认展示的传递过去
  166. const rightBtnEffect = (props, ctx) => {
  167. const rightDataChecked = ref([])
  168. rightDataChecked.value = props.rightChecked
  169. // props.rightChecked.forEach(e => {
  170. // if (!e.disabled) {
  171. // rightDataChecked.value.push(e)
  172. // }
  173. // })
  174. const rightCheckChange = (value) => {
  175. // console.log(value)
  176. rightDataChecked.value = value
  177. }
  178. // 右侧确定事件
  179. const saveRight = () => {
  180. ctx.emit('changeTransferRight', rightDataChecked)
  181. }
  182. return { rightDataChecked, rightCheckChange, saveRight }
  183. }
  184. export default {
  185. props: {
  186. value: {
  187. type: Array,
  188. default() {
  189. return []
  190. }
  191. },
  192. // 按钮文字
  193. idDom: {
  194. default() {
  195. return 'transfer'
  196. },
  197. type: String
  198. },
  199. // 按钮文字
  200. buttonTexts: {
  201. default() {
  202. return []
  203. },
  204. type: Array
  205. },
  206. // 数据
  207. dataList: {
  208. default() {
  209. return []
  210. },
  211. type: Array
  212. },
  213. leftChecked: {
  214. default() {
  215. return []
  216. },
  217. type: Array
  218. },
  219. rightChecked: {
  220. default() {
  221. return []
  222. },
  223. type: Array
  224. },
  225. // 标题
  226. titles: {
  227. default() {
  228. return []
  229. },
  230. type: Array
  231. }
  232. },
  233. emits: ['changeTransfer', 'changeTransferLeft', 'changeTransferRight'],
  234. setup(props, ctx) {
  235. const { init, dataListT } = initEffect(props, ctx)
  236. const { leftCheckChange, saveLeft } = leftBtnEffect(props, ctx)
  237. const { rightCheckChange, saveRight } = rightBtnEffect(props, ctx)
  238. // 数据加载完之后 再获取对应的id
  239. onMounted(() => {
  240. init()
  241. })
  242. const renderFunc = (h, option) => {
  243. return h('span', null, option.label)
  244. }
  245. const handleChange = (value, direction, movedKeys) => {
  246. ctx.emit('changeTransfer', value, direction, movedKeys)
  247. }
  248. const drag = (ev, option) => {
  249. transferData.draggingKey = option.key
  250. }
  251. return { transferData, dataListT, handleChange, drag, leftCheckChange, saveLeft, rightCheckChange, saveRight, renderFunc }
  252. }
  253. }
  254. </script>
  255. <style lang="scss" >
  256. .el-transfer__buttons {
  257. .el-button:first-child {
  258. margin-bottom: 8px;
  259. }
  260. }
  261. </style>

使用

  1. <template>
  2. <div>
  3. <LZTransfer
  4. v-model="transferData.value"
  5. :id-dom="transferData.transferId"
  6. :button-texts="transferData.buttonTexts"
  7. :left-checked="transferData.leftChecked"
  8. :left-data-list="transferData.leftDataList"
  9. :right-checked="transferData.rightChecked"
  10. :right-data-list="transferData.rightDataList"
  11. :titles="transferData.titles"
  12. @changeTransfer="changeTransfer"
  13. @changeTransferLeft="changeTransferLeft"
  14. @changeTransferRight="changeTransferRight"
  15. ></LZTransfer>
  16. </div>
  17. <div>
  18. <span>一个页面有两个穿梭框的展示和数据问题</span>
  19. <LZTransfer
  20. v-model="transferData2.value"
  21. :data-list="transferData2.dataList"
  22. :id-dom="transferData2.transferId2"
  23. :button-texts="transferData2.buttonTexts"
  24. :left-checked="transferData2.leftChecked"
  25. :right-checked="transferData2.rightChecked"
  26. :titles="transferData2.titles"
  27. @changeTransfer="changeTransfer2"
  28. @changeTransferLeft="changeTransferLeft2"
  29. @changeTransferRight="changeTransferRight2"
  30. ></LZTransfer>
  31. </div>
  32. </template>
  33. <script>
  34. import { reactive } from 'vue'
  35. const transferData = reactive({
  36. // 默认右移动的数据
  37. value: [2, 3],
  38. // 箭头描述
  39. buttonTexts: ['到左边', '到右边'],
  40. // 左边默认选中
  41. leftChecked: [1, 4],
  42. // 右边默认选中
  43. rightChecked: [2, 3],
  44. // 每个穿梭框id
  45. transferId: 'transferId1',
  46. titles: ['左边标题', '右边标题'] // 自定义数据 里面必须要要label或者title 才能展示文字
  47. })
  48. const transferData2 = reactive({
  49. value: [],
  50. // 箭头描述
  51. buttonTexts: ['到左边2', '到右边2'],
  52. // 左边默认选中
  53. leftChecked: [5, 4],
  54. // 右边默认选中
  55. rightChecked: [],
  56. // 每个id
  57. transferId2: 'transferId2',
  58. titles: ['左边标题2', '右边标题2'],
  59. // 自定义数据 里面必须要要label或者title 才能展示文字
  60. dataList: [
  61. {
  62. disabled: false,
  63. key: 1,
  64. label: '备选项 11',
  65. },
  66. {
  67. disabled: false,
  68. key: 2,
  69. label: '备选项 2',
  70. },
  71. {
  72. disabled: false,
  73. key: 3,
  74. label: '备选项 3',
  75. },
  76. {
  77. disabled: false,
  78. key: 4,
  79. label: '备选项 4',
  80. },
  81. {
  82. disabled: false,
  83. key: 5,
  84. label: '备选项 5',
  85. },
  86. {
  87. disabled: false,
  88. key: 6,
  89. label: '备选项 6',
  90. },
  91. {
  92. disabled: false,
  93. key: 7,
  94. label: '备选项 7',
  95. },
  96. {
  97. disabled: false,
  98. key: 8,
  99. label: '备选项 8',
  100. },
  101. {
  102. disabled: false,
  103. key: 9,
  104. label: '备选项 9',
  105. },
  106. {
  107. disabled: false,
  108. key: 10,
  109. label: '备选项 10',
  110. },
  111. {
  112. disabled: false,
  113. key: 11,
  114. label: '备选项 11',
  115. },
  116. ]
  117. })
  118. export default {
  119. setup() {
  120. // 当前移动的数据和方向 移动的key
  121. const changeTransfer = (value, direction, movedKeys) => {
  122. console.log(value, direction, movedKeys)
  123. }
  124. const changeTransferLeft = (list) => {
  125. // 这里要通过.value拿到数据
  126. console.log(list.value)
  127. }
  128. const changeTransferRight = (list) => {
  129. console.log(list.value)
  130. }
  131. const changeTransfer2 = (value, direction, movedKeys) => {
  132. console.log(value, direction, movedKeys)
  133. }
  134. const changeTransferLeft2 = (list) => {
  135. console.log(list.value)
  136. }
  137. const changeTransferRight2 = (list) => {
  138. console.log(list.value)
  139. }
  140. return { transferData, transferData2, changeTransfer, changeTransferLeft, changeTransferRight, changeTransfer2, changeTransferLeft2, changeTransferRight2 }
  141. }
  142. }
  143. </script>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/223924
推荐阅读
相关标签
  

闽ICP备14008679号