vue3 any ts 疯装一下自定义指令

529 阅读2分钟

前言

其实很多自定义指令实现的功能,现在都能直接从hooks函数找到

比如vue的vueuse,绝大部分功能都有

废话不多说,直接上手艺

1.第一步

src下整个ts文件,名字随便,路径随便,只要你找的到

我的文件路径:src/utils/directive.ts

2.第二步

去main.ts引入一下

import { createApp } from 'vue';
import App from '@/App.vue';
// 自定义指令配置
import myDirective from "@/utils/directive";

// 创建实例
const app = createApp(App)

// 自定义指令
myDirective(app)

这样做,其实就是在main.ts注册的自定义指令,只不过把自定义指令放在其他文件了

3.第三步

写指令咯,开干

src/utils/directive.ts

import Message from "xxxxxx"

// 自定义指令文件
const myDirective = (app: any) => {
    // 复制指令
    app.directive("copy", {
        mounted: (el: any, { value }: { value: string }) => {
            el.value = value
            el.handler = () => {
                if (!el.value) return Message({ content: "Nothing to copy!", type: "warning" })
                if (navigator.clipboard && window.isSecureContext) {
                    navigator.clipboard.writeText(el.value)
                        .then(() => { return Message({ content: "Copy successfully!", type: "success" }) })
                        .catch(() => { return Message({ content: "Replication failed!", type: "error" }) })
                } else {
                    // 动态创建 textarea 标签
                    let textarea = document.createElement('textarea')
                    // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
                    textarea.readOnly = true
                    textarea.style.position = 'absolute'
                    textarea.style.left = '-9999px'
                    // 将要 copy 的值赋给 textarea 标签的 value 属性
                    textarea.value = el.value
                    // 将 textarea 插入到 body 中
                    document.body.appendChild(textarea)
                    // 选中值并复制
                    textarea.select()
                    const result = document.execCommand('Copy')
                    if (result) Message({ content: "Copy successfully!", type: "success" })
                    else Message({ content: "Replication failed!", type: "error" })
                    document.body.removeChild(textarea)
                }
            }
            // 绑定点击事件
            el.addEventListener('click', el.handler)
        },
        // 当传进来的值更新的时候触发
        updated: (el: any, { value }: { value: string }) => el.value = value,
        // 指令与元素解绑的时候,移除事件绑定
        unmounted: (el: any) => el.removeEventListener('click', el.handler)
    })
    // 长按指令(可自定义长按时间)
    app.directive("longpress", {
        created: (el: any, { value }: { value: Function | { fn: Function, delay: number } }) => {
            let fn: Function, delay: number = 2000
            if (typeof value === 'function') fn = value
            else {
                fn = value.fn
                delay = value.delay >= 0 ? value.delay : 2000
            }
            let pressTimer: number | null = null
            // 创建计时器
            let start = (e: any) => {
                if (e.type === 'click' && e.button !== 0) return
                if (pressTimer === null) pressTimer = setTimeout(() => handler(e), delay)
            }
            // 取消计时器
            let cancel = () => {
                if (pressTimer !== null) {
                    clearTimeout(pressTimer)
                    pressTimer = null
                }
            }
            // 执行函数
            const handler = (e: any) => fn(e)
            // 添加事件监听器
            el.addEventListener('mousedown', start)
            el.addEventListener('touchstart', start, { passive: true })
            // 取消计时器
            el.addEventListener('click', cancel)
            el.addEventListener('mouseout', cancel)
            el.addEventListener('touchend', cancel)
            el.addEventListener('touchcancel', cancel)
        },
        // 移除事件绑定
        unmounted: (el: any) => el.removeEventListener('click', el.handler)
    })
    // 防抖节流(只支持点击事件),可设置是否立即执行与防抖时间
    const deThArr = ["debounce", "throttle"]
    for (let i = 0, length = deThArr.length; i < length; i++) {
        app.directive(deThArr[i], {
            created: (el: any, { value }: { value: Function | { fn: Function, delay: number, isImmeDiate: 1 | 0 } }) => {
                let fn: Function, delay: number = i ? 300 : 500, isImmeDiate: 1 | 0 = 1
                if (typeof value === "function") fn = value
                else {
                    fn = value.fn
                    delay = value.delay >= 0 ? value.delay : i ? 300 : 500
                    isImmeDiate = value.isImmeDiate >= 0 ? value.isImmeDiate : 1
                }
                let timeout: number | null = null
                el.addEventListener('click', () => {
                    if (isImmeDiate > 0) return isImmeDiate-- && fn()
                    if (timeout) {
                        if (i) return
                        else clearTimeout(timeout)
                    }
                    timeout = setTimeout(() => {
                        fn()
                        timeout = null
                    }, delay)
                })
            }
        })
    }
}

export default myDirective

我这里后期切了一刀,全局消息提示的引入替换了

目前写了一些常用的,刚想写其他的时候发现自己写的确实还不如用hooks的

等我技术在成长一些再考虑

目前这些指令都测试过来,能用

萌新一枚,轻喷