效果圖

功能
實現bar左右拖拽
左側:js通過width控制 :style="{width: lwidth}"
右側:盒子設置定位position,js通過的left來控制,同時樣式需要設置 right: 0; bottom: 0; 才會出現width
中間:設置定位position,使用calc計算的時候,`calc(${this.left_width *100 }% - 5px)`,同時需要通過js來計算對應的位置設置left,:style="{left: bar_width}";
bar移動:
鼠標按下mousedown后監聽鼠標移動mousemove和鼠標抬起mouseup事件;
在data中定義一個變量記錄此時是抬起還是按下,按下可以移動,抬起不移動【鼠標移動和抬起都是給document綁定,因為在容器外也可以移動】;
出現的bug:不是點擊正中間的bar時,bar會自動移動到中間,可以通過減去bar自身的寬度解決
解決辦法:
data中定義一個【鼠標距離bar容器左側的距離】initWidth,當鼠標按下時給這個值賦值,
this.initWidth = event.pageX - event.srcElement.getBoundingClientRect().left
在計算鼠標到大盒子box左側距離時減去initWidth, 同時需要加上自身寬度的一半
let MBoffsetPrec = (event.pageX - this.$refs.wrapper.getBoundingClientRect().left - this.initWidth + 5)/this.$refs.wrapper.getBoundingClientRect().width
設置左右兩側的最大(盒子寬度 - bar一半寬度) 最小 (bar一半寬度) 臨界值,不能超出邊界外
const min = (this.$refs.bar.offsetWidth / 2) /this.$refs.wrapper.getBoundingClientRect().width const max = (this.$refs.wrapper.getBoundingClientRect().width - (this.$refs.bar.offsetWidth / 2)) / this.$refs.wrapper.getBoundingClientRect().width

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box{ width: 500px; height: 300px; background-color: pink; position: relative; margin: 100px auto; overflow: hidden; } .left{ position: absolute; top: 0; background-color: skyblue; /* width: 30%; */ height: 100%; } .bar{ position: absolute; height: 100%; width: 10px; background-color: teal; z-index: 2; user-select: none; } .right{ position: absolute; top: 0; /* left: 30%; */ right: 0; bottom: 0; background-color: yellow; height: 100%; } </style> </head> <body> <div id="app"> <div class="box" ref="wrapper"> <div class="left" :style="{width: lwidth}" @click="handelChange">zuo</div> <div class="bar" :style="{left: bar_width}" @mousedown="handelMousedown" ref="bar"></div> <div class="right" :style="{left: lwidth}">you</div> </div> </div> <script src="http://vuejs.org/js/vue.js"></script> <script> var vm=new Vue({ el:'#app', data:{ left_width: 0.5, // 記錄鼠標按下還是抬起 isMousemouse: false, //鼠標距離bar容器左側的距離 initWidth: 0 }, methods:{ handelChange(){ this.left_width -= 0.05 console.log(this.$refs.bar.offsetWidth / 2); }, handelMousedown(event){ this.isMousemouse = true this.initWidth = event.pageX - event.srcElement.getBoundingClientRect().left // console.log(this.initWidth); // 移動的時候給document綁定事件,在容器外也能移動 document.addEventListener('mousemove',this.handelMousemove) // 在框外停下鼠標不能移動,也給document綁定事件 document.addEventListener('mouseup',this.handelMouseup) }, handelMousemove(event){ if(this.isMousemouse){ // event.pageX:鼠標指針相對於該網頁的水平位置;getBoundingClientRect().left: 容器距離頁面左側距離 // MBoffset: 鼠標距離盒子左側的位置 // initWidth:鼠標距離bar容器左側的距離 let MBoffsetPrec = (event.pageX - this.$refs.wrapper.getBoundingClientRect().left - this.initWidth + this.$refs.bar.offsetWidth / 2)/this.$refs.wrapper.getBoundingClientRect().width const min = (this.$refs.bar.offsetWidth / 2) /this.$refs.wrapper.getBoundingClientRect().width const max = (this.$refs.wrapper.getBoundingClientRect().width - (this.$refs.bar.offsetWidth / 2)) / this.$refs.wrapper.getBoundingClientRect().width if(MBoffsetPrec < min){ MBoffsetPrec = min return this.left_width = MBoffsetPrec }else if(MBoffsetPrec > max){ return MBoffsetPrec = max } this.left_width = MBoffsetPrec }else{ return } }, handelMouseup(){ this.isMousemouse = false } }, computed: { lwidth(){ return (this.left_width * 100) + '%' }, bar_width(){ // 5 是bar的一半寬度 return `calc(${this.left_width *100 }% - 5px)` } }, }) </script> </body> </html>
