在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组件的更多相关文章

  1. vue.js组件化开发实践

    前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...

  2. 如何理解vue.js组件的作用域是独立的

    vue.js组件的作用域是独立,可以从以下三个方面理解: 1.父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据:2.子组件模板在子组件作用域内编译,子组件模板的数据用子组件内da ...

  3. Vue 子组件向父组件传参

    直接上代码 <body> <div id="counter-event-example"> <p>{{ total }}</p> & ...

  4. VUE.JS组件化

    VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...

  5. Vue动态组件

    前面的话 让多个组件使用同一个挂载点,并动态切换,这就是动态组件.本文将详细介绍Vue动态组件 概述 通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动 ...

  6. vue中组件的四种方法总结

    希望对大家有用 全局组件的第一种写法 html: <div id = "app"> <show></show></div> js: ...

  7. 如何抽象一个 Vue 公共组件

    之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...

  8. vue的组件和生命周期

    Vue里组件的通信 通信:传参.控制.数据共享(A操控B做一个事件) 模式:父子组件间.非父子组件 父组件可以将一条数据传递给子组件,这条数据可以是动态的,父组件的数据更改的时候,子组件接收的也会变化 ...

  9. 为什么VUE注册组件命名时不能用大写的?

    这段时间一直在弄vue,当然也遇到很多问题,这里就来跟大家分享一些注册自定义模板组件的心得 首先"VUE注册组件命名时不能用大写"其实这句话是不对的,但我们很多人开始都觉得是对的, ...

随机推荐

  1. Ceph集群更换public_network网络

    1.确保ceph集群是连通状态 这里,可以先把机器配置为以前的x.x.x.x的网络,确保ceph集群是可以通的.这里可以执行下面的命令查看是否连通,显示HEALTH_OK则表示连通 2.获取monma ...

  2. Flutter错误集合

    一.Waiting for another flutter command to release the startup lock... 运行flutter命令 flutter upgrade 运行 ...

  3. Docker环境下的Mysql8 实现主从数据库数据同步方案

    本文记录下通过MySQL Replication在Docker环境下,通过多个容器 实现数据库主从配置. MySQL Replication就不多解释了,简单说就是MySQL非常出色的一个功能,该功能 ...

  4. 移动端弹出层加遮罩后禁止body滑动

    //实现滚动条无法滚动 var mo=function(e){e.preventDefault();}; /***禁止滑动***/ function stop(){ document.body.sty ...

  5. MNIST机器学习入门

    "python: 3.5" # -*- coding: utf-8 -*-"""Created on Tue Oct 16 15:29:38 2018 ...

  6. Windows MySQL测试数据库employees的导入

    一: 首先下载employees测试数据库 https://launchpad.net/test-db/ 二:用文本编辑器打开其中的employees.sql文件,将第38行的set storage_ ...

  7. GDB程序调试

    GDB使用流程 1.编译生成可执行文件: gcc -g tst.c -o tst2.启动GDB gdb tst3. 在main 函数处设置断点 break main4. 运行程序 run GDB 命令 ...

  8. HTTP Status 500 - Error instantiating servlet class cn.it.bd.S011

    HTTP Status 500 - Error instantiating servlet class cn.it.bd.S011 出现此报错的很大可能是因为 <servlet-class> ...

  9. Windows下网页连接VNC操作手册

    所需软件:tigervnc noVnc(https://github.com/novnc/noVNC) websockify(https://github.com/novnc/websockify) ...

  10. linux 安装 ftp 实现文件共享

    转载:http://blog.sina.com.cn/s/blog_165e646820102xe1q.html 参考:1.http://www.cnblogs.com/mrcln/p/6179673 ...