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注册组件命名时不能用大写"其实这句话是不对的,但我们很多人开始都觉得是对的, ...
随机推荐
- Adversarial Examples for Semantic Segmentation and Object Detection 阅读笔记
Adversarial Examples for Semantic Segmentation and Object Detection (语义分割和目标检测中的对抗样本) 作者:Cihang Xie, ...
- KendoUi 学习笔记(二) Grid
Kendo.ui.Grid Kendo Ui Grid控件,继承至Widget. 一.构造 allowCopy Boolen|Object (默认:false) 当他设置true, ...
- 预先封装数据的思路.md
预先封装数据的思路.md python3 最近有两位同学开发开发了用程序在线竞猜数字的小游戏,可以通过以下两个网址去玩: bbaa的游戏 http://bbaass.tk/math/ codetige ...
- c++学习过程
作者本人也是一名初学者,我的QQ:2522929921,可以一起交流啊! 希望广大初学者能够一起进步: 1.掌握编程思维真的很重要!!!!***. 2.不能刻意记忆语法规则. 3.在循序渐进的项目实战 ...
- ecside中<c:table>使用
<ec:table action="sjzc/tbWaterproject!list.do" items="objList" var="tbWa ...
- maven 常用备忘录
1.maven 国内的常用中央仓库地址配置: <mirror> <id>alimaven</id> <name>aliyun maven</nam ...
- windows.h详解
参考 http://blog.csdn.net/fengningning/article/details/2306650?locationNum=1&fps=1 windows.h解构 刚开头 ...
- 显示react配置
1. 由于react默认隐藏webpack配置需要手动显示. npm run eject //Are you sure you want to eject? This action is perman ...
- MySQL数据库“十宗罪”【十大经典错误案例】
原文作者:张甦 来源:http://blog.51cto.com/sumongodb 今天就给大家列举 MySQL 数据库中,最经典的十大错误案例,并附有处理问题的解决思路和方法,希望能给刚入行,或数 ...
- oracle 修改服务端字符集编码
进入服务端的sqlplus命令界面 SELECT * FROM V$NLS_PARAMETERS; 可以查看参数的值. 解决字符集编码 NLS_CHARACTERSET 办法: UPDATE PROP ...