搬山行者

无志愁压头,有志能搬山

业余程序员的学习笔记~


lineone css模板解析-js

目录

配置

tailwind.config.js


const colors = require("tailwindcss/colors");
const defaultTheme = require("tailwindcss/defaultTheme");
// 引入依赖
// colors:Tailwind CSS 提供的颜色对象。
// defaultTheme:Tailwind CSS 默认的主题对象

const navyColor = {
  50: "#E7E9EF",
  100: "#C2C9D6",
  200: "#A3ADC2",
  300: "#697A9B",
  400: "#5C6B8A",
  450: "#465675",
  500: "#384766",
  600: "#313E59",
  700: "#26334D",
  750: "#222E45",
  800: "#202B40",
  900: "#192132",
};

// 自定义颜色
const customColors = {
  navy: navyColor,
  "slate-150": "#E9EEF5",
  primary: colors.indigo["600"],
  "primary-focus": colors.indigo["700"],
  "secondary-light": "#ff57d8",
  secondary: "#F000B9",
  "secondary-focus": "#BD0090",
  "accent-light": colors.indigo["400"],
  accent: "#5f5af6",
  "accent-focus": "#4d47f5",
  info: colors.sky["500"],
  "info-focus": colors.sky["600"],
  success: colors.emerald["500"],
  "success-focus": colors.emerald["600"],
  warning: "#ff9800",
  "warning-focus": "#e68200",
  error: "#ff5724",
  "error-focus": "#f03000",
};
// 定义了名为navy的颜色调色板。


// 导出配置
module.exports = {
  // TailwindCSS应扫描的文件路径,以提取类名并生成最终的CSS文件
  content: [
    "./src/**/*.{php,html,js,jsx,ts,tsx,vue}",
    "./resources/**/*.{php,html,js,jsx,ts,tsx,vue}",
    "./storage/framework/views/*.php",
  ],
  darkMode: "class",
  // 设置暗模式为通过类名控制,即根元素上添加 class="dark" 来切换暗模式。
  theme: {
    extend: {
      fontFamily: { // 扩展默认的字体族,添加 Poppins 和 Inter 字体
        sans: ["Poppins", ...defaultTheme.fontFamily.sans],
        inter: ["Inter", ...defaultTheme.fontFamily.sans],
      },
      fontSize: { // 定义新的字体大小
        tiny: ["0.625rem", "0.8125rem"],
        "tiny+": ["0.6875rem", "0.875rem"],
        "xs+": ["0.8125rem", "1.125rem"],
        "sm+": ["0.9375rem", "1.375rem"],
      },
      colors: { ...customColors }, // 扩展默认的颜色,添加自定义颜色
      opacity: { // 定义新的透明度值
        15: ".15",
      },
      spacing: { // 定义新的间距值
        4.5: "1.125rem",
        5.5: "1.375rem",
        18: "4.5rem",
      },
      boxShadow: { // 定义新的阴影效果
        soft: "0 3px 10px 0 rgb(48 46 56 / 6%)",
        "soft-dark": "0 3px 10px 0 rgb(25 33 50 / 30%)",
      },
      zIndex: { // 定义新的 z-index 值
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
      },
      keyframes: { // 定义新的关键帧动画
        "fade-out": {
          "0%": {
            opacity: 1,
            visibility: "visible",
          },
          "100%": {
            opacity: 0,
            visibility: "hidden",
          },
        },
      },
    },
  },
  corePlugins: { // 禁用一些默认的核心插件,以减少生成的 CSS 文件大小
    textOpacity: false,
    backgroundOpacity: false,
    borderOpacity: false,
    divideOpacity: false,
    placeholderOpacity: false,
    ringOpacity: false,
  },
  plugins: [
    require("@tailwindcss/line-clamp")
    // 引入 @tailwindcss/line-clamp 插件,用于控制文本的行数。
  ],
};

webpack.mix.js

const mix = require("laravel-mix");
// 引入 laravel-mix 模块,用于配置和运行 Webpack 构建任务

mix
  .js("src/js/app.js", "js") // src/js/app.js编译并输出到dist/js目录
  .postCss("src/css/app.css", "css", [
    require("tailwindcss"),
    require("autoprefixer"),
  ])
  // 使用PostCSS处理src/css/app.css文件,
  // 并应用tailwindcss和autoprefixer插件。
  // 输出结果到dist/css目录下
  .options({ processCssUrls: false })
  // 禁用CSS URL处理,防止Mix自动处理CSS中的URL
  .webpackConfig({
    module: {
      rules: [ // 使用source-map-loader预处理.js文件,以生成源映射文件
        {
          test: /\.js$/,
          enforce: "pre", // 在其他加载器之前执行
          use: ["source-map-loader"],
        },
      ],
    },
    devServer: {
      open: true, // 在开发服务器启动时自动打开浏览器
    },
  })
  .copyDirectory("src/html/", "dist")
  //  src/html 目录下的所有文件复制到 dist 目录下
  .copyDirectory("src/images", "dist/images")
  // src/images 目录下的所有文件复制到 dist/images 目录下
  .copyDirectory("src/fonts", "dist/fonts")
  // src/fonts 目录下的所有文件复制到 dist/fonts 目录下
  .setPublicPath("dist")
  // 设置输出文件的公共路径为 dist
  .disableNotifications();
  // 禁用 Mix 在构建成功或失败时发送的通知

JS

app.js

import Alpine from "alpinejs";
// AlpineJS:一个轻量级的JavaScript框架,用于构建交互式用户界面

// AlpineJS Plugins 
import persist from "@alpinejs/persist"; 
// persist 用于持久化数据
import collapse from "@alpinejs/collapse"; 
// collapse实现折叠效果
import intersect from "@alpinejs/intersect"; 
// intersect 用于检测元素是否进入视口

// 导入第三方库

/**
 * Scrollbar Library
 * @see https://github.com/Grsmto/simplebar
 */
import SimpleBar from "simplebar";
// SimpleBar:一个滚动条库,用于自定义滚动条样式。

/**
 * Code highlighting library
 * JUST FOR DEMO PURPOSE ONLY FOR HIGHLIGHTING CODE
 * @see https://highlightjs.org/
 */
// highlight.js:一个代码高亮库,用于在网页上显示高亮的代码块
import hljs from "highlight.js/lib/core";
import xml from "highlight.js/lib/languages/xml";

/**
 * Date Utility Library
 * @see https://day.js.org/
 */
import dayjs from "dayjs";
// dayjs:一个轻量级的日期处理库

/**
 * Carousel Library
 * @see https://swiperjs.com/
 */
import Swiper from "swiper/bundle";
// Swiper:一个滑动库,用于实现轮播图效果

/**
 * Drag & Drop Library
 * @see https://github.com/SortableJS/Sortable
 */
import Sortable from "sortablejs";
// Sortable:一个拖放排序库,用于实现列表项的拖放排序

/**
 * Chart Library
 * @see https://apexcharts.com/
 */
import ApexCharts from "apexcharts";
// ApexCharts:一个图表库,用于绘制各种图表。

/**
 * Table Library
 * @see https://gridjs.io/
 */
import * as Gridjs from "gridjs";
// Gridjs:一个表格库,用于创建响应式的表格

//  Forms Libraries
import "@caneara/iodine"; // @see https://github.com/caneara/iodine
// @caneara/iodine:一个表单验证库

import * as FilePond from "filepond"; 
// @see https://pqina.nl/filepond/
// FilePond:一个文件上传库,用于处理文件上传 

import FilePondPluginImagePreview from "filepond-plugin-image-preview"; // @see https://pqina.nl/filepond/docs/api/plugins/image-preview/
// FilePondPluginImagePreview:FilePond的插件,用于预览上传的图片。

import Quill from "quill/dist/quill.min"; // @see https://quilljs.com/
// Quill:一个富文本编辑器库

import flatpickr from "flatpickr"; // @see https://flatpickr.js.org/
// flatpickr:一个日期选择器库

import Tom from "tom-select/dist/js/tom-select.complete.min"; // @see https://tom-select.js.org/
// Tom:一个选择器库,用于创建多选和单选选择器

// Helper Functions
import * as helpers from "./utils/helpers";
// helpers:自定义的辅助函数集合,用于处理各种通用任务

// Pages Scripts
import * as pages from "./pages";
// pages:包含各个页面的特定脚本

// Global Store
import store from "./store";
// store:全局状态管理库,用于存储应用的状态

// Breakpoints Store
import breakpoints from "./utils/breakpoints";
// breakpoints:用于存储不同屏幕尺寸的断点信息

// Alpine Components
import usePopper from "./components/usePopper";
// usePopper,用于实现弹出提示
import accordionItem from "./components/accordionItem";
// accordionItem, 实现手风琴效果
import navLink from "./components/navLink";
// navLink, 实现导航链接

// Alpine Directives
import tooltip from "./directives/tooltip";
// tooltip, 实现工具提示
import inputMask from "./directives/inputMask";
// inputMask,实现输入掩码

// Alpine Magic Functions
import notification from "./magics/notification";
// notification, 显示通知
import clipboard from "./magics/clipboard";
// clipboard, 复制文本到剪贴板

// Register HTML, XML language for highlight.js
// Just for demo purpose only for highlighting code
hljs.registerLanguage("xml", xml);
// 注册XML语言支持
hljs.configure({ ignoreUnescapedHTML: true });
// 配置highlight.js忽略未转义的HTML

// Register plugin image preview for filepond
FilePond.registerPlugin(FilePondPluginImagePreview);
// 注册FilePond的图像预览插件

// 挂载库和工具到全局对象window
window.hljs = hljs;
window.dayjs = dayjs;
window.SimpleBar = SimpleBar;
window.Swiper = Swiper;
window.Sortable = Sortable;
window.ApexCharts = ApexCharts;
window.Gridjs = Gridjs;
window.FilePond = FilePond;
window.flatpickr = flatpickr;
window.Quill = Quill;
window.Tom = Tom;

window.Alpine = Alpine;
window.helpers = helpers;
window.pages = pages;

// 注册AlpineJS的persist、collapse、intersect插件
Alpine.plugin(persist);
Alpine.plugin(collapse);
Alpine.plugin(intersect);

// 注册AlpineJS指令
Alpine.directive("tooltip", tooltip);
Alpine.directive("input-mask", inputMask);

// 注册自定义的AlpineJS魔法函数(notification、clipboard)
Alpine.magic("notification", () => notification);
Alpine.magic("clipboard", () => clipboard);

// 注册AlpineJS数据组件
Alpine.store("breakpoints", breakpoints);
Alpine.store("global", store);

Alpine.data("usePopper", usePopper);
Alpine.data("accordionItem", accordionItem);
Alpine.data("navLink", navLink);

store.js

代码分析

export default {
  isDarkModeEnabled: false, // 是否启用暗模式
  isMonochromeModeEnabled: false, // 是否启用单色模式
  isSearchbarActive: false, // 搜索栏是否激活
  isSidebarExpanded: false, // 左侧侧边栏是否展开
  isRightSidebarExpanded: false, // 右侧侧边栏是否展开
  currentLocation: currentLocation(),
  // 当前页面的URL,通过调用 currentLocation() 函数获取
  init() {
    let firstTime = true; // 标记是否是第一次初始化

    this.isDarkModeEnabled = Alpine.$persist(false).as("_x_darkMode_on");
    // 使用 Alpine.$persist 持久化暗模式状态

    this.isSidebarExpanded =
      document.querySelector(".sidebar") &&
      document.body.classList.contains("is-sidebar-open") &&
      Alpine.store("breakpoints").xlAndUp;
    // 根据页面初始状态和断点设置侧边栏是否展开  

    Alpine.effect(() => { // 监听状态变化并动态更新DOM类名
      this.isDarkModeEnabled
        ? document.documentElement.classList.add("dark")
        : document.documentElement.classList.remove("dark");
    }); 
    // 监听isDarkModeEnabled,更新document.documentElement的dark类名

    Alpine.effect(() => {
      this.isMonochromeModeEnabled
        ? document.body.classList.add("is-monochrome")
        : document.body.classList.remove("is-monochrome");
    });
    // 监听isMonochromeModeEnabled,更新document.body的is-monochrome类名

    Alpine.effect(() => {
      this.isSidebarExpanded
        ? document.body.classList.add("is-sidebar-open")
        : document.body.classList.remove("is-sidebar-open");
    });
    // 监听isSidebarExpanded,更新document.body的is-sidebar-open类名

    Alpine.effect(() => {
      if (Alpine.store("breakpoints").name && !firstTime) {
        this.isSidebarExpanded = false;
        this.isRightSidebarExpanded = false;
      }
    });
    // 监听断点变化,调整侧边栏和右侧边栏的状态

    Alpine.effect(() => {
      if (Alpine.store("breakpoints").smAndUp) this.isSearchbarActive = false;
    });
    // 监听断点变化,调整搜索栏的状态

    firstTime = false;
  },

  documentBody: {
    ["@load.window"]() { // 页面加载时触发的事件
      const preloader = document.querySelector(".app-preloader");
      // 查找页面中的预加载器元素
      // 如找到预加载器,使用setTimeout延迟执行动画效果,150毫秒后添加动画类名,1000毫秒后移除预加载器
      if (!preloader) return;
      setTimeout(() => {
        preloader.classList.add(
          "animate-[cubic-bezier(0.4,0,0.2,1)_fade-out_500ms_forwards]"
        );
        setTimeout(() => preloader.remove(), 1000);
      }, 150);
    },
  },
};

function currentLocation() {
  return [location.protocol, "//", location.host, location.pathname].join("");
  // 通过拼接protocol、host 和 pathname,返回当前页面的完整URL.
}

Alpine.effect方法

Alpine.effect是Alpine.js提供的一个响应式机制,用于在数据发生变化时自动执行某些操作。它类似于Vue.js中的watch或React中的useEffect钩子。

Alpine.effect接受一个函数作为参数,在依赖的数据发生变化时被重新执行。 可在这个函数中进行DOM操作或其他逻辑处理

utils/helper.js

代码分析

export function toggleCode(e) { 
  // 切换代码块的显示状态 e:事件对象,通常是由点击事件触发

  const card = e.target.closest(".card");
  // 使用closest方法找到事件目标元素的最近的祖先元素.card 容器
  const codeWrapper = card.querySelector(".code-wrapper");
  // 在 .card 容器中查找 .code-wrapper 元素

  e.target.checked
    ? codeWrapper.classList.remove("hidden")
    : codeWrapper.classList.add("hidden");
  /*
  如果 checked 为 true,则移除 .code-wrapper 元素的 hidden 类,使其可见
  如果 checked 为 false,则添加 .code-wrapper 元素的 hidden 类,使其隐藏
  */  
}

export function getBrwoserScrollbarWidth() {
  // 获取浏览器滚动条的宽度  
  return window.innerWidth - document.documentElement.clientWidth;
  /* window.innerWidth 浏览器窗口的内部宽度,包括滚动条
     document.documentElement.clientWidth:文档元素的宽度,不包括滚动条
     两者相减得到滚动条的宽度
  */
}

utils/breakpoints

代码分析

// 响应屏幕尺寸变化,检测当前屏幕的断点,并根据断点更新一些属性
export default {
  init() {
    this.update(); // 调用update方法,初始化当前的窗口高度和宽度
    window.addEventListener("resize", this.onResize.bind(this), {
      passive: true,
    });
    // 添加一个resize事件监听器,当窗口大小变化时调用onResize方法
  },
  height: 0,
  width: 0,
  name: "", // 当前断点的名称
  isBreakpointChanged: false, // 是否断点发生变化(但未在代码中使用)
  isXs: false,
  isSm: false,
  isMd: false,
  isLg: false,
  isXl: false,
  is2xl: false,
  /* isXs, isSm, isMd, isLg, isXl, is2xl: 分别表示当前窗口是否处于 xs, sm, md, lg, xl, 2xl 断点
    */

  smAndDown: false,
  smAndUp: false,
  mdAndDown: false,
  mdAndUp: false,
  lgAndDown: false,
  lgAndUp: false,
  xlAndDown: false,
  xlAndUp: false,
  /* smAndDown, smAndUp, mdAndDown, mdAndUp, lgAndDown, lgAndUp, xlAndDown, xlAndUp: 表示当前窗口是否处于某个断点及其以下或以上
    */

  sm: 640,
  md: 768,
  lg: 1024,
  xl: 1280,
  the2xl: 1536,
  /*
    sm, md, lg, xl, the2xl: 分别表示 sm, md, lg, xl, 2xl 断点的像素值
  */

  update() {
    const height = window.innerHeight;
    const width = window.innerWidth;
    // 获取当前窗口的高度和宽度
    
    const xs = width < this.sm;
    const sm = width < this.md && !xs;
    const md = width < this.lg && !(sm || xs);
    const lg = width < this.xl && !(md || sm || xs);
    const xl = width < this.the2xl && !(lg || md || sm || xs);
    const the2xl = width >= this.the2xl;
   

    this.height = height;
    this.width = width;

    this.isXs = xs;
    this.isSm = sm;
    this.isMd = md;
    this.isLg = lg;
    this.isXl = xl;
    this.is2xl = the2xl;
    

    this.smAndDown = (xs || sm) && !(md || lg || xl || the2xl);
    this.smAndUp = !xs && (sm || md || lg || xl || the2xl);
    this.mdAndDown = (xs || sm || md) && !(lg || xl || the2xl);
    this.mdAndUp = !(xs || sm) && (md || lg || xl || the2xl);
    this.lgAndDown = (xs || sm || md || lg) && !(xl || the2xl);
    this.lgAndUp = !(xs || sm || md) && (lg || xl || the2xl);
    this.xlAndDown = (xs || sm || md || lg || xl) && !the2xl;
    this.xlAndUp = !(xs || sm || md || lg) && (xl || the2xl);
    

    if (xs) this.name = "xs";
    if (sm) this.name = "sm";
    if (md) this.name = "md";
    if (lg) this.name = "lg";
    if (xl) this.name = "xl";
    if (the2xl) this.name = "2xl";

    document.documentElement.style.setProperty("--vh", `${height * 0.01}px`);
    /* --vh 是一个CSS自定义属性(变量)。自定义属性以--开头,可在CSS中定义并在其他地方引用.
    将当前窗口高度的 1% 作为值,设置到根元素的 --vh 自定义属性中
    */

  },

  onResize() {
    clearTimeout(this.resizeTimeout);
    // 清除之前的定时器,防止多次调用 update 方法
    this.resizeTimeout = window.setTimeout(this.update.bind(this), 175);
    // 设置一个新的定时器,在 175 毫秒后调用 update 方法
  },
};

pages/index.js

代码分析

export { charts } from "./apexchartDemo";
export { tomSelect } from "./tomselectDemo";

export * as tables from "./tablesDemo";
export * as formValidation from "./formValidationDemo";

export { default as initCreditCard } from "./initCreditCard";

/*
负责从其他模块导出一些功能或对象,具体如下:
charts 和 tomSelect 分别从 apexchartDemo.js 和 tomselectDemo.js 模块中导出。
tables 和 formValidation 作为命名空间从 tablesDemo.js 和 formValidationDemo.js 模块中导出所有成员。
initCreditCard 从 initCreditCard.js 模块中默认导出。
*/

components/usePopper.js

代码分析

import { createPopper } from "@popperjs/core";
// 从 @popperjs/core中导入createPopper函数,用于创建Popper实例

export default (userOptions = {}) => ({
  popperInstance: null,
  // 存储 Popper 实例的变量,初始值为 null
  options: buildOptions(userOptions),
  // 通过buildOptions函数根据用户提供的userOptions构建的Popper配置选项

  isShowPopper: false,
  // Popper 是否显示,默认为 false

  init() {
    this.$nextTick( //确保DOM已经渲染完成
      () =>
        (this.popperInstance = createPopper(
          this.$refs.popperRef,
          this.$refs.popperRoot,
          this.options
        ))
        // 创建Popper实例,并将其赋值给popperInstance
    );
    /*
    $refs可用于检索组件内标记有x-ref的DOM元素。
    */
    this.$watch("isShowPopper", (val) => val && this.popperInstance.update());
    /* 监听isShowPopper,为true时调用popperInstance.update()更新 Popper 的位置
    */
    
    Alpine.effect(
      () => Alpine.store("breakpoints").name && (this.isShowPopper = false)
    );
    //  监听断点变化,当断点变化时设置isShowPopper为false,隐藏Popper
  },
});

const buildOptions = (options) => {
  const config = {
    placement: options.placement ?? "auto",
    // 位置,默认为 auto
    strategy: options.strategy ?? "fixed",
    // 定位策略,默认为 fixed
    onFirstUpdate: options.onFirstUpdate ?? function () {},
    // 第一次更新时的回调函数,默认为空函数

    modifiers: [ // 修饰符数组,包含一个 offset 修饰符,用于设置偏移量
      {
        name: "offset",
        options: {
          offset: [0, options.offset ?? 0],
        },
      },
    ],
  };

  if (options.modifiers) config.modifiers.push(...options.modifiers);
  // 如果提供了额外的 modifiers,将其合并到配置对象中

  return config;
};

components/accordionItem.js

代码分析

export default (id) => ({
  acc_id: id,
  get expanded() {
    return this.expandedItem === this.acc_id;
  },
  /* 当前对象是否处于展开状态。如果 expandedItem 等于 acc_id,则返回 true,否则返回 false
  */

  set expanded(val) {
    this.expandedItem = val ? this.acc_id : null;
  }
  /*
  设置当前对象的展开状态。如果 val 为 true,则将 expandedItem 设置为 acc_id;否则将其设置为 null。 
  */
});

components/navLink.js

代码分析

export default () => ({
  isActive: false,

  init() {
    if (!this.$el.href) return;
    // 检查元素是否有 href 属性,如果没有则直接返回

    this.isActive =
      this.$el.href.split("?")[0].split("#")[0] ===
      this.$store.global.currentLocation;
    /*
    比较 href 的基础部分(去除查询参数和锚点)与全局存储中的 currentLocation 是否相同
    如果相同,则设置 isActive 为 true,并根据条件展开元素,使元素滚动到视图中心
    */

    if (this.isActive) {
      if (this.acc_id) this.expanded = true;
      this.$el.scrollIntoView({ block: "center" });
    }
  },
});

/*
scrollIntoView 方法的选项对象可以包含多个参数,用于控制滚动行为。
除了 { block: "center" } 之外,还有其他一些常用的参数。
常用参数:
block:
    start:元素的顶部边缘与视口的顶部边缘对齐。
    center:元素的顶部边缘与视口的中间位置对齐。
    end:元素的底部边缘与视口的底部边缘对齐。
    nearest:元素的最近边缘与视口的最近边缘对齐。
inline:
    start:元素的左边缘与视口的左边缘对齐。
    center:元素的左边缘与视口的中间位置对齐。
    end:元素的右边缘与视口的右边缘对齐。
    nearest:元素的最近边缘与视口的最近边缘对齐。
behavior:
    auto:默认行为,立即滚动。
    smooth:平滑滚动,滚动过程会有动画效果
*/

directives/tooltip.js

代码分析

import tippy, { followCursor, roundArrow } from "tippy.js";
/* 导入tippy.js库及其插件followCursor和roundArrow。
tippy: 主要的提示框组件。
followCursor: 插件,使提示框跟随鼠标光标。
roundArrow: 插件,为提示框添加圆角箭头
*/

export default (el, { modifiers, expression }, { evaluateLater, effect }) => {
  const getContent = evaluateLater(expression);
  const options = buildOptionsFromModifiers(modifiers);

  effect(() => { /* 初始执行一次,并且每当其依赖的数据发生变化时,会自动重新执行 */
    getContent((content) => {
      if (options.content === true) {
        options.content = document
          .querySelector(content)
          .content.cloneNode(true);
        options.allowHTML = true;
        el.__x_tippy = tippy(el, options);
      } else {
        if (!el.__x_tippy) {
          el.__x_tippy = tippy(el, options);
        }
        el.__x_tippy.setContent(content);
      }
    });
  });
  /*
  如options.content为true,则从DOM中查询并克隆内容,设置为提示框的内容。
  否则,直接设置提示框的内容为 content
  */
};

const buildOptionsFromModifiers = (modifiers) => {
  /*
  从给定的修饰符列表中构建tippy.js提示框的配置选项。
  这些修饰符可以控制提示框的各种行为和样式.
  */   
  const options = {
    plugins: [], // 存储插件的数组,默认为空
    arrow: roundArrow, // 使用roundArrow插件来生成箭头
    animation: "shift-away", // 动画效果,默认为 "shift-away"
    zIndex: 10003, // 层叠顺序,默认为 10003
  };

  if (modifiers.includes("duration")) {
    options.duration = parseInt(modifiers[modifiers.indexOf("duration") + 1]);
  }
  /*
  如果修饰符列表中包含 "duration",则从下一个位置获取持续时间值,并将其转换为整数后赋值给 options.duration
  */

  if (modifiers.includes("delay")) {
    options.delay = parseInt(modifiers[modifiers.indexOf("delay") + 1]);
  }
  /* 
  如果修饰符列表中包含 "delay",则从下一个位置获取延迟时间值,并将其转换为整数后赋值给 options.delay
  */

  if (modifiers.includes("cursor")) {
    /*如果修饰符列表中包含 "cursor",则将 followCursor 插件添加到 plugins 数组中
    */
    options.plugins.push(followCursor);

    const next = modifiers[modifiers.indexOf("cursor") + 1] ?? null;

    if (["x", "y", "initial"].includes(next)) {
      if (next === "x") options.followCursor = "horizontal";
      if (next === "y") options.followCursor = "vertical";
      if (next === "initial") options.followCursor = "initial";
    } else {
      options.followCursor = true;
    }
    /*
    从下一个位置获取方向值("x"、"y" 或 "initial"),并根据值设置 options.followCursor
    如果没有指定方向值,则默认设置为 true
    */
  }

  if (modifiers.includes("on")) {
    options.trigger = modifiers[modifiers.indexOf("on") + 1];
  }
  /*
  如果修饰符列表中包含 "on",则从下一个位置获取触发事件类型(如 "click"、"hover" 等),并赋值给 options.trigger
  */

  if (modifiers.includes("arrowless")) {
    options.arrow = false;
  }
  /*
  如果修饰符列表中包含 "arrowless",则将 options.arrow 设置为 false,表示不显示箭头
  */

  if (modifiers.includes("interactive")) {
    options.interactive = true;
  }
  /* 
  如果修饰符列表中包含 "interactive",则将 options.interactive 设置为 true,表示提示框可交互
  */

  if (modifiers.includes("border") && options.interactive) {
    options.interactiveBorder = parseInt(
      modifiers[modifiers.indexOf("border") + 1]
    );
  }
  /*
  如果修饰符列表中包含 "border" 且 options.interactive 为 true,则从下一个位置获取边框宽度值,并将其转换为整数后赋值给 options.interactiveBorder
  */

  if (modifiers.includes("debounce") && options.interactive) {
    options.interactiveDebounce = parseInt(
      modifiers[modifiers.indexOf("debounce") + 1]
    );
  }
  /* 
  如果修饰符列表中包含 "debounce" 且 options.interactive 为 true,则从下一个位置获取防抖时间值,并将其转换为整数后赋值给 options.interactiveDebounce
  */

  if (modifiers.includes("max-width")) {
    options.maxWidth = parseInt(modifiers[modifiers.indexOf("max-width") + 1]);
  }
  /*
  如果修饰符列表中包含 "max-width",则从下一个位置获取最大宽度值,并将其转换为整数后赋值给 options.maxWidth
  */

  if (modifiers.includes("placement")) {
    options.placement = modifiers[modifiers.indexOf("placement") + 1];
  }
  /*
  如果修饰符列表中包含 "placement",则从下一个位置获取放置位置(如 "top"、"bottom" 等),并赋值给 options.placement
  */

  if (modifiers.includes("light")) options.theme = "light";
  if (modifiers.includes("primary")) options.theme = "primary";
  if (modifiers.includes("secondary")) options.theme = "secondary";
  if (modifiers.includes("info")) options.theme = "info";
  if (modifiers.includes("success")) options.theme = "success";
  if (modifiers.includes("warning")) options.theme = "warning";
  if (modifiers.includes("error")) options.theme = "error";
  if (modifiers.includes("sm")) options.theme = `${options.theme} is-sm`;
  /*
  根据不同的主题修饰符(如 "light"、"primary" 等),设置options.theme。
  如果包含 "sm" 修饰符,则在当前主题基础上追加 is-sm
  */

  if (modifiers.includes("content")) {
    options.theme = "content";
    options.content = true;
  }
  /*
  如果修饰符列表中包含 "content",则将 options.theme 设置为 "content",并将 options.content 设置为 true
  */

  return options;
};

directives/inputMask.js

代码分析

import Cleave from 'cleave.js/dist/cleave.min'
/*
Cleave库是一个用于输入格式化的JavaScript库。它的主要功能包括:
自动格式化输入:根据预设的规则自动格式化用户输入的内容。例如,电话号码、日期、信用卡号等。
实时验证:在用户输入过程中实时验证输入内容,确保输入符合预期格式。
灵活配置:通过配置选项,可以轻松地定制不同的输入格式和验证规则。
*/

export default (el, { expression}, {evaluateLater, effect}) => {
    const getContent = evaluateLater(expression)

    effect(() => {
        getContent(content => {
            if (typeof content == 'object')
                el.__x_cleave = new Cleave(el, content)
            else console.warn('Input mask config should be object')
        })
    })
}

magics/notification.js

代码分析

import Toastify from "toastify-js";
// 导入了 Toastify 模块,该模块用于创建和显示通知消息

export default (userOptions) => {
  /* 定义导出函数
  接受一个参数 userOptions,包含用户传递的各种配置选项。
  */
  let [position = "right", gravity = "bottom"] = userOptions.position
    ? userOptions.position.split("-")
    : "";
  /*
  解析出 position 属性,如果存在,则将其按-分割为两个部分,分别赋值给 position 和 gravity。如果 position 不存在,则默认值分别为 "right" 和 "bottom"。
  */  

  let removeTrigger = null;
  // 初始化变量 removeTrigger,用于存储移除通知的触发器元素

  const options = {
    // 设置默认选项
    duration: userOptions.duration || 5000,
    gravity,
    position,
    text: userOptions.text || "This is a message",
    newWindow: true,
    close: userOptions.hasCloseBtn || false,
    backgroundColor: "",
    className: userOptions.class || "",
    stopOnFocus: userOptions.pauseOnHover || true,
  };
  /*
    duration: 通知显示的时间,默认为 5000 毫秒。
    gravity: 通知的垂直位置,从 userOptions 中解析得到。
    position: 通知的水平位置,从 userOptions 中解析得到。
    text: 通知的文本内容,默认为 "This is a message"。
    newWindow: 是否在新窗口中打开链接,默认为 true。
    close: 是否显示关闭按钮,默认为 false。
    backgroundColor: 通知的背景颜色,默认为空字符串。
    className: 自定义的类名,默认为空字符串。
    stopOnFocus: 当鼠标悬停时是否暂停计时,默认为 true。
  */

  if (userOptions.link) {
    options.destination = userOptions.link;
  }
  /*
  检查 userOptions 中是否存在 link 属性,如果存在,则将其赋值给 options.destination,用于指定通知链接的目标地址
  */

  if (userOptions.variant) {
    options.className = `${options.className} ${userOptions.variant}`;
  }
  /*
  检查 userOptions 中是否存在 variant 属性,如果存在,则将其添加到 options.className 中,用于应用不同的样式变体
  */

  if (userOptions.content) {
    options.node = document.querySelector(userOptions.content).content.firstElementChild.cloneNode(true);
    options.className += " html";
    options.close = false;
  }
  /*
  检查 userOptions 中是否存在 content 属性,如果存在,则从指定的选择器中获取内容,并将其克隆为 options.node。同时,将 html 类名添加到 options.className 中,并将 options.close 设置为 false,表示不显示关闭按钮
  */

  const toastify = Toastify(options);
  toastify.showToast();
  /*
  使用 Toastify 构造函数创建一个通知实例,并调用 showToast 方法显示通知
  */

  if (userOptions.content) {
    removeTrigger = toastify.toastElement.querySelector(
      "[data-notification-remove]"
    );
    if (removeTrigger) {
      removeTrigger.addEventListener("click", () =>
        toastify.removeElement(toastify.toastElement)
      );
    }
  }
  /*
  检查 userOptions 中是否存在 content 属性,如果存在,则从通知元素中查找带有 data-notification-remove 属性的元素。如果找到该元素,则为其添加点击事件监听器,当点击时调用 removeElement 方法移除通知
  */
};

magics/clipboard.js

代码分析

export default (userOptions) => {
  const options = {
    content: userOptions.content,
    onSuccess: userOptions.success ?? function () {},
    onError: userOptions.error ?? function () {},
  };
    /*
    content: 需要复制的文本内容,从 userOptions 中获取。
    onSuccess: 成功回调函数,如果 userOptions 中没有提供,则使用一个空函数作为默认值。
    onError: 错误回调函数,如果 userOptions 中没有提供,则使用一个空函数作为默认值。
    */

  if (userOptions.content === "") return;

  if (typeof userOptions.content === "function") {
    userOptions.content = userOptions.content();
  }
  /*
  检查 userOptions.content 是否是一个函数。如果是函数,则调用该函数,并将返回值赋值给 userOptions.content
  */

  navigator.clipboard.writeText(options.content).then(
    function () {
      options.onSuccess();
    },
    function (err) {
      options.onError(err);
    }
  );
  /*
  使用 navigator.clipboard.writeText 方法将 options.content 复制到剪贴板。该方法返回一个 Promise,成功时调用 options.onSuccess 回调函数,失败时调用 options.onError 回调函数,并传递错误信息 err
  */
};