vue開發公共組件之返回頂部(backtop)

記錄一下開發公共組件的流程。

背景:pc端使用element-ui框架,本身是有返回頂部的組件的。現在需要在移動端使用。照着葫蘆畫瓢弄一個。
記錄如何將公共組件通過install的方式,註冊爲全局的組件使用。

components目錄下,新建bacttop文件夾,內部包含一個index.js文件和一個src文件夾。
src文件夾內放backtop.vue組件文件。

|--components
   |--index.js
   |-- backtop
       |--index.js
       |--src
       	  |--backtop.vue

backtop下的index.js負責安裝,backtop.vue內部寫具體的組件代碼

index.js文件內容:

// index.js
import Backtop from "./src/backtop"; // 引入組件

// 配置安裝方法
/* istanbul ignore next */
Backtop.install = function (Vue) {
  Vue.component(Backtop.name, Backtop);
};

// 導出模塊
export default Backtop;

backtop.vue文件內容:

<template>
 <!-- xl-backtop樣式名,需要自己在樣式文件中定義這個樣式內容 -->
  <div
    v-if="visible"
    @click.stop="handleClick"
    :style="{
      right: styleRight,
      bottom: styleBottom,
    }"
    class="xl-backtop"
  >
    <slot>
    <!-- 這裏是返回頂部的圖標 -->
      <van-icon name="arrow-up" />
    </slot>
  </div>
</template>

<script>
// 這裏引入了節流函數
import { _throttle } from "@/utils";

const cubic = (value) => Math.pow(value, 3);
const easeInOutCubic = (value) =>
  value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2;

export default {
  name: "XlBacktop",

  props: {
    visibilityHeight: {
      type: Number,
      default: 200,
    },
    target: [String],
    right: {
      type: Number,
      default: 40,
    },
    bottom: {
      type: Number,
      default: 40,
    },
  },

  data() {
    return {
      el: null,
      container: null,
      visible: false,
    };
  },

  computed: {
    styleBottom() {
      return `${this.bottom}px`;
    },
    styleRight() {
      return `${this.right}px`;
    },
  },

  mounted() {
    this.init();
    this.throttledScrollHandler = _throttle(this.onScroll, 300);
    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;
      }
    },
    onScroll() {
      const scrollTop = this.el.scrollTop;
      this.visible = scrollTop >= this.visibilityHeight;
    },
    handleClick(e) {
      this.scrollToTop();
      this.$emit("click", e);
    },
    scrollToTop() {
      const el = this.el;
      const beginTime = Date.now();
      const beginValue = el.scrollTop;
      const rAF =
        window.requestAnimationFrame || ((func) => setTimeout(func, 16));
      const frameFunc = () => {
        const progress = (Date.now() - beginTime) / 500;
        if (progress < 1) {
          el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
          rAF(frameFunc);
        } else {
          el.scrollTop = 0;
        }
      };
      rAF(frameFunc);
    },
  },

  beforeDestroy() {
    this.container.removeEventListener("scroll", this.throttledScrollHandler);
  },
};
</script>

返回頂部的樣式內容:

// 返回頂部
.xl-backtop {
   position: fixed;
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 20px;
  cursor: pointer;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.12);
  border-radius: 50%;
  z-index: 5;
}

爲了一次性註冊多個自己寫的功能組件,我們在components文件夾下面寫一個index.js

components下的index負責一次性組合多個

// components/index.js
import BackTop from "./backtop"; // 引入我們的返回頂部組件。其他的類似的一起寫在這裏
const components = [BackTop]; // 其他的組件以數組形式繼續寫
const install = function (Vue, opts = {}) {
  components.map((component) => {
    Vue.component(component.name, component);
  });
};
/* istanbul ignore if */
if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue);
}
// 組合導出安裝方法
const exportsResult = {
  version: "1.0.0",
  install,
};
Object.assign(exportsResult, components);

export default exportsResult;

最後在項目的main.js安裝

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from "vue";
import App from "./App";
import store from "./store";
import router from "./router";


// 自己封裝的公共安裝組件
import XlComponent from "@/components";
Vue.use(XlComponent);






import "@/styles/index.less"; // 全局 css

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
  el: "#app",
  router,
  store,
  components: { App },
  template: "<App/>",
});
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章