mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	Merge branch 'main' of github.com:pure-admin/vue-pure-admin into gitee
This commit is contained in:
		
						commit
						4e62edc78e
					
				@ -68,6 +68,7 @@ menus:
 | 
			
		||||
  hsguide: Guide
 | 
			
		||||
  hsAble: Able
 | 
			
		||||
  hsMenuTree: Menu Tree
 | 
			
		||||
  hsOptimize: Debounce、Throttle、Copy Directives
 | 
			
		||||
  hsWatermark: Water Mark
 | 
			
		||||
  hsPrint: Print
 | 
			
		||||
  hsDownload: Download
 | 
			
		||||
 | 
			
		||||
@ -68,6 +68,7 @@ menus:
 | 
			
		||||
  hsguide: 引导页
 | 
			
		||||
  hsAble: 功能
 | 
			
		||||
  hsMenuTree: 菜单树结构
 | 
			
		||||
  hsOptimize: 防抖、截流、复制指令
 | 
			
		||||
  hsWatermark: 水印
 | 
			
		||||
  hsPrint: 打印
 | 
			
		||||
  hsDownload: 下载
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,9 @@ export const auth: Directive = {
 | 
			
		||||
    if (value) {
 | 
			
		||||
      !hasAuth(value) && el.parentNode?.removeChild(el);
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("need auths! Like v-auth=\"['btn.add','btn.edit']\"");
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        "[Directive: auth]: need auths! Like v-auth=\"['btn.add','btn.edit']\""
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								src/directives/copy/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/directives/copy/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
import { message } from "@/utils/message";
 | 
			
		||||
import { useEventListener } from "@vueuse/core";
 | 
			
		||||
import { copyTextToClipboard } from "@pureadmin/utils";
 | 
			
		||||
import { Directive, type DirectiveBinding } from "vue";
 | 
			
		||||
 | 
			
		||||
interface CopyEl extends HTMLElement {
 | 
			
		||||
  copyValue: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 文本复制指令(默认双击复制) */
 | 
			
		||||
export const copy: Directive = {
 | 
			
		||||
  mounted(el: CopyEl, binding: DirectiveBinding) {
 | 
			
		||||
    const { value } = binding;
 | 
			
		||||
    if (value) {
 | 
			
		||||
      el.copyValue = value;
 | 
			
		||||
      const arg = binding.arg ?? "dblclick";
 | 
			
		||||
      // Register using addEventListener on mounted, and removeEventListener automatically on unmounted
 | 
			
		||||
      useEventListener(el, arg, () => {
 | 
			
		||||
        const success = copyTextToClipboard(el.copyValue);
 | 
			
		||||
        success
 | 
			
		||||
          ? message("复制成功", { type: "success" })
 | 
			
		||||
          : message("复制失败", { type: "error" });
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        '[Directive: copy]: need value! Like v-copy="modelValue"'
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  updated(el: CopyEl, binding: DirectiveBinding) {
 | 
			
		||||
    el.copyValue = binding.value;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@ -1 +1,3 @@
 | 
			
		||||
export * from "./auth";
 | 
			
		||||
export * from "./copy";
 | 
			
		||||
export * from "./optimize";
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								src/directives/optimize/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/directives/optimize/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
import {
 | 
			
		||||
  isFunction,
 | 
			
		||||
  isObject,
 | 
			
		||||
  isArray,
 | 
			
		||||
  debounce,
 | 
			
		||||
  throttle
 | 
			
		||||
} from "@pureadmin/utils";
 | 
			
		||||
import { useEventListener } from "@vueuse/core";
 | 
			
		||||
import { Directive, type DirectiveBinding } from "vue";
 | 
			
		||||
 | 
			
		||||
/** 防抖(v-optimize或v-optimize:debounce)、节流(v-optimize:throttle)指令 */
 | 
			
		||||
export const optimize: Directive = {
 | 
			
		||||
  mounted(el: HTMLElement, binding: DirectiveBinding) {
 | 
			
		||||
    const { value } = binding;
 | 
			
		||||
    const optimizeType = binding.arg ?? "debounce";
 | 
			
		||||
    const type = ["debounce", "throttle"].find(t => t === optimizeType);
 | 
			
		||||
    if (type) {
 | 
			
		||||
      if (value && value.event && isFunction(value.fn)) {
 | 
			
		||||
        let params = value?.params;
 | 
			
		||||
        if (params) {
 | 
			
		||||
          if (isArray(params) || isObject(params)) {
 | 
			
		||||
            params = isObject(params) ? Array.of(params) : params;
 | 
			
		||||
          } else {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
              "[Directive: optimize]: `params` must be an array or object"
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        // Register using addEventListener on mounted, and removeEventListener automatically on unmounted
 | 
			
		||||
        useEventListener(
 | 
			
		||||
          el,
 | 
			
		||||
          value.event,
 | 
			
		||||
          type === "debounce"
 | 
			
		||||
            ? debounce(
 | 
			
		||||
                params ? () => value.fn(...params) : value.fn,
 | 
			
		||||
                value?.timeout ?? 200,
 | 
			
		||||
                value?.immediate ?? false
 | 
			
		||||
              )
 | 
			
		||||
            : throttle(
 | 
			
		||||
                params ? () => value.fn(...params) : value.fn,
 | 
			
		||||
                value?.timeout ?? 1000
 | 
			
		||||
              )
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          "[Directive: optimize]: `event` and `fn` are required, and `fn` must be a function"
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        "[Directive: optimize]: only `debounce` and `throttle` are supported"
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@ -10,6 +10,15 @@ export default {
 | 
			
		||||
    rank: able
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      path: "/able/directives",
 | 
			
		||||
      name: "Directives",
 | 
			
		||||
      component: () => import("@/views/able/directives.vue"),
 | 
			
		||||
      meta: {
 | 
			
		||||
        title: $t("menus.hsOptimize"),
 | 
			
		||||
        extraIcon: "IF-pure-iconfont-new svg"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: "/able/watermark",
 | 
			
		||||
      name: "WaterMark",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										117
									
								
								src/views/able/directives.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/views/able/directives.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { message } from "@/utils/message";
 | 
			
		||||
 | 
			
		||||
defineOptions({
 | 
			
		||||
  name: "Directives"
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const search = ref("");
 | 
			
		||||
const searchTwo = ref("");
 | 
			
		||||
const searchThree = ref("");
 | 
			
		||||
const searchFour = ref("");
 | 
			
		||||
const searchFive = ref("");
 | 
			
		||||
const searchSix = ref("copy");
 | 
			
		||||
const text = ref("可复制的文本");
 | 
			
		||||
 | 
			
		||||
function onInput() {
 | 
			
		||||
  message(search.value);
 | 
			
		||||
}
 | 
			
		||||
function onInputTwo() {
 | 
			
		||||
  message(searchTwo.value);
 | 
			
		||||
}
 | 
			
		||||
function onInputThree({ name, sex }) {
 | 
			
		||||
  message(`${name}${sex}${searchThree.value}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onInputFour() {
 | 
			
		||||
  message(searchFour.value);
 | 
			
		||||
}
 | 
			
		||||
function onInputFive({ name, sex }) {
 | 
			
		||||
  message(`${name}${sex}${searchFive.value}`);
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <el-card shadow="never">
 | 
			
		||||
    <template #header>
 | 
			
		||||
      <div class="card-header">
 | 
			
		||||
        <span class="font-medium">自定义防抖、截流、文本复制指令</span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <div class="mb-2">
 | 
			
		||||
      防抖指令(连续输入,只会执行第一次点击事件,立即执行)
 | 
			
		||||
      <el-input
 | 
			
		||||
        v-optimize="{
 | 
			
		||||
          event: 'input',
 | 
			
		||||
          fn: onInput,
 | 
			
		||||
          immediate: true,
 | 
			
		||||
          timeout: 1000
 | 
			
		||||
        }"
 | 
			
		||||
        v-model="search"
 | 
			
		||||
        class="!w-[200px]"
 | 
			
		||||
        clearable
 | 
			
		||||
        @clear="onInput"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="mb-2">
 | 
			
		||||
      防抖指令(连续输入,只会执行最后一次事件,延后执行)
 | 
			
		||||
      <el-input
 | 
			
		||||
        v-optimize="{ event: 'input', fn: onInputTwo, timeout: 400 }"
 | 
			
		||||
        v-model="searchTwo"
 | 
			
		||||
        class="!w-[200px]"
 | 
			
		||||
        clearable
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
      防抖指令(连续输入,只会执行最后一次事件,延后执行,传参用法)
 | 
			
		||||
      <el-input
 | 
			
		||||
        v-optimize="{
 | 
			
		||||
          event: 'input',
 | 
			
		||||
          fn: onInputThree,
 | 
			
		||||
          timeout: 400,
 | 
			
		||||
          params: { name: '小明', sex: '男' }
 | 
			
		||||
        }"
 | 
			
		||||
        v-model="searchThree"
 | 
			
		||||
        class="!w-[200px]"
 | 
			
		||||
        clearable
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <el-divider />
 | 
			
		||||
 | 
			
		||||
    <div class="mb-2">
 | 
			
		||||
      节流指令(连续输入,每一秒只会执行一次事件)
 | 
			
		||||
      <el-input
 | 
			
		||||
        v-optimize:throttle="{ event: 'input', fn: onInputFour, timeout: 1000 }"
 | 
			
		||||
        v-model="searchFour"
 | 
			
		||||
        class="!w-[200px]"
 | 
			
		||||
        clearable
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
      节流指令(连续输入,每一秒只会执行一次事件,传参用法)
 | 
			
		||||
      <el-input
 | 
			
		||||
        v-optimize:throttle="{
 | 
			
		||||
          event: 'input',
 | 
			
		||||
          fn: onInputFive,
 | 
			
		||||
          params: { name: '小明', sex: '男' }
 | 
			
		||||
        }"
 | 
			
		||||
        v-model="searchFive"
 | 
			
		||||
        class="!w-[200px]"
 | 
			
		||||
        clearable
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <el-divider />
 | 
			
		||||
 | 
			
		||||
    <div class="mb-2">
 | 
			
		||||
      文本复制指令(双击输入框内容即可复制)
 | 
			
		||||
      <el-input v-copy="searchSix" v-model="searchSix" class="!w-[200px]" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
      文本复制指令(自定义触发事件,单击复制)
 | 
			
		||||
      <span v-copy:click="text" class="text-sky-500">{{ text }}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </el-card>
 | 
			
		||||
</template>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user