当前位置:   article > 正文

基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能_vue3点击按钮左边展示的宽度变短右边宽度变长

vue3点击按钮左边展示的宽度变短右边宽度变长

前言

其原理主要是利用JavaScript中的鼠标事件来控制CSS样式。大致就是监听某个DOM元素的鼠标按下事件,以及按下之后的移动事件和松开事件。在鼠标按下且移动过程中,可实时获得鼠标的X轴坐标的值,通过简单计算,可计算出目标元素的宽度,然后再用CSS赋值就实现该效果了。

一、示例代码

(1)/src/views/Example/MouseResizeWidth/index.vue

  1. <template>
  2. <div class="index">
  3. <div class="index-left" ref="indexLeftRef">
  4. <div class="left-area-box"></div>
  5. <div class="left-resize-bar"></div>
  6. <div class="left-view-more" @click="handleViewMoreLeftClick">
  7. <div class="left-view-more-content">
  8. <div class="left-view-more-false" v-if="!isCollapseLeft" />
  9. <div class="left-view-more-true" v-else />
  10. </div>
  11. </div>
  12. </div>
  13. <div class="index-middle" ref="indexRightRef">
  14. <div class="middle-area-box">
  15. <div class="middle-area-box_main">
  16. <div class="middle-area-box_main_up">
  17. <div class="middle-area-box_main_up_wrapper">
  18. <!-- ^ 工具栏 -->
  19. <div class="index-tools-container">
  20. <el-form :inline="true" style="display: flex">
  21. <div class="tools-left"></div>
  22. <div class="tools-right">
  23. <el-form-item style="margin: 0 0 7px 7px">
  24. <el-button size="small" type="primary">
  25. <el-icon :size="12" style="margin-right: 5px"><ElementPlus /></el-icon>
  26. <small>ElementPlus</small>
  27. </el-button>
  28. </el-form-item>
  29. </div>
  30. </el-form>
  31. </div>
  32. <!-- / 工具栏 -->
  33. <!-- ^ 内容区 -->
  34. <div class="index-table-container">
  35. <el-table
  36. border
  37. size="small"
  38. row-key="id"
  39. ref="tableRef"
  40. height="100%"
  41. highlight-current-row
  42. :data="tableList"
  43. >
  44. <el-table-column fixed type="selection" :resizable="false" width="30" reserve-selection align="center" />
  45. <el-table-column prop="name" label="英雄名称" align="center" width="200" show-overflow-tooltip />
  46. <el-table-column prop="description" label="英雄描述" align="center" width="auto" show-overflow-tooltip />
  47. <el-table-column prop="firstSkill" label="一技能" align="center" width="200" show-overflow-tooltip />
  48. <el-table-column prop="secondSkill" label="二技能" align="center" width="200" show-overflow-tooltip />
  49. <el-table-column prop="thirdSkill" label="三技能" align="center" width="200" show-overflow-tooltip />
  50. <template #empty v-if="tableList == undefined || tableList.length == 0">Nothing ~</template>
  51. </el-table>
  52. </div>
  53. <!-- / 内容区 -->
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="index-right" ref="indexRightRef">
  60. <div class="right-view-more" @click="handleViewMoreRightClick">
  61. <div class="right-view-more-content">
  62. <div class="right-view-more-false" v-if="!isCollapseRight" />
  63. <div class="right-view-more-true" v-else />
  64. </div>
  65. </div>
  66. <div class="right-resize-bar"></div>
  67. <div class="right-area-box"></div>
  68. </div>
  69. </div>
  70. </template>
  71. <script setup>
  72. import { h, onMounted, onUnmounted, ref, getCurrentInstance, reactive, watch, nextTick } from 'vue'
  73. // 代理对象
  74. const { proxy } = getCurrentInstance()
  75. // 是否收起左侧
  76. const isCollapseLeft = ref(false)
  77. // 左侧模块箭头点击事件句柄方法
  78. const handleViewMoreLeftClick = async () => {
  79. const indexLeftRef = await proxy.$refs.indexLeftRef
  80. isCollapseLeft.value = !isCollapseLeft.value
  81. if (isCollapseLeft.value) {
  82. indexLeftRef.style.width = '23px'
  83. } else {
  84. indexLeftRef.style.width = '400px'
  85. }
  86. }
  87. // 表格实例
  88. const tableRef = ref(null)
  89. // 表格数据
  90. const tableList = ref([])
  91. // 是否收起右侧
  92. const isCollapseRight = ref(false)
  93. // 右侧模块箭头点击事件句柄方法
  94. const handleViewMoreRightClick = async () => {
  95. const indexRightRef = await proxy.$refs.indexRightRef
  96. isCollapseRight.value = !isCollapseRight.value
  97. if (isCollapseRight.value) {
  98. indexRightRef.style.width = '23px'
  99. } else {
  100. indexRightRef.style.width = '400px'
  101. }
  102. }
  103. /**
  104. * 左侧拖动改变宽度事件句柄方法
  105. */
  106. const handleDragLeftResizeBar = () => {
  107. var leftResizeBar = document.getElementsByClassName("left-resize-bar")[0]
  108. var wholeArea = document.getElementsByClassName("index")[0]
  109. var leftArea = document.getElementsByClassName("index-left")[0]
  110. var middleArea = document.getElementsByClassName("index-middle")[0]
  111. var rightArea = document.getElementsByClassName("index-right")[0]
  112. console.log('leftResizeBar =>', leftResizeBar)
  113. console.log('wholeArea =>', wholeArea)
  114. console.log('leftArea =>', leftArea)
  115. console.log('middleArea =>', middleArea)
  116. console.log('rightArea =>', rightArea)
  117. // 鼠标按下事件
  118. leftResizeBar.onmousedown = function (eventDown) {
  119. // 颜色提醒
  120. leftResizeBar.style.backgroundColor = "#5e7ce0"
  121. leftResizeBar.style.color = "#ffffff"
  122. // 鼠标拖动事件
  123. document.onmousemove = function (eventMove) {
  124. let width = eventMove.clientX + 20
  125. console.log('width =>', width)
  126. if (width >= 800) {
  127. width = 800 // 设置最大拉伸宽度为800
  128. } else if (width <= 23) {
  129. // 当拉伸宽度为小于或等于23,最小拉伸宽度为23,同时是否收起图标向右
  130. width = 23
  131. isCollapseLeft.value = true
  132. } else {
  133. // 当拉伸宽度为大于23且小于600,是否收起图标向左
  134. isCollapseLeft.value = false
  135. }
  136. leftArea.style.width = width + 'px'
  137. }
  138. // 鼠标松开事件
  139. document.onmouseup = function (evt) {
  140. // 颜色恢复
  141. leftResizeBar.style.backgroundColor = "#ffffff"
  142. leftResizeBar.style.color = "#40485c"
  143. document.onmousemove = null
  144. document.onmouseup = null
  145. leftResizeBar.releaseCapture && leftResizeBar.releaseCapture();
  146. }
  147. leftResizeBar.setCapture && leftResizeBar.setCapture();
  148. return false
  149. }
  150. }
  151. /**
  152. * 右侧拖动改变宽度事件句柄方法
  153. */
  154. const handleDragRightResizeBar = () => {
  155. var rightResizeBar = document.getElementsByClassName("right-resize-bar")[0]
  156. var wholeArea = document.getElementsByClassName("index")[0]
  157. var leftArea = document.getElementsByClassName("index-left")[0]
  158. var middleArea = document.getElementsByClassName("index-middle")[0]
  159. var rightArea = document.getElementsByClassName("index-right")[0]
  160. console.log('rightResizeBar =>', rightResizeBar)
  161. console.log('wholeArea =>', wholeArea)
  162. console.log('leftArea =>', leftArea)
  163. console.log('middleArea =>', middleArea)
  164. console.log('rightArea =>', rightArea)
  165. // 鼠标按下事件
  166. rightResizeBar.onmousedown = function (eventDown) {
  167. // 颜色提醒
  168. rightResizeBar.style.backgroundColor = "#5e7ce0"
  169. rightResizeBar.style.color = "#ffffff"
  170. // 开始x坐标
  171. // let startX = eventDown.clientX
  172. // console.log('startX =>', startX)
  173. // 鼠标拖动事件
  174. document.onmousemove = function (eventMove) {
  175. // 方式一:基于移动距离方式实现
  176. // const endX = eventMove.clientX // 结束坐标
  177. // const len = startX - endX // 移动距离
  178. // rightArea.style.width = rightArea.clientWidth + len + 'px' // 改变宽度
  179. // startX = endX // 重新对开始x坐标赋值
  180. // 方式二:基于总长度和结束x坐标方式实现
  181. let width = wholeArea.clientWidth + 20 - eventMove.clientX
  182. if (width >= 800) {
  183. width = 800 // 设置最大拉伸宽度为800
  184. } else if (width <= 23) {
  185. // 当拉伸宽度为小于或等于23,最小拉伸宽度为23,同时是否收起图标向左
  186. width = 23
  187. isCollapseRight.value = true
  188. } else {
  189. // 当拉伸宽度为大于23且小于600,是否收起图标向右
  190. isCollapseRight.value = false
  191. }
  192. rightArea.style.width = width + 'px'
  193. }
  194. // 鼠标松开事件
  195. document.onmouseup = function (evt) {
  196. // 颜色恢复
  197. rightResizeBar.style.backgroundColor = "#ffffff"
  198. rightResizeBar.style.color = "#40485c"
  199. document.onmousemove = null
  200. document.onmouseup = null
  201. rightResizeBar.releaseCapture && rightResizeBar.releaseCapture();
  202. }
  203. rightResizeBar.setCapture && rightResizeBar.setCapture();
  204. return false
  205. }
  206. }
  207. onMounted(() => {
  208. handleDragLeftResizeBar()
  209. handleDragRightResizeBar()
  210. })
  211. onUnmounted(() => {
  212. // ...
  213. })
  214. </script>
  215. <style lang="less" scoped>
  216. .index {
  217. display: flex;
  218. flex-direction: row;
  219. width: 100%;
  220. height: 100%;
  221. overflow: hidden;
  222. /* ---- ^ 左边 ---- */
  223. :deep(.index-left) {
  224. position: relative;
  225. z-index: 2;
  226. display: flex;
  227. flex-direction: row;
  228. width: 400px;
  229. border-right: 1px solid #dcdfe6;
  230. // ^ 左侧区域
  231. .left-area-box {
  232. flex: 1;
  233. display: flex;
  234. flex-direction: column;
  235. overflow: hidden;
  236. background-color: #f8f8f8;
  237. }
  238. // / 左侧区域
  239. // ^ 是否收起左侧边栏的图标
  240. .left-view-more {
  241. position: relative;
  242. width: 15px;
  243. height: 100%;
  244. background-color: #f3f6f8;
  245. border-left: 1px solid #dcdfe6;
  246. .left-view-more-content {
  247. width: 12px;
  248. height: 30px;
  249. background-color: #ccc;
  250. border-bottom-right-radius: 4px;
  251. border-top-right-radius: 4px;
  252. position: absolute;
  253. display: block;
  254. margin: auto;
  255. left: 0;
  256. top: 0;
  257. bottom: 0;
  258. cursor: pointer;
  259. z-index: 1;
  260. transition: all ease 0.3s;
  261. &:hover {
  262. background-color: #5e7ce0;
  263. }
  264. .left-view-more-true {
  265. width: 100%;
  266. height: 10px;
  267. position: absolute;
  268. display: block;
  269. margin: auto;
  270. left: 0;
  271. right: 0;
  272. top: 0;
  273. bottom: 0;
  274. &::before {
  275. display: block;
  276. height: 2px;
  277. width: 10px;
  278. content: "";
  279. position: absolute;
  280. left: 0;
  281. top: 0;
  282. background-color: #fff;
  283. transform: rotate(70deg);
  284. }
  285. &::after {
  286. display: block;
  287. height: 2px;
  288. width: 10px;
  289. content: "";
  290. position: absolute;
  291. left: 0;
  292. bottom: 0;
  293. background-color: #fff;
  294. transform: rotate(-70deg);
  295. }
  296. }
  297. .left-view-more-false {
  298. width: 100%;
  299. height: 10px;
  300. position: absolute;
  301. display: block;
  302. margin: auto;
  303. left: 0;
  304. right: 0;
  305. top: 0;
  306. bottom: 0;
  307. &::before {
  308. display: block;
  309. height: 2px;
  310. width: 10px;
  311. content: "";
  312. position: absolute;
  313. left: 0;
  314. top: 0;
  315. background-color: #fff;
  316. transform: rotate(-70deg);
  317. }
  318. &::after {
  319. display: block;
  320. height: 2px;
  321. width: 10px;
  322. content: "";
  323. position: absolute;
  324. left: 0;
  325. bottom: 0;
  326. background-color: #fff;
  327. transform: rotate(70deg);
  328. }
  329. }
  330. }
  331. }
  332. // / 是否收起左侧边栏的图标
  333. // ^ 左侧拖动条
  334. .left-resize-bar {
  335. display: flex;
  336. align-items: center;
  337. width: 7px;
  338. height: 100%;
  339. background-color: rgb(255, 255, 255);
  340. cursor: col-resize;
  341. user-select: none;
  342. transition: all ease 0.3s;
  343. font-size: 20px;
  344. color: #40485c;
  345. &:hover {
  346. color: #fff !important;
  347. background-color: #5e7ce0 !important;
  348. }
  349. }
  350. // / 左侧拖动条
  351. }
  352. /* ---- / 左边 ---- */
  353. /* ---- ^ 中间 ---- */
  354. :deep(.index-middle) {
  355. position: relative;
  356. z-index: 1;
  357. flex: 1;
  358. overflow: hidden;
  359. position: relative;
  360. transition: all ease 0.3s;
  361. background-color: #f3f6f8;
  362. // ^ 中间区域
  363. .middle-area-box {
  364. display: flex;
  365. position: relative;
  366. width: 100%;
  367. height: 100%;
  368. overflow: hidden;
  369. .middle-area-box_main {
  370. position: relative;
  371. flex: 1 1;
  372. display: flex;
  373. flex-direction: column;
  374. width: 100%;
  375. .middle-area-box_main_up {
  376. flex: 1;
  377. display: flex;
  378. overflow: hidden;
  379. flex-direction: column;
  380. background-color: #fff;
  381. .middle-area-box_main_up_wrapper {
  382. flex: 1;
  383. display: flex;
  384. flex-direction: column;
  385. padding: 7px;
  386. overflow: auto;
  387. .index-tools-container {
  388. .tools-left {
  389. flex: 1;
  390. }
  391. .tools-right {
  392. height: auto;
  393. }
  394. }
  395. .index-table-container {
  396. flex: 1;
  397. overflow: auto;
  398. }
  399. .el-table {
  400. th .cell {
  401. padding: 2.5px;
  402. font-weight: normal;
  403. font-size: 13px;
  404. }
  405. td .cell {
  406. padding: 2.5px 0;
  407. color: #000;
  408. font-size: 13px;
  409. }
  410. .el-table__cell {
  411. padding: 0;
  412. }
  413. /* ^ 表格复选框 */
  414. .el-table-column--selection {
  415. .cell {
  416. width: 100%;
  417. display: block;
  418. .el-checkbox {
  419. .el-checkbox__inner {
  420. transform: scale(1.2);
  421. border-radius: 50%;
  422. border: 1px solid #bbb;
  423. }
  424. .el-checkbox__input.is-checked .el-checkbox__inner,
  425. .el-checkbox__input.is-indeterminate .el-checkbox__inner {
  426. border: 1px solid #5e7ce0;
  427. }
  428. }
  429. }
  430. }
  431. /* / 表格复选框 */
  432. }
  433. }
  434. }
  435. .middle-area-box_main_down {
  436. flex: 0;
  437. }
  438. }
  439. }
  440. // / 中间区域
  441. }
  442. /* ---- / 中间 ---- */
  443. /* ---- ^ 右边 ---- */
  444. :deep(.index-right) {
  445. position: relative;
  446. z-index: 2;
  447. display: flex;
  448. flex-direction: row;
  449. width: 400px;
  450. border-left: 1px solid #dcdfe6;
  451. // ^ 是否收起右侧边栏的图标
  452. .right-view-more {
  453. position: relative;
  454. width: 15px;
  455. height: 100%;
  456. background-color: #f3f6f8;
  457. border-right: 1px solid #dcdfe6;
  458. .right-view-more-content {
  459. width: 12px;
  460. height: 30px;
  461. background-color: #ccc;
  462. border-bottom-left-radius: 4px;
  463. border-top-left-radius: 4px;
  464. position: absolute;
  465. display: block;
  466. margin: auto;
  467. right: 0;
  468. top: 0;
  469. bottom: 0;
  470. cursor: pointer;
  471. z-index: 1;
  472. transition: all ease 0.3s;
  473. &:hover {
  474. background-color: #5e7ce0;
  475. }
  476. .right-view-more-true {
  477. width: 100%;
  478. height: 10px;
  479. position: absolute;
  480. display: block;
  481. margin: auto;
  482. left: 0;
  483. right: 0;
  484. top: 0;
  485. bottom: 0;
  486. &::before {
  487. display: block;
  488. height: 2px;
  489. width: 10px;
  490. content: "";
  491. position: absolute;
  492. left: 0;
  493. top: 0;
  494. background-color: #fff;
  495. transform: rotate(-70deg);
  496. }
  497. &::after {
  498. display: block;
  499. height: 2px;
  500. width: 10px;
  501. content: "";
  502. position: absolute;
  503. left: 0;
  504. bottom: 0;
  505. background-color: #fff;
  506. transform: rotate(70deg);
  507. }
  508. }
  509. .right-view-more-false {
  510. width: 100%;
  511. height: 10px;
  512. position: absolute;
  513. display: block;
  514. margin: auto;
  515. left: 0;
  516. right: 0;
  517. top: 0;
  518. bottom: 0;
  519. &::before {
  520. display: block;
  521. height: 2px;
  522. width: 10px;
  523. content: "";
  524. position: absolute;
  525. right: 0;
  526. top: 0;
  527. background-color: #fff;
  528. transform: rotate(70deg);
  529. }
  530. &::after {
  531. display: block;
  532. height: 2px;
  533. width: 10px;
  534. content: "";
  535. position: absolute;
  536. right: 0;
  537. bottom: 0;
  538. background-color: #fff;
  539. transform: rotate(-70deg);
  540. }
  541. }
  542. }
  543. }
  544. // / 是否收起右侧边栏的图标
  545. // ^ 右侧拖动条
  546. .right-resize-bar {
  547. position: relative;
  548. display: flex;
  549. align-items: center;
  550. width: 7px;
  551. height: 100%;
  552. background-color: rgb(255, 255, 255);
  553. cursor: col-resize;
  554. user-select: none;
  555. transition: all ease 0.3s;
  556. font-size: 20px;
  557. color: #40485c;
  558. &:hover {
  559. color: #fff !important;
  560. background-color: #5e7ce0 !important;
  561. }
  562. }
  563. // / 右侧拖动条
  564. // ^ 右侧区域
  565. .right-area-box {
  566. flex: 1;
  567. display: flex;
  568. flex-direction: column;
  569. overflow: hidden;
  570. background-color: #f8f8f8;
  571. }
  572. // / 右侧区域
  573. }
  574. /* ---- / 右边 ---- */
  575. }
  576. </style>

二、运行效果

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

闽ICP备14008679号