<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
的顶部