@Author:Outman
@Date:2023-03-08

JS自定义指令 —— 无限滚动(改写el-table-infinite-scroll)

自定义指令实现

// directives/index.js
/*** 此处引入element官方的infinite-scroll,'./infinite-scroll/index'此处的index并非为当前的index.js文件* 整体目录结构为:* · directives*   · index.js (当前文件)*   · infinite-scroll (element官方的infinite-scroll,本文文末已提供)*     · index.js*     · src*       · main.js*/
import InfiniteScroll from "./infinite-scroll/index";
export default {// 全局挂载install(Vue) {/*** @description: 无限滚动* @param scrollClass String 需要添加无限滚动的节点class* scrollClass默认为".el-table__body-wrapper",可自行修改为所需绑定无限滚动节点的class* 例如:element-table中若要实现无限滚动,则需要绑定class为el-table__body-wrapper* 无限滚动相关配置项(elementUI相关配置):* infinite-scroll-disabled      是否禁用                                          boolean    -   false* infinite-scroll-delay         节流时延,单位为ms                                  number   - 200* infinite-scroll-distance       触发加载的距离阈值,单位为px                          number   -   0* infinite-scroll-immediate   是否立即执行加载方法,以防初始状态下内容无法撑满容器    boolean  - true*/const elScope = 'InfiniteScroll'; // scope nameVue.directive('outman-infinite-scroll', {inserted(el, binding, vnode, oldVnode){const value = binding.value || {};const { scrollClass = ".el-table__body-wrapper" } = value;// 获取 hui table 中的滚动层  const scrollElement = el.querySelector(scrollClass);if(!scrollElement)throw '找不到指定的容器!'// 设置自动滚动scrollElement.style.overflowY = 'auto';// dom 渲染后setTimeout(()=>{// 高度默认值赋值if (!el.style.height) {scrollElement.style.height = '300px';}// 获取配置参数asyncElOptions(vnode, el, scrollElement);// 绑定 infinite-scrollInfiniteScroll.inserted(scrollElement, binding, vnode);// 将子集的引用放入 el 上,用于 unbind 中销毁事件el[elScope] = scrollElement[elScope];}, 0)},componentUpdated(el, binding, vnode){const value = binding.value || {};const { scrollClass = ".h-table-body" } = value;// 更新配置参数asyncElOptions(vnode, el, el.querySelector(scrollClass));},unbind(el){InfiniteScroll.unbind(el)}})/*** 同步 el-infinite-scroll 的配置项* @param sourceVNode* @param sourceElem* @param targetElem*/function asyncElOptions(sourceVNode, sourceElem, targetElem) {let value;['disabled', 'delay', 'immediate'].forEach((name) => {name = 'infinite-scroll-' + name;value = sourceElem.getAttribute(name);if (value !== null) {targetElem.setAttribute(name, value);} else {targetElem.removeAttribute(name);}});// fix: windows/chrome 的 scrollTop + clientHeight 与 scrollHeight 不一致的 BUGconst name = 'infinite-scroll-distance';value = sourceElem.getAttribute(name);targetElem.setAttribute(name, value < 1 ? 1 : value);}}
};

自定义指令引入

// 引入app.js
import directives from '../src/directives/index';
Vue.use(directives);

自定义指令应用

<!-- 应用 -->
<template><el-table height="200" :columns="columns" :data="data" v-outman-infinite-scroll="handleInfinite" :infinite-scroll-delay="200":infinite-scroll-disabled="busy" :infinite-scroll-distance="10"></el-table>
</template>
<script>
export default {data() {return {busy: false,columns: [{title: '姓名',key: 'name'},{title: '年龄',key: 'age'},{title: '地址',key: 'address'}],data: [{name: '王小明',age: 18,address: '北京市朝阳区芍药居'},{name: '张小刚',age: 25,address: '北京市海淀区西二旗'},{name: '李小红',age: 30,address: '上海市浦东新区世纪大道'},{name: '周小伟',age: 26,address: '深圳市南山区深南大道'},{name: '王小明',age: 18,address: '北京市朝阳区芍药居'},{name: '张小刚',age: 25,address: '北京市海淀区西二旗'}]};},methods: {handleInfinite() {console.log('我在无限滚动了!');}}
};
</script>

el-infinite-scroll 源码(上述infinite-scroll目录内的文件)

// infinite/index.js
import InfiniteScroll from './src/main.js';/* istanbul ignore next */
InfiniteScroll.install = function(Vue) {Vue.directive(InfiniteScroll.name, InfiniteScroll);
};export default InfiniteScroll;// infinite/src/main.js
import throttle from 'throttle-debounce/debounce';
import {isHtmlElement,isFunction,isUndefined,isDefined
} from 'element-ui/src/utils/types';
import {getScrollContainer
} from 'element-ui/src/utils/dom';const getStyleComputedProperty = (element, property) => {if (element === window) {element = document.documentElement;}if (element.nodeType !== 1) {return [];}// NOTE: 1 DOM access hereconst css = window.getComputedStyle(element, null);return property ? css[property] : css;
};const entries = (obj) => {return Object.keys(obj || {}).map(key => ([key, obj[key]]));
};const getPositionSize = (el, prop) => {return el === window || el === document? document.documentElement[prop]: el[prop];
};const getOffsetHeight = el => {return getPositionSize(el, 'offsetHeight');
};const getClientHeight = el => {return getPositionSize(el, 'clientHeight');
};const scope = 'ElInfiniteScroll';
const attributes = {delay: {type: Number,default: 200},distance: {type: Number,default: 0},disabled: {type: Boolean,default: false},immediate: {type: Boolean,default: true}
};const getScrollOptions = (el, vm) => {if (!isHtmlElement(el)) return {};return entries(attributes).reduce((map, [key, option]) => {const { type, default: defaultValue } = option;let value = el.getAttribute(`infinite-scroll-${key}`);value = isUndefined(vm[value]) ? value : vm[value];switch (type) {case Number:value = Number(value);value = Number.isNaN(value) ? defaultValue : value;break;case Boolean:value = isDefined(value) ? value === 'false' ? false : Boolean(value) : defaultValue;break;default:value = type(value);}map[key] = value;return map;}, {});
};const getElementTop = el => el.getBoundingClientRect().top;const handleScroll = function(cb) {const { el, vm, container, observer } = this[scope];const { distance, disabled } = getScrollOptions(el, vm);if (disabled) return;const containerInfo = container.getBoundingClientRect();if (!containerInfo.width && !containerInfo.height) return;let shouldTrigger = false;if (container === el) {// be aware of difference between clientHeight & offsetHeight & window.getComputedStyle().heightconst scrollBottom = container.scrollTop + getClientHeight(container);shouldTrigger = container.scrollHeight - scrollBottom <= distance;} else {const heightBelowTop = getOffsetHeight(el) + getElementTop(el) - getElementTop(container);const offsetHeight = getOffsetHeight(container);const borderBottom = Number.parseFloat(getStyleComputedProperty(container, 'borderBottomWidth'));shouldTrigger = heightBelowTop - offsetHeight + borderBottom <= distance;}if (shouldTrigger && isFunction(cb)) {cb.call(vm);} else if (observer) {observer.disconnect();this[scope].observer = null;}};export default {name: 'InfiniteScroll',inserted(el, binding, vnode) {const cb = binding.value;const vm = vnode.context;// only include vertical scrollconst container = getScrollContainer(el, true);const { delay, immediate } = getScrollOptions(el, vm);const onScroll = throttle(delay, handleScroll.bind(el, cb));el[scope] = { el, vm, container, onScroll };if (container) {container.addEventListener('scroll', onScroll);if (immediate) {const observer = el[scope].observer = new MutationObserver(onScroll);observer.observe(container, { childList: true, subtree: true });onScroll();}}},unbind(el) {const { container, onScroll } = el[scope];if (container) {container.removeEventListener('scroll', onScroll);}}
};

【前端技巧】JS自定义指令 —— 无限滚动(改写el-table-infinite-scroll)相关推荐

  1. js:Vue.js自定义指令实现scroll下滑滚动翻页

    Vue.js自定义指令实现scroll下滑滚动翻页 核心代码 import Vue from 'vue'// v-scroll Vue.directive('scroll', {bind(el, bi ...

  2. Vue.js自定义指令的用法与实例

    市面上大多数关于Vue.js自定义指令的文章都在讲语法,很少讲实际的应用场景和用例,以致于即便明白了怎么写,也不知道怎么用.本文不讲语法,就讲自定义指令的用法. 自定义指令是用来操作DOM的.尽管Vu ...

  3. JS 自定义实现数字滚动处理

    一.浏览器端js自定义实现数字滚动 使用示例: <!DOCTYPE html> <html lang="en"><head><meta c ...

  4. Vue踩坑之旅(四)—— 自定义指令实现滚动加载

    这几天在做商城首页的商品列表,商品卡片的数量很多,如果一次性加载那么多,加载较慢,而且用户体验不好.所以使用鼠标无限滚动加载效果更好. 实现滚动加载的方式有很多,有现成的组件 InfiniteScro ...

  5. (13)Vue.js 自定义指令

    一.Vue.js之定义指令介绍 前面我们学习了一些Vue.js给我们提供的指令,那么我们知道指令就是帮助我们去简化DOM操作的,相当于对基础 DOM操作的一种封装.那么我们仅仅使用这些Vue.js提供 ...

  6. angular.js自定义指令

    angular.js最为强大的地方在于可以通过自定义指令来扩展html元素,这种思路与JSP的taglib类似,但在实现细节上更为自由,并且自定义指令也可以提供表单元素交互.数据绑定.事件处理功能. ...

  7. Vue.js 自定义指令

    简介 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令.注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件.然而,有的情况下,你仍然需要对普通 D ...

  8. 前端技巧-JS元编程ES6 symbol公开符号

    元编程就是指以操作目标为程序本身的行为特性的编程,而在ES6中增加了类型symbol,除了自定义的符号之外,还预定义了其他的一些内置符号,可以被称为内置符号.下面就来给大家介绍一下这些内置符号. 1. ...

  9. 无限滚动重置服务器,简单无限滚动的实现

    在使用elementUI组件库的时候,用到了无限滚动这个功能.我没有看源码,直接在网上学习了下实现的思路,然后自己手动编码以下.在此总结下. 假设页面上有一个盒子容器,容器内有一些子元素.容器的高度是 ...

最新文章

  1. HTTP协议解析之Cookie
  2. 秦州:西瓜书 + 南瓜书 吃瓜系列 10. 集成学习(下)
  3. 浅谈强化学习的方法及学习路线
  4. oracle 数组的用法,oracle存储过程中数组的使用
  5. 2041. 干草堆(前缀和差分)
  6. android mtk平台,android mtk平台默认输入法
  7. 去除内联元素之间的间距
  8. 编写可靠shell脚本的8个建议
  9. 计算机网络基础问题总结
  10. 人工智能十大算法_【读书】人工智能和大数据:新智能的诞生/人工智能科学与技术丛书...
  11. 2013年最新十大xp系统下载排行榜-无极系统下载站
  12. Linux网络编程必学的TCP/IP协议——图解分层(通俗易懂)【建议新手收藏】
  13. 【C语言典例】——day8:猜名次
  14. 《数学之美》吴军-读书笔记
  15. iPhoneX、iPhoneXS、iPhoneXR、iPhoneXSMax屏幕适配尺寸@media
  16. 怎么把荣耀8x的手机备忘录导到电脑里?
  17. 护卫神备份mysql_护卫神好备份系统数据库怎么备份?
  18. dba招生_深圳DBA项目招生简介
  19. android 功能模块之通讯模块四
  20. 中关村被骗记(维权全过程)

热门文章

  1. 数据建模语言IDEF、IDEF1、IDEF1X
  2. day5 RecyclerView、多布局、万能适配器
  3. 键盘输入圆的半径,计算并输出圆的周长和面积
  4. Linux使用rmp安装tree
  5. rmp安装gitlab10.1.0
  6. 西南科技大学计算机网络,西南科技大学计算机网络 实验一
  7. 台式计算机折旧年限,电脑折旧年限是多少年(2021年固定资产折旧年限最新规定)...
  8. docker 安装 zulip
  9. JAVA里面的堆栈区别
  10. 泛型通配符之PECS