npm 发布一个函数,支持 Vue3 hook 和 directive 使用

参考:https://www.bilibili.com/video/BV1dS4y1y7vd?p=41&vd_source=f37aed835423b3341b4323bc48e10402

实现一个函数同时支持 hook 和 directive 去监听 dom 宽高的变化

  1. 如何监听dom宽高变化
  2. 如何用vite打包库
  3. 如何发布npm

基本准备

  • 初始化 packge.json 文件: npm init -y

  • 下载 Vue、vite 插件:

    npm install vue vite -D
    

    注意:这个插件是专门为 Vue 提供的,所以没有必要安装插件的时候再去安装Vue

  • 初始化 ts 配置文件:tsc --init

  • 最终目录结构:
    在这里插入图片描述

监听dom宽高变化

  • 编写 hook 和 directive 函数: src/index.ts

    import type {App, DirectiveBinding} from 'vue'
    
    /**
     * 监听元素宽高变化
     * @param el {HTMLElement} - 需要监听宽高变化的元素
     * @param callback {Function} - 回调函数
     *  - entries {ResizeObserverEntry[]}
     *  - observer {ResizeObserver} ResizeObserver实例
     * @returns void
     */
    function useResizeObserver(el: HTMLElement, callback: (entries: ResizeObserverEntry[], observer: ResizeObserver) => void): void {
      // MutationsObserver API 侦听DOM树变化(子集、属性、增删改查)
      // Resize Observer API 侦听元素宽高变化
      // IntersectionObserver API 侦听元素交叉区域变化,也就是元素是否在视口内,常用于图片懒加载、虚拟列表
      // 三者使用上是一样的
      let resize = new ResizeObserver((entries) => {
        callback(entries, resize)
      })
      resize.observe(el)
    }
    
    /**
     * 编写Vue自定义指令
     * @param app {App} - Vue实例,通过 Vue.use(useResizeObserver) 安装的时候传入
     */
    const install = (app: App) => {
      app.directive('resize-observer', {
        mounted(el: HTMLElement, binding: DirectiveBinding) {
          useResizeObserver(el, binding.value)
        }
      })
    }
    
    useResizeObserver.install = install
    
    export default useResizeObserver
    

使用vite打包库

  • 配置 vite 打包信息: vite.config.ts

    import {defineConfig} from 'vite';
    
    // es module 语法
    // umd 支持 amd cmd cjs 全局变量模式
    export default defineConfig({
      // https://cn.vitejs.dev/config/build-options.html#build-lib
      build: {
        lib: {
          entry: 'src/index.ts', // 入口文件
          name: 'useResizeObserver', // 设置为你想要暴露的全局变量名
        },
        // 给 rollup 透传 external
        rollupOptions: {
          external: ['vue'], // 不想打包进库的依赖
          output: {
            // 提供一个全局变量
            globals: {
              useResizeObserver: 'useResizeObserver',
            }
          }
        }
      }
    })
    

    库模式
    请添加图片描述
    在这里插入图片描述

  • 声明库: index.d.ts

    import type { App } from 'vue'
    
    declare const useResizeObserver: {
      (el: HTMLElement, callback: (entries: ResizeObserverEntry[], observer: ResizeObserver) => void): void
      install: (app: App) => void
    }
    export default useResizeObserver
    
  • 配置 package.json

    {
      "scripts": {
        "build": "vite build"
      },
    }
    
  • build:npm run build
    执行成功后会生成dist目录,里面有两个文件
    在这里插入图片描述

发布npm

  • 配置 package.json: 注意 main 和 module 的文件要对应 dist 打包的结果文件。

    {
      "name": "dom-resize-vivian",
      "version": "0.0.1",
      "main": "dist/dom-resize-vivian.umd.js",
      "module": "dist/dom-resize-vivian.mjs",
      "files": [
        "dist",
        "index.d.ts"
      ],
    }
    

    通常,main 字段应该指向 CommonJS 规范的入口文件,而 module 字段应该指向 ES 模块规范的入口文件

    文件解释:

    • umd.js:支持 Common.js,也就是Node.js 规范。当我们 require 的时候,就会去找 main 对应的文件 dom-resize-vivian.umd.js

    • mjs:支持 import 和 export。当我们 import 的时候,就会去找 module 对应的文件 dom-resize-vivian.mjs

    files:要向npm发布的目录

    version: 版本号

  • npm 操作

    • 添加 npm 账号: npm adduser

    • 登录 npm:npm login

    • 发布:npm publish

      报错:在这里插入图片描述

      这是因为包名冲突,将 package.json 的 name 和 main 、module 都修改下,dom-resize 改成 dom-resize-vivian 再重新发布就能够成功了

使用 dom-resize-vivian

  • 下载依赖:npm i dom-resize-vivian
  • 编写测试代码
    • 测试 hook
      <template>
        <div class="resize" ref="resizeRef"></div>
      </template>
      
      <script setup lang="ts">
        import {ref, onMounted} from 'vue'
        import useResizeObserver from 'dom-resize-vivian'
      
        const resizeRef = ref<HTMLDivElement>()
        onMounted(() => {
          useResizeObserver(
            resizeRef.value as HTMLDivElement,
            (entries: ResizeObserverEntry[], observer: ResizeObserver) => {
              console.log(entries, observer)
            },
          )
        })
      </script>
      
      <style lang="scss">
        .resize {
          width: 200px;
          height: 300px;
          background-color: red;
          resize: both;
          overflow: hidden;
        }
      </style>
      
    • 测试自定义指令
      main.ts
      import useResizeObserver from 'dom-resize-vivian'
      const app = createApp(App)
      app.use(useResizeObserver)
      
      <template>
        <div class="resize" v-resize-observer="onChange"></div>
      </template>
      
      <script setup lang="ts">
        const onChange = (entries: ResizeObserverEntry[], observer: ResizeObserver) => {
          console.log(entries, observer)
        }
      </script>
      
      <style lang="scss">
        .resize {
          width: 200px;
          height: 300px;
          background-color: red;
          resize: both;
          overflow: hidden;
        }
      </style>
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值