mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-04 13:42:27 +08:00
34
src/directives/copy.ts
Normal file
34
src/directives/copy.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* v-copy
|
||||
* 复制某个值至剪贴板
|
||||
* 接收参数:string类型/Ref<string>类型/Reactive<string>类型
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
interface ElType extends HTMLElement {
|
||||
copyData: string | number;
|
||||
__handleClick__: any;
|
||||
}
|
||||
const copy: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
el.copyData = binding.value;
|
||||
el.addEventListener('click', handleClick);
|
||||
},
|
||||
updated(el: ElType, binding: DirectiveBinding) {
|
||||
el.copyData = binding.value;
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener('click', el.__handleClick__);
|
||||
},
|
||||
};
|
||||
function handleClick(this: any) {
|
||||
const input = document.createElement('input');
|
||||
input.value = this.copyData.toLocaleString();
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('Copy');
|
||||
document.body.removeChild(input);
|
||||
console.log('复制成功', this.copyData);
|
||||
}
|
||||
|
||||
export default copy;
|
||||
31
src/directives/debounce.ts
Normal file
31
src/directives/debounce.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* v-debounce
|
||||
* 按钮防抖指令,可自行扩展至input
|
||||
* 接收参数:function类型
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
__handleClick__: () => any;
|
||||
}
|
||||
const debounce: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
if (typeof binding.value !== "function") {
|
||||
throw "callback must be a function";
|
||||
}
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
el.__handleClick__ = function () {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
binding.value();
|
||||
}, 500);
|
||||
};
|
||||
el.addEventListener("click", el.__handleClick__);
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener("click", el.__handleClick__);
|
||||
}
|
||||
};
|
||||
|
||||
export default debounce;
|
||||
49
src/directives/draggable.ts
Normal file
49
src/directives/draggable.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。
|
||||
|
||||
思路:
|
||||
1、设置需要拖拽的元素为absolute,其父元素为relative。
|
||||
2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
|
||||
3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
|
||||
4、鼠标松开(onmouseup)时完成一次拖拽
|
||||
|
||||
使用:在 Dom 上加上 v-draggable 即可
|
||||
<div class="dialog-model" v-draggable></div>
|
||||
*/
|
||||
import type { Directive } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
parentNode: any;
|
||||
}
|
||||
const draggable: Directive = {
|
||||
mounted: function (el: ElType) {
|
||||
el.style.cursor = "move";
|
||||
el.style.position = "absolute";
|
||||
el.onmousedown = function (e) {
|
||||
let disX = e.pageX - el.offsetLeft;
|
||||
let disY = e.pageY - el.offsetTop;
|
||||
document.onmousemove = function (e) {
|
||||
let x = e.pageX - disX;
|
||||
let y = e.pageY - disY;
|
||||
let maxX = el.parentNode.offsetWidth - el.offsetWidth;
|
||||
let maxY = el.parentNode.offsetHeight - el.offsetHeight;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
} else if (x > maxX) {
|
||||
x = maxX;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
} else if (y > maxY) {
|
||||
y = maxY;
|
||||
}
|
||||
el.style.left = x + "px";
|
||||
el.style.top = y + "px";
|
||||
};
|
||||
document.onmouseup = function () {
|
||||
document.onmousemove = document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
export default draggable;
|
||||
49
src/directives/longpress.ts
Normal file
49
src/directives/longpress.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* v-longpress
|
||||
* 长按指令,长按时触发事件
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
|
||||
const directive: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
if (typeof binding.value !== "function") {
|
||||
throw "callback must be a function";
|
||||
}
|
||||
// 定义变量
|
||||
let pressTimer: any = null;
|
||||
// 创建计时器( 2秒后执行函数 )
|
||||
const start = (e: any) => {
|
||||
if (e.button) {
|
||||
if (e.type === "click" && e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (pressTimer === null) {
|
||||
pressTimer = setTimeout(() => {
|
||||
handler(e);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
// 取消计时器
|
||||
const cancel = () => {
|
||||
if (pressTimer !== null) {
|
||||
clearTimeout(pressTimer);
|
||||
pressTimer = null;
|
||||
}
|
||||
};
|
||||
// 运行函数
|
||||
const handler = (e: MouseEvent | TouchEvent) => {
|
||||
binding.value(e);
|
||||
};
|
||||
// 添加事件监听器
|
||||
el.addEventListener("mousedown", start);
|
||||
el.addEventListener("touchstart", start);
|
||||
// 取消计时器
|
||||
el.addEventListener("click", cancel);
|
||||
el.addEventListener("mouseout", cancel);
|
||||
el.addEventListener("touchend", cancel);
|
||||
el.addEventListener("touchcancel", cancel);
|
||||
}
|
||||
};
|
||||
|
||||
export default directive;
|
||||
41
src/directives/throttle.ts
Normal file
41
src/directives/throttle.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。
|
||||
|
||||
思路:
|
||||
1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮
|
||||
2、将需要触发的方法绑定在指令上
|
||||
|
||||
使用:给 Dom 加上 v-throttle 及回调函数即可
|
||||
<button v-throttle="debounceClick">节流提交</button>
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
__handleClick__: () => any;
|
||||
disabled: boolean;
|
||||
}
|
||||
const throttle: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
if (typeof binding.value !== "function") {
|
||||
throw "callback must be a function";
|
||||
}
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
el.__handleClick__ = function () {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
if (!el.disabled) {
|
||||
el.disabled = true;
|
||||
binding.value();
|
||||
timer = setTimeout(() => {
|
||||
el.disabled = false;
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
el.addEventListener("click", el.__handleClick__);
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener("click", el.__handleClick__);
|
||||
}
|
||||
};
|
||||
|
||||
export default throttle;
|
||||
@@ -1,6 +1,10 @@
|
||||
import { App } from 'vue';
|
||||
|
||||
import { permission } from '@/directives/permission';
|
||||
import copy from '@/directives/copy';
|
||||
import debounce from '@/directives/debounce';
|
||||
import throttle from '@/directives/throttle';
|
||||
import draggable from '@/directives/draggable';
|
||||
|
||||
/**
|
||||
* 注册全局自定义指令
|
||||
@@ -9,4 +13,12 @@ import { permission } from '@/directives/permission';
|
||||
export function setupDirectives(app: App) {
|
||||
// 权限控制指令(演示)
|
||||
app.directive('permission', permission);
|
||||
// 复制指令
|
||||
app.directive('copy', copy);
|
||||
// 防抖指令
|
||||
app.directive('debounce', debounce);
|
||||
// 节流指令
|
||||
app.directive('throttle', throttle);
|
||||
// 拖拽指令
|
||||
app.directive('draggable', draggable);
|
||||
}
|
||||
|
||||
31
src/router/modules/test.ts
Normal file
31
src/router/modules/test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { Layout } from '@/router/constant';
|
||||
import { ProjectOutlined } from '@vicons/antd';
|
||||
import { renderIcon } from '@/utils/index';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/test',
|
||||
name: 'test',
|
||||
component: Layout,
|
||||
meta: {
|
||||
sort: 12,
|
||||
isRoot: true,
|
||||
activeMenu: 'test_index',
|
||||
icon: renderIcon(ProjectOutlined),
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: `test_index`,
|
||||
meta: {
|
||||
title: '指令测试',
|
||||
activeMenu: 'test_index',
|
||||
},
|
||||
component: () => import('@/views/test/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
54
src/views/test/index.vue
Normal file
54
src/views/test/index.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="card content-box">
|
||||
<n-card>
|
||||
<n-input placeholder="请输入内容" v-model:value="data" style="width: 500px"> </n-input>
|
||||
</n-card>
|
||||
<n-card>
|
||||
<n-button v-copy="data" type="primary" @click="a">复制</n-button>
|
||||
</n-card>
|
||||
<n-card>
|
||||
<n-button type="primary" v-debounce="b">防抖按钮</n-button>
|
||||
</n-card>
|
||||
<n-card>
|
||||
<n-button type="primary" v-throttle="c">节流按钮</n-button>
|
||||
</n-card>
|
||||
<div class="box" v-draggable> </div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="copyDirect">
|
||||
import { ref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
const data = ref<string>();
|
||||
const message = useMessage();
|
||||
const a = () => {
|
||||
message.success('复制成功:' + data.value);
|
||||
};
|
||||
const b = () => {
|
||||
message.success('防抖');
|
||||
console.log(data.value);
|
||||
};
|
||||
const c = () => {
|
||||
message.success('节流');
|
||||
console.log(data.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
body {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: #ccc;
|
||||
position: relative;
|
||||
}
|
||||
.content-box {
|
||||
height: 100vh;
|
||||
.box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: red;
|
||||
position: absolute;
|
||||
z-index: 10000000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user