vue开发公共组件之返回顶部
本文实例为大家分享了vue开发公共组件之返回顶部的具体代码,供大家参考,具体内容如下
记录一下开发公共组件的流程。
背景:pc端使用element-ui框架,本身是有返回顶部的组件的。现在需要在移动端使用。照着葫芦画瓢弄一个。
记录如何将公共组件通过install的方式,注册为全局的组件使用。
components目录下,新建bacttop文件夹,内部包含一个index.js文件和一个class="lazy" data-src文件夹。
class="lazy" data-src文件夹内放backtop.vue组件文件。
|--components
|--index.js
|-- backtop
|--index.js
|--class="lazy" data-src
|--backtop.vue
backtop下的index.js负责安装,backtop.vue内部写具体的组件代码
index.js文件内容:
// index.js
import Backtop from "./class="lazy" data-src/backtop"; // 引入组件
// 配置安装方法
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);
});
};
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;
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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341