首页 > 其他分享 >推荐15个 Vue 常用自定义指令,含实现原理与使用方式

推荐15个 Vue 常用自定义指令,含实现原理与使用方式

时间:2024-10-26 09:47:34浏览次数:3  
标签:el style Vue 15 自定义 binding tooltip const

前言

Vue.js 是一个流行的前端框架,它的核心理念是通过指令(Directives)来扩展 HTML 的能力。尽管 Vue.js 已经内置了一些非常实用的指令(比如 v-if, v-show, v-for 等),但有时候我们还是需要创建自定义指令来满足特定的需求。今天我们就来聊聊 Vue 常用的自定义指令,它们能让你的代码更加简洁和高效。

常用自定义指令

1. v-focus:自动聚焦输入框

如果你希望在页面加载时,某个输入框自动获得焦点,可以创建一个 v-focus 指令。这个指令可以帮你省掉在 mounted 钩子里写 DOM 操作的麻烦。

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中时
  inserted: function (el) {
    // 聚焦元素
    el.focus();
  }
});

使用方法:

<input v-focus>

2. v-color:动态改变元素颜色

有时候我们需要根据某些条件动态改变某个元素的颜色,v-color 指令就派上用场了。

// 注册一个全局自定义指令 v-color
Vue.directive('color', {
  // 当绑定元素插入到 DOM 中时
  bind: function (el, binding) {
    el.style.color = binding.value;
  }
});

使用方法:

<div v-color="'red'">这段文字将会是红色的</div>

3. v-debounce:防抖输入

在处理用户输入时,你可能希望减少输入触发的事件次数(比如搜索输入框),使用 v-debounce 指令可以轻松实现防抖功能。

Vue.directive('debounce', {
  bind: function (el, binding) {
    let timeout;
    el.addEventListener('input', () => {
      if (timeout) clearTimeout(timeout);
      timeout = setTimeout(() => {
        binding.value(el.value);
      }, 500); // 延迟时间可以根据需要调整
    });
  }
});

使用方法:

<input v-debounce="handleInput">

在你的 Vue 组件中:

methods: {
  handleInput(value) {
    console.log(value);
  }
}

4. v-scroll:监听滚动事件

有时候我们需要在页面滚动时执行一些操作,比如加载更多数据或改变导航栏样式,可以使用 v-scroll 指令。

Vue.directive('scroll', {
  inserted: function (el, binding) {
    window.addEventListener('scroll', () => {
      binding.value(window.scrollY);
    });
  }
});

使用方法:

<div v-scroll="handleScroll">内容</div>

在你的 Vue 组件中:

methods: {
  handleScroll(scrollY) {
    console.log('滚动位置:', scrollY);
  }
}

5. v-resize:监听窗口大小变化

有时候我们需要动态调整元素的布局或样式以适应窗口的大小变化,v-resize 指令可以帮助我们简化这一操作。

Vue.directive('resize', {
  bind(el, binding) {
    const onResize = () => binding.value(el);
    window.addEventListener('resize', onResize);
    // 在元素卸载时移除事件监听器
    el._onResize = onResize;
  },
  unbind(el) {
    window.removeEventListener('resize', el._onResize);
  }
});

使用方法:

<div v-resize="handleResize">内容</div>

在你的 Vue 组件中:

methods: {
  handleResize(el) {
    console.log('元素尺寸:', el.clientWidth, el.clientHeight);
  }
}

6. v-lazyload:图片懒加载

懒加载是一种优化网页加载性能的技术,当用户滚动到图片所在位置时再加载图片,从而减少初始页面加载的资源消耗。我们可以创建一个 v-lazyload 指令来实现图片懒加载。

Vue.directive('lazyload', {
  bind(el, binding) {
    const loadImage = () => {
      const rect = el.getBoundingClientRect();
      if (rect.top < window.innerHeight && rect.bottom > 0) {
        el.src = binding.value;
        window.removeEventListener('scroll', loadImage);
      }
    };
    window.addEventListener('scroll', loadImage);
    loadImage(); // 立即执行一次,以防图片已在视口内
  },
  unbind() {
    window.removeEventListener('scroll', loadImage);
  }
});

使用方法:

<img v-lazyload="'path/to/image.jpg'" alt="图片描述">

7. v-clipboard:复制到剪贴板

为了在网页上提供一键复制文本到剪贴板的功能,我们可以创建一个 v-clipboard 指令。

Vue.directive('clipboard', {
  bind(el, binding) {
    el.addEventListener('click', () => {
      const textarea = document.createElement('textarea');
      textarea.value = binding.value;
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand('copy');
      document.body.removeChild(textarea);
      alert('复制成功!');
    });
  }
});

使用方法:

<button v-clipboard="'要复制的文本'">点击复制</button>

8. v-tooltip:简易提示框

有时候我们需要在鼠标悬停在某个元素上时显示一个提示框,这时可以用 v-tooltip 指令来实现。

Vue.directive('tooltip', {
  bind(el, binding) {
    const tooltip = document.createElement('div');
    tooltip.className = 'tooltip';
    tooltip.innerText = binding.value;
    tooltip.style.position = 'absolute';
    tooltip.style.backgroundColor = '#333';
    tooltip.style.color = '#fff';
    tooltip.style.padding = '5px 10px';
    tooltip.style.borderRadius = '4px';
    tooltip.style.display = 'none';
    document.body.appendChild(tooltip);

    el.addEventListener('mouseenter', () => {
      tooltip.style.display = 'block';
      const rect = el.getBoundingClientRect();
      tooltip.style.top = `${rect.top + window.scrollY - tooltip.offsetHeight}px`;
      tooltip.style.left = `${rect.left + window.scrollX}px`;
    });

    el.addEventListener('mouseleave', () => {
      tooltip.style.display = 'none';
    });
  },
  unbind(el) {
    el.removeEventListener('mouseenter');
    el.removeEventListener('mouseleave');
  }
});

使用方法:

<button v-tooltip="'这里是提示信息'">鼠标悬停显示提示</button>

9. v-permission:权限控制

在应用权限管理中,我们可能需要根据用户权限动态显示或隐藏某些内容,这时可以使用 v-permission 指令。

Vue.directive('permission', {
  bind(el, binding, vnode) {
    const userPermissions = vnode.context.$store.state.userPermissions; // 假设从 Vuex store 中获取用户权限
    if (!userPermissions.includes(binding.value)) {
      el.style.display = 'none';
    }
  }
});

使用方法:

<button v-permission="'admin'">仅管理员可见的按钮</button>

10. v-draggable:拖拽元素

为了让某些元素可以被拖拽,我们可以创建一个 v-draggable 指令。

Vue.directive('draggable', {
  bind(el) {
    el.style.position = 'absolute';
    el.onmousedown = function (e) {
      const disX = e.clientX - el.offsetLeft;
      const disY = e.clientY - el.offsetTop;
      document.onmousemove = function (e) {
        el.style.left = `${e.clientX - disX}px`;
        el.style.top = `${e.clientY - disY}px`;
      };
      document.onmouseup = function () {
        document.onmousemove = null;
        document.onmouseup = null;
      };
    };
  }
});

使用方法:

<div v-draggable style="width: 100px; height: 100px; background-color: red;"></div>

11. v-longpress:长按事件

有时候我们希望在用户长按某个元素时触发特定的操作,比如弹出菜单或执行某个命令,这时可以使用 v-longpress 指令。

Vue.directive('longpress', {
  bind(el, binding) {
    let pressTimer = null;
    const handler = (e) => {
      binding.value(e);
    };
    const start = (e) => {
      if (e.type === 'click' && e.button !== 0) {
        return;
      }
      if (pressTimer === null) {
        pressTimer = setTimeout(() => {
          handler(e);
        }, 1000); // 长按时间为1秒,可以根据需求调整
      }
    };
    const cancel = () => {
      if (pressTimer !== null) {
        clearTimeout(pressTimer);
        pressTimer = null;
      }
    };
    el.addEventListener('mousedown', start);
    el.addEventListener('touchstart', start);
    el.addEventListener('click', cancel);
    el.addEventListener('mouseout', cancel);
    el.addEventListener('touchend', cancel);
    el.addEventListener('touchcancel', cancel);
  },
  unbind(el) {
    el.removeEventListener('mousedown', start);
    el.removeEventListener('touchstart', start);
    el.removeEventListener('click', cancel);
    el.removeEventListener('mouseout', cancel);
    el.removeEventListener('touchend', cancel);
    el.removeEventListener('touchcancel', cancel);
  }
});

使用方法:

<button v-longpress="handleLongPress">长按我</button>

在你的 Vue 组件中:

methods: {
  handleLongPress() {
    alert('长按事件触发');
  }
}

12. v-autosize:自动调整文本域大小

为了让文本域(textarea)根据输入内容自动调整高度,可以使用 v-autosize 指令。

Vue.directive('autosize', {
  bind(el) {
    el.style.resize = 'none';
    const adjustHeight = () => {
      el.style.height = 'auto';
      el.style.height = `${el.scrollHeight}px`;
    };
    el.addEventListener('input', adjustHeight);
    adjustHeight(); // 初始化时调整一次高度
  },
  unbind(el) {
    el.removeEventListener('input', adjustHeight);
  }
});

使用方法:

<textarea v-autosize></textarea>

13. v-hover: 悬停样式切换

我们可以使用 v-hover 指令来在鼠标悬停时切换元素的样式。

Vue.directive('hover', {
  bind(el, binding) {
    const enter = () => {
      el.style.backgroundColor = binding.value.enter || 'yellow';
    };
    const leave = () => {
      el.style.backgroundColor = binding.value.leave || '';
    };
    el.addEventListener('mouseenter', enter);
    el.addEventListener('mouseleave', leave);
  },
  unbind(el) {
    el.removeEventListener('mouseenter', enter);
    el.removeEventListener('mouseleave', leave);
  }
});

使用方法:

<div v-hover="{ enter: 'lightblue', leave: 'white' }">鼠标悬停我试试!</div>

14. v-infinite-scroll:无限滚动加载

在做分页加载时,常常会用到无限滚动加载,可以使用 v-infinite-scroll 指令来实现这一功能。

Vue.directive('infinite-scroll', {
  bind(el, binding) {
    const options = {
      root: el,
      rootMargin: '0px',
      threshold: 1.0
    };

    const callback = (entries) => {
      if (entries[0].isIntersecting) {
        binding.value();
      }
    };

    const observer = new IntersectionObserver(callback, options);
    observer.observe(el.lastElementChild);

    el._observer = observer;
  },
  unbind(el) {
    if (el._observer) {
      el._observer.disconnect();
      delete el._observer;
    }
  }
});

使用方法:

<div v-infinite-scroll="loadMore">
  <div v-for="item in items" :key="item.id">{{ item.name }}</div>
</div>

在你的 Vue 组件中:

methods: {
  loadMore() {
    // 加载更多数据的逻辑
  }
}

15. v-highlight:文本高亮

为了在页面上高亮显示某些特定的文本,可以使用 v-highlight 指令。

Vue.directive('highlight', {
  bind(el, binding) {
    const text = el.innerHTML;
    const query = binding.value;
    const highlightedText = text.replace(new RegExp(`(${query})`, 'gi'), '<span class="highlight">$1</span>');
    el.innerHTML = highlightedText;
  }
});

使用方法:

<div v-highlight="'关键字'">这里包含一些关键字文本内容</div>

在 CSS 文件中定义高亮样式:

.highlight {
  background-color: yellow;
}

总结

通过自定义指令,我们可以更加灵活地操控 DOM 元素,并简化代码逻辑,提高开发效率。上述的 15 个自定义指令示例覆盖了开发中常见的需求,从自动聚焦、颜色变更、懒加载、复制到剪贴板、到无限滚动加载和文本高亮等。

标签:el,style,Vue,15,自定义,binding,tooltip,const
From: https://blog.csdn.net/m0_37890289/article/details/143246541

相关文章

  • JAVA开源项目 基于Vue和SpringBoot在线文档管理系统
    本文项目编号T038,文末自助获取源码\color{red}{T038,文末自助获取源码}......
  • 【开题报告】基于Springboot+vueHPV疫苗预约管理系统(程序+源码+论文) 计算机毕业设计
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在当今社会,随着健康意识的不断提升,预防疾病已成为人们日益关注的话题。其中,HPV(人乳头瘤病毒)疫苗作为预防宫颈癌等恶性疾病的重要手段,其接种需求在全球......
  • Vue-Router实现路由跳转
    1、官方指导文件1、官方指导文件客户端路由的作用是在单页应用(SPA)中将浏览器的URL和用户看到的内容绑定起来。当用户在应用中浏览不同页面时,URL会随之更新,但页面不需要从服务器重新加载。2、如何定义一个新的路由1)引入相关的组件importHomeViewfrom'../views/H......
  • 基于nodejs+vue基于的私人物品管理平台[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于私人物品管理的研究,现有研究主要以企业物品管理或公共物品管理为主,专门针对私人物品管理的研究较少。在国内外,对于物品管理的研究多集中在大型组织......
  • 基于nodejs+vue基于的食品销售系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于食品销售系统的研究,现有研究主要以传统的销售模式和管理方式为主。在国内外,虽然有不少企业已经在食品销售领域应用了信息化管理手段,但专门针对集会......
  • 基于nodejs+vue基于的诗文网站[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于诗文网站的研究,现有研究主要集中在传统诗文内容的呈现与简单交互功能方面。在国内外,诗文网站多以展示经典诗文作品、提供简单的检索功能为主。专门......
  • [java毕业设计]免费分享一套SpringBoot+Vue宠物商城网站系统【论文+源码+SQL脚本】,帅
    大家好,我是java1234_小锋老师,看到一个不错的SpringBoot++Vue宠物商城网站系统,分享下哈。项目视频演示【免费】SpringBoot+Vue宠物商城网站系统Java毕业设计_哔哩哔哩_bilibili项目介绍本论文旨在设计与实现一个基于SpringBoot和Vue.js的宠物商城网站系统。随着互联网技......
  • 基于SpringBoot+Vue的药店管理系统设计与实现毕设(文档+源码)
            目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:        大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的药店管理系统,项目源码请点击文章末尾联系我哦~目前有各类成品毕......
  • 基于SpringBoot+Vue的校园二手书交易平台管理系统设计与实现毕设(文档+源码)
           目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:        大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的校园二手书交易平台管理系统,项目源码请点击文章末尾联系我哦~目前有......
  • [Ynoi2015] 盼君勿忘 题解
    CSP前学习珂学,祝自己\(while(1)\rp++\)。考虑求解出每种数对答案的贡献。设\(t=r-l+1,k_x=\sum\limits_{i=l}^r[a_i=x]\),由容斥得贡献为\(x(2^t-2^{t-k_x})\)。求解\(k_x\),考虑莫队,时间复杂度为\(O(n\sqrtn)\),这也是本题的复杂度上限。由于\(p\)会变,所以不能用莫......