超实用!JS 自定义侧滑抽屉菜单,手把手教你打造 JavaScript 侧滑抽屉菜单插件

15 篇文章 0 订阅
8 篇文章 0 订阅

侧滑菜单作为一种常见的 UI 交互模式,广泛应用于各种网站和移动应用中。今天,我们就来一步步解析如何使用 JavaScript 创建一个功能完备、易于使用的侧滑抽屉菜单插件。

一、插件目标

我们希望实现的侧滑菜单插件具备以下功能:

  • 平滑的动画效果: 菜单的滑入和滑出都应有流畅的过渡效果。
  • 自定义滑出方向: 可以设置菜单从左侧或右侧滑出。
  • 外部点击关闭: 点击菜单区域以外的地方,菜单会自动关闭。
  • 按钮切换动画: 菜单按钮可以设置点击时的动画效果。
  • 易于集成: 插件应易于集成到现有的项目中,并提供简单的 API 进行调用。

二、HTML 结构

首先,我们需要在 HTML 中定义菜单按钮和菜单内容的结构:

<button class="drawer-toggle" data-target="#my-drawer" data-side="left">
  <span class="drawer-icon">&#9776;</span> 打开菜单
</button>
<div id="my-drawer" class="drawer">
  <button class="drawer-close">×</button>
  <ul>
    <li><a href="#">菜单项 1</a></li>
    <li><a href="#">菜单项 2</a></li>
    <li><a href="#">菜单项 3</a></li>
  </ul>
</div>
  • drawer-toggle:菜单按钮的类名,用于绑定点击事件。
  • data-target:指定要控制的菜单容器的 ID。
  • data-side:指定菜单滑出的方向,可选值 left 或 right
  • drawer:菜单容器的类名,用于设置样式和控制显示状态。
  • drawer-close:菜单关闭按钮的类名。

三、CSS 样式

我们可以使用 CSS 来定义菜单的外观和动画效果:

.drawer-toggle {
  /* 自定义按钮样式 */
  position: relative;
  background-color: #4CAF50;
  color: white;
  padding: 10px 15px;
  border: none;
  cursor: pointer;
}
.drawer {
  position: fixed;
  top: 0;
  width: 250px;
  height: 100%;
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  transition: transform 0.3s ease;
  z-index: 100;
}
.drawer.left {
  left: -250px; /* 初始时隐藏在左侧 */
}
.drawer.right {
  right: -250px; /* 初始时隐藏在右侧 */
}
.drawer.open {
  transform: translateX(250px); 
}
.drawer.open.right {
  transform: translateX(-250px); 
}
.drawer-close {
  /* 自定义关闭按钮样式 */
  position: absolute;
  top: 10px;
  right: 10px;
  background-color: transparent;
  border: none;
  font-size: 20px;
  cursor: pointer;
}
  • 我们使用 transform: translateX() 来实现菜单的滑入和滑出效果。
  • transition 属性确保动画过渡平滑。
  • .drawer.left 和 .drawer.right 分别定义了菜单从左侧和右侧滑出的初始状态。

四、 JavaScript 实现

现在,我们来编写 JavaScript 代码来实现插件的逻辑:

/**
 * @description 创建一个侧滑抽屉菜单插件
 * @name Drawer
 * @version 1.0.2
 */
(function (window, document, undefined) {
  'use strict';
  // CSS 样式内容
  const drawerCSS = `
    /* ... 上面定义的 CSS 样式 ... */
  `;

  // 插件构造函数
  function Drawer(options) {
    this.options = {
      side: 'left', 
      openClass: 'open', 
      toggleAnimation: 'rotate(90deg)',
      duration: 300 
    };
    // 合并自定义选项
    for (let key in options) {
      if (this.options.hasOwnProperty(key)) {
        this.options[key] = options[key];
      }
    }
    // 初始化
    this.init();
  }

  // 初始化方法
  Drawer.prototype.init = function () {
    this.addCSS(); // 添加 CSS 样式
    this.cacheDOM(); // 缓存 DOM 元素
    this.setInitialSide(); // 设置初始滑出方向
    this.bindEvents(); // 绑定事件 
  };

  // 添加 CSS 样式
  Drawer.prototype.addCSS = function () {
    // 判断是否已存在相同内容的 style 标签
    if (!document.querySelector(`style[data-drawer-css]`)) {
      const style = document.createElement('style');
      style.setAttribute('data-drawer-css', '');
      style.innerHTML = drawerCSS;
      document.head.appendChild(style);
    }
  };

  // 缓存 DOM 元素
  Drawer.prototype.cacheDOM = function () {
    this.toggleButtons = document.querySelectorAll('.drawer-toggle');
    this.drawers = document.querySelectorAll('.drawer');
  };

  //在 drawerCSS 中,我们为 .drawer.left 和 .drawer.right 添加了默认的隐藏样式:
  //.drawer.left 的 left 属性设置为 -250px,使其隐藏在屏幕左侧外部。
  //.drawer.right 的 right 属性设置为 -250px,使其隐藏在屏幕右侧外部。
  //新增 setInitialSide 方法,在初始化时为每个抽屉菜单添加对应的 left 或 right 类,确保初始状态下是隐藏的。
  // 设置初始滑出方向
  Drawer.prototype.setInitialSide = function () {
    this.drawers.forEach(drawer => {
      drawer.classList.add(this.options.side);
    });
  };

  // 绑定事件
  Drawer.prototype.bindEvents = function () {
    const self = this;
    this.toggleButtons.forEach(button => {
      button.addEventListener('click', function (event) {
        // 阻止事件冒泡,防止触发 document 的点击事件
        event.stopPropagation();
        const targetId = this.dataset.target;
        const targetDrawer = document.querySelector(targetId);
        self.toggleDrawer(targetDrawer);
        self.toggleAnimation(this);
      });
    });

    this.drawers.forEach(drawer => {
      const closeButton = drawer.querySelector('.drawer-close');
      if (closeButton) {
        closeButton.addEventListener('click', function (event) {
          // 阻止事件冒泡
          event.stopPropagation(); 
          self.closeDrawer(drawer);
        });
      }
      //添加全局事件,点击drawer以外的区域关闭 Drawer菜单
      document.addEventListener('click', function (event) {
        if (!drawer.contains(event.target)) { 
          self.closeDrawer(drawer);
        }
      });
    });
  };

  // 切换抽屉菜单状态
  Drawer.prototype.toggleDrawer = function (drawer) {
    drawer.classList.toggle(this.options.openClass);
  };

  // 关闭抽屉菜单
  Drawer.prototype.closeDrawer = function (drawer) {
    drawer.classList.remove(this.options.openClass);
  };

  // 切换按钮动画
  Drawer.prototype.toggleAnimation = function (button) {
    button.style.transition = `transform ${this.options.duration}ms ease`;
    button.style.transform = button.style.transform === this.options.toggleAnimation ? '' : this.options.toggleAnimation;
  };

  // 将 Drawer 构造函数暴露到全局作用域
  window.Drawer = Drawer;

})(window, document);
  • 插件封装: 我们使用 IIFE (Immediately Invoked Function Expression) 将代码封装成一个独立的插件,避免污染全局作用域。
  • 构造函数Drawer 构造函数用于创建新的抽屉菜单实例,并接受一个可选的 options 对象,用于自定义插件的行为。
  • 初始化init 方法用于初始化插件,包括添加 CSS 样式、缓存 DOM 元素、设置初始滑出方向以及绑定事件。
  • 事件处理bindEvents 方法用于绑定按钮点击事件和文档点击事件,实现菜单的打开、关闭以及外部点击关闭功能。
  • 在 bindEvents 方法中,我们为 document 添加了一个点击事件监听器。
  • 在事件处理函数中,我们使用 event.target 获取到点击的目标元素,并使用 drawer.contains(event.target) 判断目标元素是否在当前 drawer 元素内。
  • 如果目标元素不在 drawer 元素内,则调用 closeDrawer 方法关闭抽屉菜单。
  • 现在,当您点击 Drawer 以外的区域时,抽屉菜单就会自动关闭了!
  • 动画控制toggleAnimation 方法用于控制按钮的动画效果,toggleDrawer 和 closeDrawer 方法用于控制菜单的打开和关闭。

五、使用方法

在 HTML 文件中引入 JavaScript 文件后,我们可以创建一个新的 Drawer 实例来使用插件:

<script src="drawer.js"></script>
<script>
  // 创建一个新的抽屉菜单实例,内部还可以添加自定义参数new Drawer({side: 'left'})
  var myDrawer = new Drawer();
</script>

六、总结

通过以上步骤,我们就完成了一个功能完善、易于使用的 JavaScript 侧滑抽屉菜单插件。你可以根据自己的需求修改代码,自定义样式和动画效果,打造独一无二的交互体验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值