vue开发公共组件之返回顶部
本文实例为大家分享了vue开发公共组件之返回顶部的具体代码,供大家参考,具体内容如下
记录一下开发公共组件的流程。
背景: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/>", });
补充:上述方法在安卓端会失效
原因是document.documentElement.scrollTop在安卓端始终是0;只有pc端和IOS端才是正常的。
改写backtop组件中的代码,完成兼容。
<template> <transition name="van-fade"> <div v-if="visible" @click.stop="handleClick" :style="{ right: styleRight, bottom: styleBottom, }" class="xl-backtop" > <slot> <van-icon name="arrow-up" color="#13b7f6" /> </slot> </div> </transition> </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() { // 这里,如果document.documentElement.scrollTop 的值为0,就获取document.body.scrollTop const scrollTop = this.el.scrollTop || document.body.scrollTop; this.visible = scrollTop >= this.visibilityHeight; }, handleClick(e) { this.scrollToTop(); this.$emit("click", e); }, scrollToTop() { // 还有这里,如果document.documentElement.scrollTop 的值为0,就获取document.body元素 const el = this.el.scrollTop? this.el : document.body; 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); this.el = null; }, }; </script>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
赞 (0)