Vue Affix组件
在vue的项目中经常用到固钉,但是 element-ui 上并没有提供这样的组件可供使用,ant-design-vue 有提供,总不能为了这一个组件再去引入一个组件库吧
下面是一个封装好的 affix 组件,可以放到项目中直接使用
Affix.vue
<template>
<div class="affix-placeholder" :style="wrapStyle">
<div :class="{'affix': affixed}" :style="styles">
<slot></slot>
</div>
</div>
</template>
<script>
/**
* @file Affix.vue
* @author v_shenjieping@baidu.com
* @date 2018-12-11 10:09:50
*/
export default {
props: {
offset: {
type: Number,
default: 0
},
onAffix: {
type: Function,
default() {}
},
boundary: {
type: String,
default: ''
}
},
data() {
return {
affixed: false,
styles: {},
affixedClientHeight: 0,
wrapStyle: {}
};
},
methods: {
getScroll(w, top) {
let ret = w[`page${(top ? 'Y' : 'X')}Offset`];
const method = `scroll${top ? 'Top' : 'Left'}`;
if (typeof ret !== 'number') {
const d = w.document;
// ie6,7,8 standard mode
ret = d.documentElement[method];
if (typeof ret !== 'number') {
// quirks mode
ret = d.body[method];
}
}
return ret;
},
getOffset(element) {
const rect = element.getBoundingClientRect();
const body = document.body;
const clientTop = element.clientTop || body.clientTop || 0;
const clientLeft = element.clientLeft || body.clientLeft || 0;
// const clientHeight = element.clientHeight || 0;
const scrollTop = this.getScroll(window, true);
const scrollLeft = this.getScroll(window);
return {
top: rect.bottom + scrollTop - clientTop - this.affixedClientHeight,
left: rect.left + scrollLeft - clientLeft
};
},
handleScroll() {
const scrollTop = this.getScroll(window, true) + this.offsets; // handle setting offset
const elementOffset = this.getOffset(this.$el);
if (!this.affixed && scrollTop > elementOffset.top) {
this.affixed = true;
this.styles = {
top: `${this.offsets}px`,
left: `${elementOffset.left}px`,
width: `${this.$el.offsetWidth}px`
};
this.onAffix(this.affixed);
}
// if setting boundary
if (this.boundary && scrollTop > elementOffset.top) {
const el = document.getElementById(this.boundary.slice(1));
if (el) {
const boundaryOffset = this.getOffset(el);
if ((scrollTop + this.offsets) > boundaryOffset.top) {
const top = scrollTop - boundaryOffset.top;
this.styles.top = `-${top}px`;
}
}
}
if (this.affixed && scrollTop < elementOffset.top) {
this.affixed = false;
this.styles = {};
this.onAffix(this.affixed);
}
if (this.affixed && this.boundary) {
const el = document.getElementById(this.boundary.slice(1));
if (el) {
const boundaryOffset = this.getOffset(el);
if ((scrollTop + this.offsets) <= boundaryOffset.top) {
this.styles.top = 0;
}
}
}
}
},
computed: {
offsets() {
if (this.boundary) {
return 0;
}
return this.offset;
}
},
mounted() {
this.affixedClientHeight = this.$el.children[0].clientHeight;
this.wrapStyle = {height: `${this.affixedClientHeight}px`};
window.addEventListener('scroll', this.handleScroll);
window.addEventListener('resize', this.handleScroll);
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll);
window.removeEventListener('resize', this.handleScroll);
}
};
</script>
<style lang="sass">
.affix
position: fixed
</style>
使用方法也是非常简单
test.vue
<template>
<div class="test">
<affix>
<div>这是一个固钉组件</div>
</affix>
<affix :offset="40">
<div>这是一个固钉组件</div>
</affix>
</div>
</template> <script>
import Affix from '@/components/Affix';
export default {
name: 'test',
components: {
Affix
}
};
</script>
API
参数 | 说明 | 类型 | 默认值 |
offset | 距离窗口顶部达到指定偏移量后触发 | Number | 0 |
boundary | 设置 Affix 的活动范围,值为affix上级元素的id(可以是父元素,也可以是父元素的父元素...) | String(#parent) | |
on-affix | 固定状态改变时触发的回调函数 | Function(affixed) | 无 |
Vue Affix组件的更多相关文章
- vue.js组件化开发实践
前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...
- 如何理解vue.js组件的作用域是独立的
vue.js组件的作用域是独立,可以从以下三个方面理解: 1.父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据:2.子组件模板在子组件作用域内编译,子组件模板的数据用子组件内da ...
- Vue 子组件向父组件传参
直接上代码 <body> <div id="counter-event-example"> <p>{{ total }}</p> & ...
- VUE.JS组件化
VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...
- Vue动态组件
前面的话 让多个组件使用同一个挂载点,并动态切换,这就是动态组件.本文将详细介绍Vue动态组件 概述 通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动 ...
- vue中组件的四种方法总结
希望对大家有用 全局组件的第一种写法 html: <div id = "app"> <show></show></div> js: ...
- 如何抽象一个 Vue 公共组件
之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...
- vue的组件和生命周期
Vue里组件的通信 通信:传参.控制.数据共享(A操控B做一个事件) 模式:父子组件间.非父子组件 父组件可以将一条数据传递给子组件,这条数据可以是动态的,父组件的数据更改的时候,子组件接收的也会变化 ...
- 为什么VUE注册组件命名时不能用大写的?
这段时间一直在弄vue,当然也遇到很多问题,这里就来跟大家分享一些注册自定义模板组件的心得 首先"VUE注册组件命名时不能用大写"其实这句话是不对的,但我们很多人开始都觉得是对的, ...
随机推荐
- Ceph集群更换public_network网络
1.确保ceph集群是连通状态 这里,可以先把机器配置为以前的x.x.x.x的网络,确保ceph集群是可以通的.这里可以执行下面的命令查看是否连通,显示HEALTH_OK则表示连通 2.获取monma ...
- Flutter错误集合
一.Waiting for another flutter command to release the startup lock... 运行flutter命令 flutter upgrade 运行 ...
- Docker环境下的Mysql8 实现主从数据库数据同步方案
本文记录下通过MySQL Replication在Docker环境下,通过多个容器 实现数据库主从配置. MySQL Replication就不多解释了,简单说就是MySQL非常出色的一个功能,该功能 ...
- 移动端弹出层加遮罩后禁止body滑动
//实现滚动条无法滚动 var mo=function(e){e.preventDefault();}; /***禁止滑动***/ function stop(){ document.body.sty ...
- MNIST机器学习入门
"python: 3.5" # -*- coding: utf-8 -*-"""Created on Tue Oct 16 15:29:38 2018 ...
- Windows MySQL测试数据库employees的导入
一: 首先下载employees测试数据库 https://launchpad.net/test-db/ 二:用文本编辑器打开其中的employees.sql文件,将第38行的set storage_ ...
- GDB程序调试
GDB使用流程 1.编译生成可执行文件: gcc -g tst.c -o tst2.启动GDB gdb tst3. 在main 函数处设置断点 break main4. 运行程序 run GDB 命令 ...
- HTTP Status 500 - Error instantiating servlet class cn.it.bd.S011
HTTP Status 500 - Error instantiating servlet class cn.it.bd.S011 出现此报错的很大可能是因为 <servlet-class> ...
- Windows下网页连接VNC操作手册
所需软件:tigervnc noVnc(https://github.com/novnc/noVNC) websockify(https://github.com/novnc/websockify) ...
- linux 安装 ftp 实现文件共享
转载:http://blog.sina.com.cn/s/blog_165e646820102xe1q.html 参考:1.http://www.cnblogs.com/mrcln/p/6179673 ...