怎么搭建一个vue指令库并发布到 npm 上

227 阅读5分钟

说在前面

使用vue框架开发的同学们,在开发过程中应该或多或少都会使用到自定义指令吧,大家平时都是怎么管理自己的vue指令的呢?每新建一个新项目就复制一份代码过去?试试来搭建一个vue指令库吧

vue指令有什么好处

Vue 指令是 Vue.js 框架提供的一种特殊属性,用于在 DOM 元素上添加交互行为和样式。使用 Vue 指令可以带来以下好处:

1. 与 DOM 分离

指令将 DOM 操作和交互逻辑与组件分离开来,提高了代码的可读性和可维护性。指令可以将复杂的 DOM 操作封装到一个简单的指令中,使组件代码更加简洁清晰。

2. 优化可重用性

指令可以被多个组件共享和重用,减少了重复编写相似代码的工作量。通过将常用的交互行为封装成指令,可以在不同的组件中快速应用,并且可以根据需要进行定制和扩展。

3. 提升开发效率

Vue 指令提供了一种声明式的方式来处理 DOM 操作和交互行为,使开发人员可以直观地理解和编写交互逻辑。相比手动操作 DOM,使用指令可以节省大量的开发时间和工作量。

4. 增强可维护性

通过将通用逻辑抽象成指令,可以减少重复代码的编写,降低代码量,提高代码的可维护性和可读性。

搭建步骤

要搭建一个 Vue 指令库并发布到 npm 上,可以按照以下步骤进行操作:

一、安装vue环境

已有的可以跳过

npm i vue -g 
npm i vue-cli -g

二、创建一个vue项目

vue create .

文件目录如下图:

在这里插入图片描述

三、调整目录

1、packages

增加一个packages目录,用来存放我们的组件模块

2、examples

修改原来的src目录为examples,用于运行展示代码

四、文件调整

1、vue.config.js

修改项目入口

const path = require('path')
function resolve(dir) {
  return path.join(__dirname, dir)
}
module.exports = {
  // 修改 src 为 examples
  pages: {
    // lintOnSave: false,
    index: {
      entry: "examples/main.js",
      template: "public/index.html",
      filename: "index.html"
    }
  },
  // 组件样式内联
  css: {
    extract: false
  },
  // 扩展 webpack 配置,使 packages 加入编译
  chainWebpack: config => {
    config.resolve.alias
      .set('@', resolve('examples'))
      .set('~', resolve('packages'))
  }
};

五、将指令代码放到packages目录中

完整组件目录如下,指令文件我们放在directives目录下。

image.png

这里以一个3D旋转指令为例来给大家介绍一下:

package/directives/JRotate3D.js

指令逻辑代码编写

export default {
    // 当被绑定的元素插入到 DOM 中时
    inserted: function (el) {
        let startX,
            startY,
            currentX = 0,
            currentY = 0;
        el.style.display = "inline-block";
        el.style.cursor = "pointer";
        // 绑定 mousedown 事件,在鼠标按下时开始拖拽
        el.addEventListener("mousedown", function (event) {
            event.preventDefault();
            startX = event.pageX - currentX;
            startY = event.pageY - currentY;
            // 绑定 mousemove 事件,在鼠标移动时旋转元素
            document.addEventListener("mousemove", onMouseMove);
            // 绑定 mouseup 事件,在鼠标松开时结束拖拽
            document.addEventListener("mouseup", onMouseUp);
        });

        // 针对手机端还需要绑定 touchstart,touchmove 和 touchend 事件
        el.addEventListener("touchstart", function (event) {
            event.preventDefault();
            startX = event.touches[0].clientX - currentX;
            startY = event.touches[0].clientY - currentY;
            document.addEventListener("touchmove", onTouchMove);
            document.addEventListener("touchend", onTouchEnd);
        });

        // 定义鼠标移动时的方法
        function onMouseMove(event) {
            event.preventDefault();
            currentX = event.pageX - startX;
            currentY = event.pageY - startY;
            applyTransform(el);
        }

        // 定义鼠标松开时的方法
        function onMouseUp() {
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("mouseup", onMouseUp);
        }

        // 定义触摸移动时的方法
        function onTouchMove(event) {
            event.preventDefault();
            currentX = event.touches[0].clientX - startX;
            currentY = event.touches[0].clientY - startY;
            applyTransform(el);
        }

        // 定义触摸结束时的方法
        function onTouchEnd() {
            document.removeEventListener("touchmove", onTouchMove);
            document.removeEventListener("touchend", onTouchEnd);
        }

        // 应用 transform 属性以旋转元素
        function applyTransform(el) {
            el.style.transform = `rotateX(${currentY}deg) rotateY(${currentX}deg)`;
        }
    },
};

packages/index.js

// 使用 require.context 动态导入所有指令
const requireDirective = require.context(`./directives/`, false, /\.js$/);
// 定义 install 方法,接收 Vue 作为参数。
const install = function (Vue) {
    if (install.installed) return;
    requireDirective.keys().forEach((directiveFileName) => {
        const moduleName = directiveFileName.replace(/^\.\/(.*)\.\w+$/, "$1");
        const directiveConfig = requireDirective(directiveFileName);
        Vue.directive(moduleName, directiveConfig.default);
    });
};
// 判断是否是直接引入文件
if (typeof window !== "undefined" && window.Vue) {
    install(window.Vue);
}

export default {
    // 导出的对象必须具有 install,才能被 Vue.use() 方法安装
    install,
    // 以下是具体的组件列表
    ...components,
};

六、测试指令

main.js引入指令

import jvuewhell from './../packages/index'
// 注册指令库
Vue.use(jvuewhell)

在App.vue中使用指令

<img
    v-JRotate3D
    alt=""
    src="https://gitee.com/jyeontostore/img-bed/raw/master/img/1699276911873.jpg"
/>

3D翻转指令.gif

体验地址

jyeontu.xyz/jvuewheel/#…

七、上传到npm

测试通过了之后也就到了最后的一步,将我们的组件上传到npm库上去。

package.json信息填写

在script中加上打包命令:

"scripts": {
    "lib": "vue-cli-service build --target lib --name jvuewhell --dest lib packages/index.js"
},

填写好基本信息

  "name": "@jyeontu/jvuewhell",
  "version": "0.1.0",
  "author": "JYeontu",
  "license": "MIT",
  "description":"vue组件库封装",
  "main": "lib/jvuewhell.umd.min.js",
  "keyword": "vue components",
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "lib": "vue-cli-service build --target lib --name jvuewhell --dest lib packages/index.js"
  },

打包

npm run lib

设置.npmignore,只上传我们需要的文件

examples/
packages/
public/
node_modules/
dist/

登录npm

在cmd中输入命令 npm login(注意不要使用其他源)

npm login

需要先注册账号,没有的可以先去官网注册

npm官网

发布

npm publish

因为我的name为'@jyeontu/jvuewhell',所以需要使用下面命令

npm publish --access public

发布成功之后就可以上自己的npm库里查看了。

源码

一、gitee

gitee 地址:gitee.com/zheng_yongt…

文档地址:jyeontu.xyz/jvuewheel/#…

二、公众号

关注公众号『前端也能这么有趣』发送 组件库即可获取源码。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。