在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. TypeError: format string

    先来看一段Python代码: class Negate: def __init__(self, val): self.val = -val def __repr__(self): return str ...

  2. 策略模式(Strategy Model)

    定义:一个类的行为或算法能在运行时被改变,将一组算法封装成一系列对象,通过这些对象灵活改变系统功能: 实现方式: 首先定义个strategy接口,然后创建一系列对象(strategy objects) ...

  3. vue-cli 项目里屏幕自适应

    很多同学可能在写h5的时候,也会遇到移动端如何控制屏幕自适应问题!在移动端网页开发中,我们可以用手机淘宝的flexible.那么在vue当中,也同样可以用!接下来就介绍下如何在vue-cli配置的项目 ...

  4. JAVA EE------XML

    1.XML定义:在电子计算机中,标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等.它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语 ...

  5. Csrf_token ||| CSRF跨站请求伪造

    # 注: 部分内容参考网上,侵删   CSRF(Cross-site request forgery) 跨站请求伪造,是一种对网站的恶意利用  它会通过伪装成受信任用户的请求来利用受信任的网站来获取一 ...

  6. 神州数码DHCP及DHCP中继配置

    实验要求:掌握DHCP及DHCP中继配置方法 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface g0/5 进入端口 ip a ...

  7. you-get 下载视频

    亲测有效,没在别的平台试,道理是相通的 平台:Windows 10 所需工具: python3,pip3,you-get 步骤流程: 正确安装python3,配置环境变量 (目前使用的是3.6+) 打 ...

  8. CentOS下将php和mysql命令加入到环境变量中-简单

    开发过程中.需要使用到php命令执行程序.但是php命令没有在全局命令中:每次执行都需要加上全路径特别麻烦,把php命令添加到全局变量中,以后每次只用输入php可以了 例: php -v  或 mys ...

  9. 使用nginx反向代理实现多端口映射(未解决)

    问题: 想实现访问在同一个主机上实现多个域名访问, 如用 blog.xxx.com访问博客(使用8000端口), app.xxx.com访问其他应用(使用8080端口): 不同的服务用URL区分,不用 ...

  10. matlab 曲线拟合小记

    在matlab中经常需要对数据进行曲线拟合,如最常见的多项式拟合,一般可以通过cftool调用曲线拟合工具(curve fit tool),通过图形界面可以很方便的进行曲线拟合,但是有些时候也会遇到不 ...