mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-03-01 00:23:11 +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 { App } from 'vue';
|
||||||
|
|
||||||
import { permission } from '@/directives/permission';
|
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) {
|
export function setupDirectives(app: App) {
|
||||||
// 权限控制指令(演示)
|
// 权限控制指令(演示)
|
||||||
app.directive('permission', permission);
|
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