vue 返回顶部组件(可自定义)

时间:2024-03-26 17:33:10
一、大致效果图

vue 返回顶部组件(可自定义)
vue 返回顶部组件(可自定义)
默认: vue 返回顶部组件(可自定义)

说明:使用非脚手架开发,脚手架开发使用 ==> 可直接新建.vue文件,复制代码过去即可。

二、主内容

2.0 页面调用

<go-top :nav-data="navData" ref="backTop" @handle-click="getHandleClick"></go-top>

2.1 数据获取

const vm = new Vue({
	el: '#view',
	data() {
		return {
			testData: [],
			navData: []
		}
	},
	created() {
		// 页面假数据模拟
		for (let i = 0; i < 200; i++) {
			this.testData.push(`testScroll-${i + 1}`)
		}

		// `axios` 获取导航数据
		axios.get('json/demo-goTop.json').then(res => {
			this.navData = res.data.navData
		}).catch(err => {
			console.log(err)
		})
	},
	methods: {
		// 获取子组件点击事件传的值
		getHandleClick(data, index, event) {
			switch (data.clickType) {
				case 0:
					return false
				case 1:
					window.open(data.urlPath)
					break
				case 2:
					window.open(data.urlPath, '_blank',
						'width=300,height=300,menubar=no,toolbar=no, status=no,scrollbars=yes')
					break
				case 3:
					this.$refs.backTop.goTopClick()
					break
			}
		}
	}
})

2.2 组件

Vue.component('go-top', {
	template: `
		<div class="top-warp" v-if="navData.length">
			<div class="top-ul">
				<div class="top-li" v-for="(val,key) in navData" :key="key" v-if="val.isShowTop" :style="bgStyle(key, oneNavHover)"
				@click="handleClickData(val, key, $event)" @mouseover="addHoverStyle(key)" @mouseleave="cleanHoverStyle">
					<i class="iconfont" :class="val.icon"></i>
					<div class="top-li-msg" :class="{'top-QR' : val.children.length}" :style="bgStyle(key, twoNavHover)">
						<span class="top-triangle" :style="brColor(key, twoNavHover)"></span>
						<span v-if="!val.children.length">{{val.title}}</span>
						<div class="top-img-flex" v-else>
							<div class="top-img" v-for="(v,k) in val.children" :key="k">
								<img :src="v.imgPath">
								<span>{{v.msg}}</span>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	`,
	props: {
		navData: {
			type: Array,
			default: () => []
		},
		speed: {
			type: Number,
			default: 100
		},
		showBtnOffset: {
			type: Number,
			default: 200
		},
		oneNavHover: {
			type: String,
			default: '#000000'
		},
		twoNavHover: {
			type: String,
			default: '#f44444'
		}
	},
	data() {
		return {
			hoverIndex: null
		}
	},
	mounted() {
		window.addEventListener('scroll', this.getScollTop, true)
	},
	methods: {
		// 动态添加样式
		bgStyle(key, hoverStyle) {
			return {
				background: key == this.hoverIndex ? hoverStyle : ''
			}
		},
		brColor(key, hoverStyle) {
			return {
				borderLeftColor: key == this.hoverIndex ? hoverStyle : ''
			}
		},
		addHoverStyle(index) {
			this.hoverIndex = index
		},
		cleanHoverStyle() {
			this.hoverIndex = null
		},

		// 当前点击
		handleClickData(data, index, event) {
			this.$emit('handle-click', data, index, event)
		},

		// 滚动条
		getScollTop() {
			let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
			this.navData.filter(item => {
				if (scrollTop > this.showBtnOffset) {
					return item.clickType == 3 ? item.isShowTop = true : item.isShowTop = true
				} else {
					return item.clickType == 3 ? item.isShowTop = false : item.isShowTop = true
				}
			})
		},

		// 返回顶部点击
		goTopClick() {
			let cleanTime = setInterval(() => {
				document.documentElement.scrollTop -= this.speed
				if (document.documentElement.scrollTop === 0) {
					this.cleanHoverStyle()
					clearInterval(cleanTime)
				}
			}, 10)
		}
	}
})

2.31 Attributes

参数 类型 默认值 说明
nav-data Array [] 导航数据(即下面的json
speed Number 100 滚动条滚动到顶部的速度
show-btn-offset Number 200 返回顶部按钮出现的初始位置
one-nav-hover String ‘#000000’ 一级导航鼠标经过背景颜色
two-nav-hover String ‘#f44444’ 二级导航背景颜色
backTop String ref="backTop" *想要返回顶部功能,此项必须加上

2.32 Events

事件名 参数 说明
handle-click data, index, event 当前项导航点击时,获取子组件的数据,下标及 event。通过 data.clickType 判断点击之后,具体要做什么,返回顶部按钮点击时,需要手动触发方法:this.$refs.backTop.goTopClick()

2.4 json 数据格式

{
	"navData": [{
			"icon": "icon-fanhuidingbu",
			"urlPath": "https://www.csdn.net/",
			"title": "返回顶部",
			"isShowTop": false,
			"clickType": 3,
			"children": []
		},
		{
			"icon": "icon-erweima",
			"urlPath": "https://www.csdn.net/",
			"title": "",
			"clickType": 0,
			"isShowTop": true,
			"children": [{
					"msg": "关注公众号",
					"imgPath": "https://g.csdnimg.cn/side-toolbar/1.2/images/qr_wechat.png"
				},
				{
					"msg": "下载APP",
					"imgPath": "https://g.csdnimg.cn/side-toolbar/1.2/images/qr_app.png"
				}
			]
		},
		{
			"icon": "icon-2zaixiankefucheng",
			"urlPath": "https://www.csdn.net/",
			"title": "在线客服",
			"clickType": 1,
			"isShowTop": true,
			"children": []
		},
		{
			"icon": "icon-fankuiyijian",
			"urlPath": "https://www.csdn.net/",
			"title": "意见反馈",
			"clickType": 2,
			"isShowTop": true,
			"children": []
		}
	]
}
三、全部html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title>vue返回顶部组件</title>
		<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_1078306_8ycnernwlnu.css" />
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
		<style type="text/css">
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
			}

			html,
			body,
			section {
				width: 100%;
				height: 100%;
				background: #F5F5F5;
			}

			[v-clock] {
				display: none;
			}

			/* start */
			.top-warp {
				width: 38px;
				min-height: 38px;
				position: fixed;
				right: 20px;
				bottom: 60px;
				cursor: pointer;
				background: white;
				box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
			}

			.top-ul {
				display: flex;
				flex-direction: column;
			}

			.top-li {
				width: 100%;
				height: 38px;
				display: flex;
				position: relative;
			}

			.top-li i {
				margin: auto;
			}

			.top-li-msg {
				position: absolute;
				height: 38px;
				line-height: 38px;
				left: -100px;
				width: 74px;
				color: white;
				font-size: 14px;
				text-align: center;
				transition: left .5s ease;
				transform-style: preserve-3d;
				visibility: hidden;
				opacity: 0;
			}

			.top-triangle {
				position: absolute;
				right: -5px;
				top: 50%;
				transform: translateY(-50%);
				width: 0;
				height: 0;
				border-style: solid;
				border-width: 5px 0 5px 5px;
				border-color: transparent transparent transparent #f44444;
			}

			.top-QR {
				height: 125px;
				width: 200px;
				top: 50%;
				left: -226px;
				transform: translateY(-50%);
				z-index: 1;
				display: flex;
			}

			.top-nav {
				background: #f44444;
			}

			.top-img-flex {
				display: flex;
				width: 100%;
			}

			.top-img {
				flex: 1;
				padding: 10px;
				font-size: 14px;
				display: flex;
				flex-direction: column;
				margin: auto;
			}

			.top-img img {
				width: 80px;
				height: 80px;
				margin: auto;
			}

			.top-li:hover {
				color: white;
			}

			.top-li:hover .top-li-msg {
				left: -74px;
				transition: left .5s ease;
				visibility: visible;
				opacity: 1;
			}

			.top-li:hover .top-QR {
				left: -200px;
			}

			/* end */
		</style>
	</head>
	<body>
		<section id="view" clock>
			<div v-for="v in testData" :key="v">{{v}}</div>
			<go-top :nav-data="navData" :speed="300" one-nav-hover="#09F" two-nav-hover="green" @handle-click="getHandleClick"
			 :show-btn-offset="1000" ref="backTop"></go-top>
		</section>
	</body>

	<script type="text/javascript">
		Vue.component('go-top', {
			template: `
				<div class="top-warp" v-if="navData.length">
					<div class="top-ul">
						<div class="top-li" v-for="(val,key) in navData" :key="key" v-if="val.isShowTop" :style="bgStyle(key, oneNavHover)"
						@click="handleClickData(val, key, $event)" @mouseover="addHoverStyle(key)" @mouseleave="cleanHoverStyle">
							<i class="iconfont" :class="val.icon"></i>
							<div class="top-li-msg" :class="{'top-QR' : val.children.length}" :style="bgStyle(key, twoNavHover)">
								<span class="top-triangle" :style="brColor(key, twoNavHover)"></span>
								<span v-if="!val.children.length">{{val.title}}</span>
								<div class="top-img-flex" v-else>
									<div class="top-img" v-for="(v,k) in val.children" :key="k">
										<img :src="v.imgPath">
										<span>{{v.msg}}</span>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>
			`,
			props: {
				navData: {
					type: Array,
					default: () => []
				},
				speed: {
					type: Number,
					default: 100
				},
				showBtnOffset: {
					type: Number,
					default: 200
				},
				oneNavHover: {
					type: String,
					default: '#000000'
				},
				twoNavHover: {
					type: String,
					default: '#f44444'
				}
			},
			data() {
				return {
					hoverIndex: null
				}
			},
			mounted() {
				window.addEventListener('scroll', this.getScollTop, true)
			},
			methods: {
				// 动态添加样式
				bgStyle(key, hoverStyle) {
					return {
						background: key == this.hoverIndex ? hoverStyle : ''
					}
				},
				brColor(key, hoverStyle) {
					return {
						borderLeftColor: key == this.hoverIndex ? hoverStyle : ''
					}
				},
				addHoverStyle(index) {
					this.hoverIndex = index
				},
				cleanHoverStyle() {
					this.hoverIndex = null
				},

				// 当前点击
				handleClickData(data, index, event) {
					this.$emit('handle-click', data, index, event)
				},

				// 滚动条
				getScollTop() {
					let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
					this.navData.filter(item => {
						if (scrollTop > this.showBtnOffset) {
							return item.clickType == 3 ? item.isShowTop = true : item.isShowTop = true
						} else {
							return item.clickType == 3 ? item.isShowTop = false : item.isShowTop = true
						}
					})
				},

				// 返回顶部点击
				goTopClick() {
					let cleanTime = setInterval(() => {
						document.documentElement.scrollTop -= this.speed
						if (document.documentElement.scrollTop === 0) {
							this.cleanHoverStyle()
							clearInterval(cleanTime)
						}
					}, 10)
				}
			}
		})
	</script>

	<script type="text/javascript">
		const vm = new Vue({
			el: '#view',
			data() {
				return {
					testData: [],
					navData: []
				}
			},
			created() {
				// 页面假数据模拟
				for (let i = 0; i < 200; i++) {
					this.testData.push(`testScroll-${i + 1}`)
				}

				// `axios` 获取导航数据
				axios.get('json/demo-goTop.json').then(res => {
					this.navData = res.data.navData
				}).catch(err => {
					console.log(err)
				})
			},
			methods: {
				// 获取子组件点击事件传的值
				getHandleClick(data, index, event) {
					switch (data.clickType) {
						case 0:
							return false
						case 1:
							window.open(data.urlPath)
							break
						case 2:
							window.open(data.urlPath, '_blank',
								'width=300,height=300,menubar=no,toolbar=no, status=no,scrollbars=yes')
							break
						case 3:
							this.$refs.backTop.goTopClick()
							break
					}
				}
			}
		})
	</script>
</html>