<transition name="el-fade-in">
<div v-if="visible" @click.stop="handleClick" :style="{ 'right': styleRight, 'bottom': styleBottom }" class="el-backtop">
<slot>
<el-icon name="caret-top"></el-icon>
</slot>
</div>
</transition>
複製代碼
能夠看到,backtop組件的結構是比較簡單的。div > icon
。
icon是寫在slot裏面,這樣子的寫法有一個好處就是若是沒有傳遞slot,那麼這個icon將會顯示出來,若是傳遞slot,那麼icon將不會渲染,詳見官網:cn.vuejs.org/v2/guide/co…javascript
backTop組件有兩個重要的點html
mounted() {
this.init();
this.throttledScrollHandler = throttle(300, this.onScroll);
this.container.addEventListener('scroll', this.throttledScrollHandler);
},
// methods:
init() {
this.container = document;
this.el = document.documentElement;
if (this.target) {
this.el = document.querySelector(this.target);
if (!this.el) {
throw new Error(`target is not existed: ${this.target}`);
}
this.container = this.el;
}
},
複製代碼
mounted
時,獲取prop
值target
(觸發滾動的對象),將target元素賦值給this.el
和this.container
。監聽this.container
的scroll
事件。同時,這裏作了節流的處理。每300毫秒內重複觸發scroll事件都會被認爲只觸發一次 。vue
我以爲有兩個節流與防抖的比喻,很是形象!!!
節流比如地鐵限流,過一段時間纔會放人進去
防抖比如坐電梯,只有沒有人在上來了,電梯門纔會關閉。不然持續有人上電梯,電梯是不會關門的。java
當滾動的高度大於visibilityHeight
(backtop組件可見時的高度), visible纔會爲true。git
click事件除了emit以外,還要作的就是返回頂部。若是直接將this.el
的滾動高度設置爲0,固然是最簡單最容易達到目的。可是不要忘了,element-ui的設計原則: 一致,反饋,效率,可控。feedback(反饋)這一點,明確的說到:github
反饋 Feedback
控制反饋:經過界面樣式和交互動效讓用戶能夠清晰的感知本身的操做; 頁面反饋:操做後,經過頁面元素的變化清晰地展示當前狀態。element-ui
若是咱們可以讓滾動條慢慢的滾回到頂部,而不是一會兒跳到頂部,是比較符合咱們的習慣的。show code:bash
scrollToTop() {
let el = this.el;
let step = 0;
let interval = setInterval(() => {
if (el.scrollTop <= 0) {
clearInterval(interval);
return;
}
step += 10;
el.scrollTop -= step;
}, 20);
}
複製代碼
attention please:iview
scrollTop < 0
呢? 這個時候就要請出咱們的MDN規範老師了scrollTop 能夠被設置爲任何整數值,同時注意:async
- 若是一個元素不能被滾動(例如,它沒有溢出,或者這個元素有一個"non-scrollable"屬性), scrollTop將被設置爲0。
- 設置scrollTop的值小於0,scrollTop 被設爲0
- 若是設置了超出這個容器可滾動的值, scrollTop 會被設爲最大值.
it('create', async() => {
vm = createVue({
template: `
<div ref="scrollTarget" class="test-scroll" style="height: 100px; overflow: auto">
<div style="height: 10000px; width: 100%">
<el-backtop target=".test-scroll">
<span>test_up_text</span>
</el-backtop>
</div>
</div>
`
}, true);
expect(vm.$el).to.exist;
expect(vm.$el.innerText).to.be.equal('');
vm.$refs.scrollTarget.scrollTop = 2000;
await wait();
expect(vm.$el.innerText).to.be.equal('test_up_text');
});
複製代碼
測試用例中,對visible進行了測試。這個就比較簡單,就無需多講啦。
iview
的異同不一樣 | element | iview |
---|---|---|
scroll事件 | 節流 | - |
滾動對象 | prop(target)決定 | window |
顯示隱藏 | v-if | display |
動畫 | setInterval,逐漸加快 | requestAnimationFrame, 勻速 |
提供了一個prop: duration
,是滾動動畫持續時間,單位毫秒
// scrollTop animation
export function scrollTop(el, from = 0, to, duration = 500, endCallback) {
// `requestAnimationFrame `降級處理處理,代碼省略
const difference = Math.abs(from - to);
const step = Math.ceil(difference / duration * 50);
function scroll(start, end, step) {
if (start === end) {
endCallback && endCallback();
return;
}
let d = (start + step > end) ? end : start + step;
if (start > end) {
d = (start - step < end) ? end : start - step;
}
if (el === window) {
window.scrollTo(d, d);
} else {
el.scrollTop = d;
}
window.requestAnimationFrame(() => scroll(d, end, step));
}
scroll(from, to, step);
}
複製代碼
requestAnimationFrame
降級處理step = Math.ceil(difference / duration * 50)
計算每幀須要滾動的距離爲何是50
?
我也不知道 = = 我以爲是算錯了TAT, 應該是*(1000/60)
纔對
scrollTop
window.pageYOffset
el.scrollTop
結合兩個組件庫的特色,總結以下:
requestAnimationFrame
處理動畫target
,指定觸發滾動的對象,咱們要的backTop組件並不是必定是返回document.documentElement
的頂部