📦从0封装vue组件并使用npm发布

2,223 阅读3分钟

前言

我们经常会使用组件,同时为了学习和进步,我们也会经常造轮子,二次封装或创造新的组件,提供给其他开发者使用。

那我们应该如何发布 npm 包呢?这里我主要介绍一下从0封装一个Vue scrollTop回到顶部组件,并使用npm打包发布

开发vue组件

环境&包

  • vue-cli 3.x
  • throttle-debounce

封装一个 scrollTop 组件

目录创建

因为我一直比较喜欢兔子,所以我的前缀都是ra

vue create ra-scrolltop

删除大部分基本目录,在src目录下,创建main.jsra-scrolltop.vue文件,目录结构大致如下:

src
    - main.js
    - ra-scrolltop.vue
.gitignore
.npmignore
LICENCE
README.md
README.zh-CN.md
babel.config.js
package.json
vue.config.js
yarn.lock

组件开发

ra-scrolltop.vue添加如下代码 源码地址

<template>
  <transition name='scroll-to-top-fade'>
    <div
      v-show="visible"
      class="ra-scroll-to-top"
      :style="{
            bottom,
            right
        }"
      @click="scrollToTop"
    >
      <slot>
        <div class="default">
          <div class="scroll-to-top-circle">
            <div class="scroll-to-top-circle-triangle"></div>
          </div>
        </div>
      </slot>
    </div>
  </transition>
</template>

<script>
import { throttle } from 'throttle-debounce';
export default {
    name: 'ra-scrolltop',
    props: {
        bottom: {
            type: String,
            default: '40px'
        },
        right: {
            type: String,
            default: '30px'
        },
        speed: {
            type: String,
            default: 'average'
        },
        offset: {
            type: [String, Number],
            default: 600
        },
    },
    data() {
        return {
            visible: false,
            throttleHandler: null
        }
    },
    created() {
        try {
            if(['average', 'fast-to-slow','immediate'].indexOf(this.speed) === -1) {
                throw new Error("prop 'speed' must be 'average', 'fast-to-slow', or 'immediate'")
            }
        } catch (error) {
            // console.log(error)
        }
    },
    mounted() {
        window.speedScroll = () => {
            // current page scroll height
            let currentTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
            
            if(currentTop > 0) {
                // for compatibility
                window.requestAnimationFrame ?  window.requestAnimationFrame(window.speedScroll) : setTimeout(window.speedScroll, 16)
                switch(this.speed){
                    case 'average':
                        window.scrollTo(0, currentTop - 60)
                        break
                    case 'fast-to-slow':
                        window.scrollTo(0, currentTop - (currentTop / 5))
                        break
                    case 'immediate':
                        window.scrollTo(0,0)
                        break
                }
            }
        }
        this.throttleHandler = throttle(300, this.catchScroll)
        window.addEventListener('scroll', this.throttleHandler)
    },
    destroyed() {
        window.removeEventListener('scroll', this.throttleHandler)
    },
    methods: {
        scrollToTop() {
            window.speedScroll()
            // scrolled event is triggered after the page scrolling is finished
            this.$emit('scrolled')
        },
        /**
         * catch window scroll event 
         * 捕获 window scroll 事件
         * 这里主要需要对 visible进行处理,当距离页面高度为多少则隐藏 scroll 组件
         */
        catchScroll() {
            const scrolltop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
            this.visible = scrolltop > parseInt(this.offset)
        }
    }
}
</script>

<style scoped>
.ra-scroll-to-top {
  position: fixed;
  cursor: pointer;
  background: transparent;
}
.scroll-to-top-circle {
  position: relative;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: #f2f5f6;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.12);
}
.scroll-to-top-circle-triangle {
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -8px;
  margin-top: -12px;
  width: 0;
  height: 0;
  border: 8px solid transparent;
  border-bottom: 8px solid #579FF8;
}
</style>

然后我们需要修改main.js里面的内容

import RaScrolltop from './ra-scrolltop.vue'

// RaScrolltop.install = function (Vue) {
//     Vue.component(RaScrolltop.name, RaScrolltop)
// }

// 存储组件列表
const components = [
    RaScrolltop
]

const install = function (Vue) {
  if (install.installed) return
  components.map(component => Vue.component(component.name, component))
}

// 判断是否是直接引入文件
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

export default {
  install,
  RaScrolltop
}

npm 发布

要发布到 npm 上,我们首先需要修改 webpack 配置,这里需要修改vue.config.js

const path = require('path')
// const webpack = require('webpack')
module.exports = {
    publicPath: '/dist/',
    css: {
        extract: false
    },
    outputDir: path.resolve(__dirname, './dist'),
    configureWebpack: {
        output: {
            filename: 'ra-scrolltop.min.js',
            library: 'ra-scrolltop',
            libraryTarget: 'umd',
            umdNamedDefine: true
        }
    }
}

修改package.json文件:

{
  "name": "ra-scrolltop", // 项目名称,也是下载 npm 包的名称 yarn add <name>
  "version": "1.0.0", // 项目版本
  "main": "lib/ra-scrolltop.umd.min.js",
  "author": "邮箱|作者",
  "description": "描述",
  "keywords": [ // 项目关键字
    "vue",
    "scroll-top",
    "ra-scrolltop"
  ],
  "private": false,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lib": "vue-cli-service build --target lib --name ra-scrolltop --dest lib ./src/main.js",
    "lint": "vue-cli-service lint"
  },
  ...
  "repository": {
    "type": "git",
    "url": "项目的git地址"
  },
  "license": "MIT"
}

最后你需要修改你的markdown文件,你可以加上项目和包的说明,可以设置中文和英文的markdown,尽你所爱就好。

发布

发布命令其实就是两句话:

// 这里需要你有一个 npm 的账号
npm login   // 登陆 
npm publish // 发布

我建议使用 yarn,这样就不需要每次都重新输入账号和密码了

使用

成功发布到 npm 官网以后,你可以去npmJs查看你的包,与其他npm包一样,你可以直接使用npm yarn安装你的包。

yarn add ra-scrolltop