-
安装指令:
pnpm i wdy_custom_hooks
-
使用方式,全局注册(在项目 main.ts 或者 main.js 中引入):
import { createApp } from "vue"; import App from "./app.vue"; // 引入自定义指令 import { useResize, useFocus } from "wdy_custom_hooks"; const app = createApp(App); // 全局注册指令 app.use(useResize); app.use(useFocus); app.mount("#app");
-
目前可供使用的指令以及使用 Demo:
1. v-focus:自动焦点
2. v-resize:监听元素大小的变化
3. v-copy:复制文本
4. v-scrollLoad:滚动加载更多
5. v-imgLazy:图片懒加载
6. v-longPress:绑定长按事件
7. v-waterMarker:页面水印
8. v-outsideClick:点击元素外部事件
9. v-debounce:防抖指令
10. v-throttle:节流指令
11. v-permission:权限按钮指令
<template>
<input v-focus />
</template>
<template>
<!-- 基本用法,默认200ms触发一次 -->
<div v-resize="resizeCallback"></div>
<!-- 支持自定义防抖时间 -->
<div v-resize:300="resizeCallback"></div>
</template>
<script setup lang="ts">
// 元素大小的变化回调函数
const resizeCallback = (e) => {
console.log("回调触发了:" + e);
};
</script>
<template>
<button v-copy="copyConfig">点击复制</button>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { ElMessage } from "element-plus";
const copyConfig = ref({
text: "Hello,World!", // 要复制的文本
// 自定义复制成功的回调,可选,默认console.log("复制成功")
success: () => {
ElMessage.success("复制成功");
},
// 自定义复制失败的回调,可选,默认console.error("复制失败")
error: (err: any) => {
ElMessage.error("失败:" + err);
},
});
</script>
<template>
<div style="height: 100vh; overflow: auto" v-scrollLoad="scrollConfig">
<ul>
<li
v-for="item in items"
:key="item"
style="padding: 30px; font-size: 20px"
>
{{ item }}
</li>
</ul>
<div
v-if="loading"
style="
height: 50px;
display: flex;
justify-content: center;
font-size: 20px;
"
>
<el-icon><Loading /></el-icon>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { Loading } from "@element-plus/icons-vue";
const loading = ref(false);
const items = ref<string[]>([
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
"Item 9",
"Item 10",
]);
// 指令配置项
const scrollConfig = ref({
distance: 100, // 距离底部的距离,可选,默认举例底部100px触发回调
loadMoreFn: loadMore, // 回调函数
});
// 模拟请求,加载更多数据
async function loadMore() {
if (loading.value) return;
if (items.value.length >= 30) return; // 假设数据只有30条
loading.value = true;
console.log("触发了回调");
// 模拟加载更多数据, 每次加载10条数据;
for (let i = 0; i < 10; i++) {
items.value.push("Item " + (items.value.length + 1));
}
loading.value = false;
}
</script>
<template>
<div>
<img v-lazyLoad="imgConfig" alt="Image" />
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const imgConfig = ref({
// 真实图片地址
src: "https://q4.itc.cn/images01/20241017/4cf3fe55a9584eb0b2c111f9e0baabfd.jpeg",
// 占位图地址,可选,没有默认的占位图
placeholderSrc:
"https://img.zcool.cn/community/01efbc5a1e6efda80120908dcb1567.gif",
// 加载失败图地址,可选,没有默认的加载失败图
errorSrc:
"https://gss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/574e9258d109b3de93ad439cc9bf6c81800a4c37.jpg",
});
</script>
<template>
<div>
{{ count }}
<el-button type="primary" v-longPress="longPressConfig"> 长按我 </el-button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const count = ref(1);
const longPressConfig = ref({
callback: () => {
console.log("长按事件触发!");
count.value++;
}, // 长按事件触发的回调函数
time: 2000, // 长按事件触发的时间,可选,默认 2000ms
});
</script>
<template>
<div v-waterMarker="waterMarkerConfig" style="width: 100%; height: 100vh;">
<h1>我的标题</h1>
<p>这是页面内容……</p>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const waterMarkerConfig = ref({
text: "某某档案@123456789@qq.com", // 水印内容
font: "16px Microsoft Yahei", // 字体样式,可选,默认 '16px Microsoft Yahei'
color: "rgba(0, 0, 0, 0.1)", // 字体颜色,可选,默认 'rgba(0, 0, 0, 0.1)'
rotate: -20, // 字体旋转角度,可选, 默认 -20
labelGap: 50, // 水印之间的间距,可选, 默认 50
});
</script>
<template>
<div v-outsideClick="clickOutside" style="position: relative; margin: 30px">
<button @click="visible = true">下拉菜单</button>
<div
v-if="visible"
style="
position: absolute;
top: 30px;
z-index: 99;
background-color: #bfa;
width: 150px;
height: 200px;
padding: 6px 10px;
border: 1px solid #d9d9d9;
"
>
<ul>
<li>菜单项1</li>
<li>菜单项2</li>
<li>菜单项3</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const visible = ref(false);
const clickOutside = () => {
visible.value = false;
};
</script>
<template>
<el-button type="primary" v-debounce:click="debounceConfig"
>防抖测试{{ count }}</el-button
>
</template>
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
const debounceConfig = ref({
callback: () => {
// 点击事件触发的回调函数
console.log("点击了按钮");
count.value++;
},
delay: 500, // 点击事件触发的时间,可选,默认 300ms
});
</script>
<template>
<el-button type="primary" v-debounce:click="debounceConfig"
>节流测试{{ count }}</el-button
>
</template>
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
const throttleConfig = ref({
callback: () => {
// 点击事件触发的回调函数
console.log("点击了按钮");
count.value++;
},
delay: 500, // 点击事件触发的时间,可选,默认 300ms
});
</script>
<template>
<div>
<button v-permission:sys:user:add="permissions">添加用户</button>
<button v-permission:[dynaimcAuth]="permissions">删除角色</button>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
// 模拟用户权限列表,实际项目中可以从 Vuex 或 Pinia或请求 中获取
const permissions = ref(["sys:user:add", "sys:role:add", "sys:role:delete"]);
// 动态按钮权限
const dynaimcAuth = ref("sys:user:delete");
onMounted(() => {
setTimeout(() => {
dynaimcAuth.value = "sys:role:delete"; // 模拟按钮权限变化
permissions.value = ["sys:role:add", "sys:role:delete"]; // 模拟用户权限列表变化
}, 3000);
});