在vue的項目中常常用到固釘,可是 element-ui 上並無提供這樣的組件可供使用,ant-design-vue 有提供,總不能爲了這一個組件再去引入一個組件庫吧vue
下面是一個封裝好的 affix 組件,能夠放到項目中直接使用git
Affix.vuegithub
<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>
使用方法也是很是簡單element-ui
test.vuesass
<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) | 無 |