vue2企业级项目(六)
自定义指令
-
创建
src/directive/index.js
const directives = require.context("./modules", true, /\.js$/);export default {install: (Vue) => {directives.keys().forEach((key) => {let directive = directives(key).default;let name = key.replace(/^\.\/(.*)\.\w+$/, "$1");directive && Vue.directive(name, directive);});}, };
-
main.js
注入使用import directives from "./directive";...Vue.use(directives);
-
创建
src/directive/modules
目录
1、v-loading
element-ui
有,就不需要
2、v-draggable
创建src/directive/draggable.js
import { checkDataType } from "@/utils/utils";
let recoverStyle = null;export default {update(el, binding) {let config = binding.value;let visible = false;let target = ".el-dialog__header";let control = ".el-dialog";if (checkDataType(config, "object")) {visible = config.visible;target = config.target;control = config.control;} else {visible = config;}const dialogHeaderEl = el.querySelector(target);const dragDom = el.querySelector(control);dialogHeaderEl.style.cursor = "move";function readStyle(dom, attr) {if (document.body.currentStyle) return dom.currentStyle[attr];return getComputedStyle(dom, false)[attr];}if (visible) {recoverStyle = {left: readStyle(dragDom, "left"),top: readStyle(dragDom, "top"),margin: readStyle(dragDom, "margin"),};dialogHeaderEl.onmousedown = function(e) {// 获取鼠标相对当前元素内部位置const disX = e.clientX - dragDom.offsetLeft;const disY = e.clientY - dragDom.offsetTop;// 获取当前窗口视图大小const screenWidth = document.body.clientWidth;const screenHeight = document.documentElement.clientHeight;// 获取当前元素大小const dragDomWidth = dragDom.offsetWidth;const dragDomheight = dragDom.offsetHeight;// 计算获取最大偏移量const maxLeft = screenWidth - dragDomWidth;const maxTop = screenHeight - dragDomheight;document.onmousemove = function(e) {let left = e.clientX - disX;let top = e.clientY - disY;// 碰撞判断if (left <= 0) left = 0;if (left >= maxLeft) left = maxLeft;if (top <= 0) top = 0;if (top >= maxTop) top = maxTop;left = ((left * 100) / screenWidth).toFixed(2) + "%";top = ((top * 100) / screenHeight).toFixed(2) + "%";dragDom.style.left = left;dragDom.style.top = top;dragDom.style.margin = 0;};document.onmouseup = function() {document.onmousemove = null;document.onmouseup = null;};};} else {// 还原初始化的样式dragDom.style.left = recoverStyle.left;dragDom.style.top = recoverStyle.top;dragDom.style.margin = recoverStyle.margin;dialogHeaderEl.onmousedown = null;recoverStyle = null;}},
};
3、v-click-outside
创建src/directive/click-outside.js
export default {bind(el, binding) {// 点击事件回调函数const onClickOutside = (event) => {if (!(el === event.target || el.contains(event.target))) {binding.value(event);}};// 将回调函数绑定到元素上el._clickOutsideCallback = onClickOutside;// 添加点击事件监听器document.addEventListener("click", onClickOutside);},unbind(el) {// 移除点击事件监听器document.removeEventListener("click", el._clickOutsideCallback);delete el._clickOutsideCallback;},
};
4、v-ripple
(简单的)
创建src/directive/ripple.js
function createRipple(el, radius, color, disX, disY) {new Promise((resolve) => {const rippleDom = document.createElement("span");rippleDom.className = "ripple";rippleDom.setAttribute("style",`display: block;position: absolute;border-radius: 50%;transform: translate(-50%, -50%) scale(0);transition: 0.5s;background-color: ${color || "rgba(0, 0, 0, 0.6)"};top: ${disY}px;left: ${disX}px;width: ${radius * 3}px;height: ${radius * 3}px;animation: ripple-animation 0.5s linear;`,);el.appendChild(rippleDom);let timer = setTimeout(() => {el.removeChild(rippleDom);resolve(timer);}, 520);}).then((timer) => {clearTimeout(timer);});
}function rippleShow(e) {const targetDom = e.target;const radius =targetDom.offsetHeight > targetDom.offsetWidth? targetDom.offsetHeight: targetDom.offsetWidth;const disX = e.clientX - targetDom.offsetLeft;const disY = e.clientY - targetDom.offsetTop;createRipple(targetDom, radius, e?._ripple, disX, disY);
}export default {bind(el, binding) {el._ripple = binding.value;el.style.position = "relative";el.style.overflow = "hidden";el.style.userSelect = "none";el.addEventListener("mousedown", rippleShow);},unbind(el) {el._ripple = null;el.removeEventListener("mousedown", rippleShow);},
};
创建src/styles/animation.less
,并在scr/styles/index.less
内引入
// ripple动画
@keyframes ripple-animation {to {transform: translate(-50%, -50%) scale(1);opacity: 0;}
}
5、v-intersect
交叉观察者
创建src/directive/intersect.js
export default {bind(el, binding) {let info = null;let callback = null;if (typeof binding.value === "object") {info = binding.value?.info;callback = binding.value?.callback;} else {callback = binding.value;}const observer = new IntersectionObserver((entries) => {entries.forEach((entry) => {if (entry.isIntersecting) {callback && callback(info);}});},{ root: el.parentElement },);observer.observe(el);},
};
6、v-scroll
滚动监听
创建src/directive/scroll.js
export default {bind(el, binding) {el.onscroll = function() {binding.value({x: el.scrollLeft,y: el.scrollTop,});};},unbind(el) {el.onscroll = null;},
};
7、v-scroll-to
滚动设置
创建src/directive/scroll-to.js
export default {update(el, binding) {let x = binding.modifiers?.x || false;if (binding.value && binding.value === binding.oldValue) return;if (typeof binding.value === "number") {x ? (el.scrollLeft = binding.value) : (el.scrollTop = binding.value);} else if (typeof binding.value === "string") {let targetDom = document.querySelector(binding.value);if (x) {let border = getComputedStyle(el, false)["borderLeftWidth"];let padding = getComputedStyle(el, false)["paddingLeft"];border = border.replace("px", "");padding = padding.replace("px", "");el.scrollLeft = targetDom.offsetLeft - el.offsetLeft - border - padding;} else {let border = getComputedStyle(el, false)["borderTopWidth"];let padding = getComputedStyle(el, false)["paddingTop"];border = border.replace("px", "");padding = padding.replace("px", "");el.scrollTop = targetDom.offsetTop - el.offsetTop - border - padding;}}},
};
8、v-auto-scroll
自动滚动
创建src/directive/scroll-auto.js
function active(el, scroll, step, max, x) {window.requestAnimationFrame(() => {x ? (el.scrollLeft = scroll) : (el.scrollTop = scroll);scroll += step;if (scroll >= max) scroll = 0 + step;active(el, scroll, step, max, x);});
}export default {inserted(el, binding) {const x = binding.modifiers?.x || false;let step = 0;let scroll = 0;if (typeof binding.value === "object") {step = binding.value?.step || 5;scroll = binding.value?.begin || 0;} else {step = binding.value || 5;}const scrollMax = x ? el.scrollWidth : el.scrollHeight;el._children = [].slice.call(el.children);el._children.forEach((child) => {el.appendChild(child.cloneNode(true));});active(el, scroll, step, scrollMax, x);},unbind(el) {el.innerHtml = "";let children = [].slice.call(el.children);children.forEach((child) => {el.removeChild(child);});el._children.forEach((child) => {el.appendChild(child.cloneNode(true));});},
};