本節代碼對照:
https://github.com/lison16/vue-cource/blob/master/src/components/split-pane/split-pane.vue
https://github.com/lison16/vue-cource/blob/master/src/views/split-pane.vue
創建組件的文件夾叫做split-pane
在路由列表里面注冊一下
添加這個vue頁面
創建組件的vue文件,設置name為SplitPane
創建index.js.把組件引進來,並導出去
引入這個組件,然后注冊這個組件。
容器中分成兩個區域,通過拖動來改變兩個區域的比例。
還可以上下,嵌套使用。
分為三個部分,左邊的區域,右邊的區域,然后是中間可拖動的部分
我們首先來定義三個div。它的寬和高應該和父容器是一樣的,所以這里我們設置它的高度和寬度是100%
寬度其實可以不設置,div是一個塊級元素,它本身的寬度就是和它容器的寬度是一樣的
less里面的寫法,有層級管理的關系的class類型,可以嵌套着寫。他們有一個共同的class是pane。左邊是pane-left右邊是pane-right
它們的高度也是和父容器一樣高
&-left就是拼接了父級別的pane。所以這里就相當於是.pane-left
我們給左邊加了一個背景色,可以看到它的顏色和父容器是一樣寬的。
再給右側的div設置一個背景色是橘黃色的,可以看到倆div成了上下布局了,因為他倆的寬度都是100%和父容器的寬度一樣。所以右側的就被擠下來了
想讓這倆div在一排上顯示。給.pane設置寬度為50%。值是寬度變窄了, 還沒有在一排上顯示。
可能有個默認的樣式是居中的,
src根目錄下的 App.vue 把這里注釋掉。因為設置了居中顯示,所以導致了上面的問題。
這里改成float:left。這樣就上到一行里面顯示了。
如果想設置左邊是30%的寬度,右邊是70%的寬度
把float:left和width都去掉。
給他倆一個position,都設置為絕對定位
設置絕對定位后,它會往上找,去他的父元素一級一級的找,它會根據有定位屬性的父元素來定位。如果沒有它就一直找到html標簽。
所以這里地方我們要給wrapper一個相對定位的屬性。這樣又不會使wrapper的元素受到影響。
讓他倆的父元素的top位置都是0,左邊設置寬度為30%。右邊這個呢?也想讓他用30%的這個值,top:0我們在.pane已經設置了,這里會繼承過來,
這樣設置右邊就是70%的寬度,用到了同樣的變量30%。這樣就是兩邊加起來就是100%
把左邊改成20%
右邊的left也改成20%。這樣他倆加起來就是100%
30%的這個值,想通過js變量去控制,這樣這個值就不能寫在css里面了。我們給它綁定一個變量,變量在data里面定義。
30%通過計算屬性計算出來。
這樣就把左邊的30%的css屬性注釋掉。
右邊是通過left的值,修改它的寬度。所以右邊我們綁定的css屬性是left
通過一個按鈕改變這個變量的值來試一下
把這個按鈕放在了左側的面板里面
通過點擊左側按鈕的面板,改變左側pane的寬度
每次點擊寬度變小。Vue里面,這樣通過數據驅動樣式的改變,這樣避免了數據和視圖不對應
定義trigger中間拖動條
它要顯示在中間也是需要設置絕對定位。設置了top為0,它顯示在了最左側。
也是給中間的條綁定style屬性。但是綁定上left后,視圖中紅色的調不見了。
中間的條,實際上在這里,說明可能是被元素遮住了。
通過設置一個z-index來看下
紅色的條 實際上是蓋在,右側的
我們希望他在最中間顯示。
首先中間條的寬度我們通過屬性傳遞進來,默認是8.我們定義個props屬性 triggerWidth
首先是向左偏移30%和left的寬度是一樣的,然后它需要減少4個像素,來達到在最中間,這里我們用到css3的一個方法calc(),它允許你在里面做一些計算。
30%的偏移再減去4像素,就可以這么寫
減去的是triggerWidth除以2
return `calc(${this.leftOffset * 100}% - ${this.triggerWidth / 2}px)`
這里綁定的是 triggerWidh 后面是px
<div class="pane pane-trigger-con" :style="{ left: triggerLeft, width: `${triggerWidth}px` }"></div>
中間只用到了width屬性
說明我們這里的計算屬性並沒有生效
我們這里把計算出來的值打印出來看一下
這里的單詞拼錯, 應該是calc
紅色的條被左側遮住了一半
被右側也遮住了一半
鼠標拖動中間trigger條
這就用到了鼠標的三個事件了
首先綁定一個mousemove事件
我們會用到參數里面的pageX就是鼠標距離頁面左側的像素,
只要能算出來鼠標距離左側有多少像素,我們只要知道這個容器距離頁面左側多少,用鼠標的距離減去容器的距離頁面的距離,就是左側left的寬度了。
獲取dom元素用ref
那么怎么獲取父容器距離左邊的距離呢?獲取dom容器呢 我們用ref屬性,給父容器div加一個ref屬性為outer
getBoundingClientRect
理解:getBoundingClientRect用於獲取某個元素相對於視窗的位置集合。集合中有top, right, bottom, left等屬性。
2.返回值類型:
rectObject.top:元素上邊到視窗上邊的距離;
rectObject.right:元素右邊到視窗左邊的距離;
rectObject.bottom:元素下邊到視窗上邊的距離;
rectObject.left:元素左邊到視窗左邊的距離;


獲取到dom后,它有個方法叫做getBoundingClientRect,這個方法返回一個對象,
這個方法返回一個對象,對象里面返回一個屬性,
先來看下它返回的值
對象里面包含了這些屬性,這些屬性在IE9下也是支持的,所以兼容性是沒有問題的。
所以這里我們減去left
鼠標的事件,有時候鼠標會超過這個框,應該綁定在頁面級別。
所以我們把mouseMove事件綁定子在document上。就是鼠標在中間的條上,按下的時候綁定這個事件。
所以這里中間的條的事件,改成mousedown事件
鼠標按下我們給document綁定一個事件,它的回調事件是下面的handleMousemove事件
當點擊這個條的時候,然后鼠標在頁面上移動,console內不斷的輸出的
偏移量除以容器的總寬度,再乘以100,就是百分比。
outerRect.width是容器的寬度,也就是dom對象的總的寬度
乘以100 去掉
this.leftOffset = (offset / outerRect.width)
現在這個條就隨着鼠標的移動而移動了
我們希望按下鼠標的時候 開始移動,松開鼠標的時候就應該停止了。
所以我們就需要有個狀態,鼠標是按下還是抬起
只有為true的時候才能移動。
mouseup的事件
這樣只有鼠標按下才能移動,鼠標抬起就不能移動了。
點擊中間的條,靠左半邊點,或者靠右半邊的時候點擊會出現這個偏移量的問題。
在鼠標按下的時候,有一個瞬間的偏移。出現問題的原因是我們在注冊事件的時候忽略了 中間的條 也有個寬度。
所以在條上有個初始的偏移量,它的初始是0
我們就要給這個偏移量設置一個值,當我們按下的時候。我要把這個寬度也計算在內。
減去這個條距離頁面左側的距離。就是鼠標距離這個條的左側距離。
因為這個事件是發生在這個條上的,
this.initOffset = event.pageX - event.srcElement.getBoundingClientRect().left
在move的時候,我們要減去這個值
還需要再加上條一半的寬度
這個時候再去拖動,就不會有一瞬間的移動了
設置最大值和最小值。
拖動最右邊應該有個頭,這里完全拖出去了。
設置最小的百分比值,是0.1
當你的拖動到百分之0.1的時候,左側的值就不會再變了。
除法的邏輯加到上面去
如果偏移量小於這個最小值的話,那么就用這個最小值。
到了最小值 再拖,就拖不動了。
我們再來設置一個最大值,最大值設置為0.9
超過最大值,就是最大值。
拖動過程中,選中的問題
拖動過程中,偶爾會做了一些選中的操作
通過設置一個樣式。這樣他就不會在這個元素上選中操作了。
初始偏移量
設置初始的偏移
調用的時候就可以設置初始的偏移了 。
這里就注釋掉,不用了。
這里就改成value的形式
我們是通過拖動來修改這個值的,那么有個問題就是。子組件如果想改變父組件的值,不能直接通過這種賦值的形式。還是要通過事件來觸發 ,告訴父組件,父組件內做事件的響應,
再父組件內,把這個傳入百分比值改成變量
然后給它綁定一個事件
回調函數里面有個參數,我們接收這個參數,並賦值給偏移量的變量值
在這里我們要拋出這個事件
拖動和修改都沒有問題了。
<split-pane :value="offset" @input="handleInput"></split-pane>
另外一種方式vue提供的語法糖
v-model簡寫的形式
.sync修飾符

子組件內,事件也不拋出去了。改用update:value


這么寫首先給value綁定值offset,同時會給你綁定一個事件會更新這個offset的值,

子組件內要觸發一個事件,固定的就叫做update。

update后面的:value就是我們這里父組件的屬性名

最后 就是你要更新的值

在區域內填充內容
就用到了我們之前講到的slot插槽的概念
右邊的right給壓到中間的條下面了。給右側綁定一個triggerWidth除以2
加一個paddingLeft的屬性 是中間調的寬度除以2
這樣它的內容就不會被壓到了。
同理left也有一個paddingRight屬性
鼠標的樣式
鼠標放上去,要讓用戶知道這是一個可以拖動的,我們就需要給它設置一個css的演示
鼠標的樣式記不住呢,推薦大家一個網站
http://css-cursor.techstream.org/
鼠標放上去會顯示對應的鼠標樣式。
左右拖動的效果就是這個了
