Browse Source

fix: BackTop CodeReview

richard1015 5 years ago
parent
commit
34bc643bbb
3 changed files with 153 additions and 66 deletions
  1. 82 53
      src/packages/backtop/backtop.vue
  2. 24 2
      src/packages/backtop/demo.vue
  3. 47 11
      src/packages/backtop/doc.md

+ 82 - 53
src/packages/backtop/backtop.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :class="['nut-backtop', {'show': backTop}]" :style="styles" @click="goto">
+  <div :class="['nut-backtop', {'show': backTop}]" :style="styles" @click.stop="click">
     <slot>
       <div class="nut-backtop-main"></div>
     </slot>
@@ -25,6 +25,14 @@ export default {
       type: Number,
       default: 1000
     },
+    isAnimation: {
+      type: Boolean,
+      default: true
+    },
+    elId: {
+      type: String,
+      default: ""
+    },
     zIndex: {
       type: Number,
       default: 1111
@@ -32,17 +40,30 @@ export default {
   },
   data() {
     return {
-      backTop: false
+      backTop: false,
+      scrollEl: window
     };
   },
   mounted() {
-    window.addEventListener("scroll", this.handleScroll, false);
-    window.addEventListener("resize", this.handleScroll, false);
+    this.init();
+  },
+
+  activated() {
+    if (this.keepAlive) {
+      this.keepAlive = false;
+      this.init();
+    }
   },
-  beforeDestroy() {
-    window.removeEventListener("scroll", this.handleScroll, false);
-    window.removeEventListener("resize", this.handleScroll, false);
+
+  deactivated() {
+    this.keepAlive = true;
+    this.removeEventListener();
+  },
+
+  destroyed() {
+    this.removeEventListener();
   },
+
   computed: {
     styles() {
       return {
@@ -53,68 +74,76 @@ export default {
     }
   },
   methods: {
-    handleScroll() {
-      this.backTop = window.pageYOffset >= this.distance;
+    addEventListener() {
+      this.scrollEl.addEventListener("scroll", this.scrollListener, false);
+      this.scrollEl.addEventListener("resize", this.scrollListener, false);
+    },
+    removeEventListener() {
+      this.scrollEl.removeEventListener("scroll", this.scrollListener, false);
+      this.scrollEl.removeEventListener("resize", this.scrollListener, false);
     },
-    goto() {
-      const sTop =
-        document.documentElement.scrollTop || document.body.scrollTop;
-      this.scrollTop(window, sTop, 0, this.duration);
-      this.$emit("click");
+    requestAniFrame() {
+      return (
+        window.requestAnimationFrame ||
+        window.webkitRequestAnimationFrame ||
+        window.mozRequestAnimationFrame ||
+        function(callback) {
+          window.setTimeout(callback, 1000 / 60);
+        }
+      );
     },
-    scrollTop(el, from = 0, to, duration = 500, endCallback) {
-      this.el = el;
-      let lastTime = 0;
+    initCancelAniFrame() {
       let vendors = ["webkit", "moz"];
       for (
         let x = 0;
         x < vendors.length && !window.requestAnimationFrame;
         ++x
       ) {
-        window.requestAnimationFrame =
-          window[vendors[x] + "RequestAnimationFrame"];
         window.cancelAnimationFrame =
           window[vendors[x] + "CancelAnimationFrame"] ||
           window[vendors[x] + "CancelRequestAnimationFrame"];
       }
-
-      if (!window.requestAnimationFrame) {
-        window.requestAnimationFrame = function(callback, element) {
-          let currTime = new Date().getTime();
-          let timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
-          let id = window.setTimeout(function() {
-            callback(currTime + timeToCall);
-          }, timeToCall);
-          lastTime = currTime + timeToCall;
-          return id;
-        };
-      }
-      if (!window.cancelAnimationFrame) {
-        window.cancelAnimationFrame = function(id) {
-          clearTimeout(id);
-        };
-      }
-      const difference = Math.abs(from - to);
-      const step = Math.ceil((difference / duration) * 50);
-
-      this.scroll(from, to, step, endCallback);
     },
-    scroll(start, end, step, endCallback) {
-      if (start === end) {
-        endCallback && endCallback();
-        return;
-      }
-
-      let d = start + step > end ? end : start + step;
-      if (start > end) {
-        d = start - step < end ? end : start - step;
+    init() {
+      if (this.elId && document.getElementById(this.elId)) {
+        this.scrollEl = document.getElementById(this.elId);
       }
-      if (this.el === window) {
-        window.scrollTo(d, d);
+      this.addEventListener();
+      this.initCancelAniFrame();
+    },
+    scrollListener() {
+      this.scrollTop =
+        this.scrollEl.pageYOffset !== undefined
+          ? this.scrollEl.pageYOffset
+          : this.scrollEl.scrollTop;
+      this.backTop = this.scrollTop >= this.distance;
+    },
+    click() {
+      this.startTime = +new Date();
+      this.isAnimation && this.duration > 0
+        ? this.scrollAnimation()
+        : this.scroll();
+    },
+    scrollAnimation() {
+      const self = this;
+      var cid = self.requestAniFrame()(function fn() {
+        var t =
+          self.duration -
+          Math.max(0, self.startTime - +new Date() + self.duration);
+        var y = (t * -self.scrollTop) / self.duration + self.scrollTop;
+        self.scroll(y);
+        cid = self.requestAniFrame()(fn);
+        if (t == self.duration) {
+          window.cancelAnimationFrame(cid);
+        }
+      });
+    },
+    scroll(y = 0) {
+      if (this.scrollEl === window) {
+        window.scrollTo(0, y);
       } else {
-        this.el.scrollTop = d;
+        this.scrollEl.scrollTop = y;
       }
-      window.requestAnimationFrame(() => this.scroll(d, end, step));
     }
   }
 };

+ 24 - 2
src/packages/backtop/demo.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="back-top-demo">
+  <div class="back-top-demo" id="backtopid">
     <h3>《再别康桥》</h3>
     <p>徐志摩</p>
     <p>轻轻的我走了,正如我轻轻的来;</p>
@@ -38,7 +38,7 @@
     <p>乡愁是一湾浅浅的海峡</p>
     <p>我在这头</p>
     <p>大陆在那头</p>
-    
+
     <h3>《盼望》</h3>
     <p>席慕容</p>
     <p>其实我盼望的</p>
@@ -53,6 +53,28 @@
     <p>回首时</p>
     <p>那短短的一瞬</p>
     <nut-backtop @click="handleClick"></nut-backtop>
+    <nut-backtop :bottom="120" :is-animation="false" @click="handleClick">
+      <div
+        style="background-color: rgb(0, 0, 0);
+    color: rgb(255, 255, 255);
+    display: flex;
+    height: 44px;
+    width: 44px;
+    align-items: center;
+    justify-content: center;"
+      >无</div>
+    </nut-backtop>
+    <nut-backtop :bottom="70" @click="handleClick">
+      <div
+        style="background-color: rgb(0, 0, 0);
+    color: rgb(255, 255, 255);
+    display: flex;
+    height: 44px;
+    width: 44px;
+    align-items: center;
+    justify-content: center;"
+      >Top</div>
+    </nut-backtop>
   </div>
 </template>
 

+ 47 - 11
src/packages/backtop/doc.md

@@ -18,6 +18,38 @@
 </nut-backtop>
 ```
 
+## 无动画
+
+``` html
+<nut-backtop :bottom="120" :is-animation="false" @click="handleClick">
+      <div
+        style="background-color: rgb(0, 0, 0);
+    color: rgb(255, 255, 255);
+    display: flex;
+    height: 44px;
+    width: 44px;
+    align-items: center;
+    justify-content: center;"
+      >无</div>
+    </nut-backtop>
+```
+
+## 自定义样式
+
+``` html
+<nut-backtop :bottom="70" @click="handleClick">
+      <div
+        style="background-color: rgb(0, 0, 0);
+    color: rgb(255, 255, 255);
+    display: flex;
+    height: 44px;
+    width: 44px;
+    align-items: center;
+    justify-content: center;"
+      >Top</div>
+    </nut-backtop>
+```
+
 > “页面垂直方向滚动高度”后出现
 
 ## click事件
@@ -44,7 +76,7 @@ export default {
 <nut-backtop 
   :bottom="20"
   :right="20"
-  :zIndex="10"
+  :z-index="10"
 >
 </nut-backtop>
 ```
@@ -61,15 +93,19 @@ export default {
 
 ## Prop
 
-| 字段 | 说明 | 类型 | 默认值
-|----- | ----- | ----- | ----- 
-| duration | 设置动画持续时间 | Number | 1000
-| distance | “页面垂直方向滚动高度”后出现 | Number | 200
-| bottom | 设置离页面底部距离 | Number | 30
-| right | 设置离页面右边距离 | Number | 30
-| zIndex | 设置层级 | Number | 1111
+| 字段         | 说明                         | 类型    | 默认值 |
+|--------------|------------------------------|---------|--------|
+| distance     | “页面垂直方向滚动高度”后出现 | Number  | 200    |
+| is-animation | 是否有动画,和duration参数互斥 | Boolean | true   |
+| duration     | 设置动画持续时间             | Number  | 1000   |
+| z-index       | 设置层级                     | Number  | 1111   |
+| el-id        | 设置滚动事件监听的容器id     | String  | -      |
+| right        | 设置离页面右边距离           | Number  | 30     |
+| bottom       | 设置离页面底部距离           | Number  | 30     |
+
+> 常见问题 : 滚动监听对象默认为window对象,开发者页面布局高度100%布局场景下,请采用此参数el-id
 
 ## Event
-| 字段 | 说明 | 回调参数 
-|----- | ----- | ----- 
-| click | 按钮点击时触发 | -
+| 字段  | 说明           | 回调参数 |
+|-------|----------------|----------|
+| click | 按钮点击时触发 | -        |