• Vue发布自定义组件库


    本文配套视频教程
    在这里插入图片描述

    NPM源的切换

    • 我们自定义的包只能发布到NPM官方源,国内镜像只是官方源的副本
    • 因此我们的用户注册和包的发布,都必须先切换到官方源
    • 切换方式请参见 NPM注册源的配置

    注册NPM用户

    • 进入 npm 官网注册账号
    • 注册地址:www.npmjs.com/
    • 注册过程中需要安装一个一次性验证器,以生成一个6位数动态校验码(OTC),笔者使用的是Google的Authenticator手机APP;

    登录NPM账号

    npm login
    
    • 1

    后续需要输入用户名、密码、以及一次性校验码,请使用上一步中的校验器生成;

    创建工程

    手动或者是使用命令创建均可

    mkdir jdzb-ui && cd jdzb-ui
    
    // 如果将来 npm i jdzb-ui
    npm init -y
    
    // 如果将来 npm i @steveouyang/jdzb-ui
    npm init --scope=steveouyang
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    配置package.json,请根据自己的项目细节自行配置

    {
      "name": "jdzb-ui",
      "version": "1.0.0",
      "description": "京东正版UI",
      "main": "src/main.js",
      "author": "steve ouyang",
      "scripts": {
        "dev": "npx rollup -wc rollup.config.dev.js",
        "build": "npx rollup -c rollup.config.js"
      },
      "license": "ISC",
      "devDependencies": {
        "@rollup/plugin-babel": "^5.3.1",
        "@rollup/plugin-commonjs": "^22.0.0",
        "@rollup/plugin-json": "^4.1.0",
        "@rollup/plugin-node-resolve": "^13.3.0",
        "rollup-plugin-scss": "^3.0.0",
        "rollup-plugin-vue": "^6.0.0"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    自定义组件库案例

    项目地址

    项目结构

    ── jdzb-ui
        |—— node_modules
        |—— lib
        |—— src
             |—— main.js
             |—— components
                     |—— Elevator
                             |—— index.vue
                             |—— index.css
                             |—— index.js
             |—— css
        |── package.json
        |—— rollup.config.js
        |—— README.md
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    组件定义

    index.vue

    <template>
      <div class="elevator elevator_recommend" :class="{ elevator_fix: fix }">
        <svg
          class="svgcont"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          style="display: none"
        >
          <defs>
            <symbol id="icon_timline" viewBox="0 0 16 16">
              <path
                d="M12.986 5.582a.505.505 0 0 0 .25-.063c.34-.188.364-.738.056-1.252-.235-.391-.59-.643-.905-.643a.511.511 0 0 0-.251.063c-.338.188-.363.738-.055 1.252.234.391.59.643.905.643m-9.975 0c.317 0 .674-.252.91-.643.31-.514.286-1.064-.056-1.253a.52.52 0 0 0-.252-.062c-.317 0-.674.252-.91.643-.31.514-.285 1.064.056 1.252.076.042.16.063.252.063m10.779.956a.372.372 0 0 0-.295-.024.387.387 0 0 0-.225.201c-.013.025-.315.609-1.062 1.191-.738.573-2.062 1.26-4.185 1.279h-.075c-2.076 0-3.384-.653-4.116-1.2-.779-.581-1.094-1.177-1.097-1.182a.395.395 0 0 0-.23-.199.371.371 0 0 0-.293.031.42.42 0 0 0-.161.549c.039.077.413.772 1.316 1.45.826.622 2.29 1.363 4.573 1.363l.089-.001c2.331-.019 3.81-.793 4.641-1.439.862-.672 1.225-1.345 1.292-1.475a.419.419 0 0 0-.172-.544m-5.848-.124c1.092 0 2.268-.218 2.268-.697S9.034 5.02 7.942 5.02c-1.071 0-2.152.216-2.152.697s1.081.697 2.152.697m4.086 4.647c-1.004.574-1.052 1.597-1.015 2.223a.098.098 0 0 1-.113.104c-.693-.096-1.161-.407-1.757-.943a1.343 1.343 0 0 0-.933-.351l-.21.003c-3.809 0-6.897-2.458-6.897-5.489 0-3.032 3.088-5.489 6.897-5.489 3.808 0 6.896 2.457 6.896 5.489 0 1.834-1.129 3.461-2.868 4.453M8 0C3.589 0 0 2.931 0 6.533c0 3.603 3.589 6.533 8 6.533l.224-.002c.102 0 .204.033.272.099 1.239 1.205 2.568 1.323 3.303 1.336a.3.3 0 0 0 .303-.342c-.087-.613-.318-1.813.477-2.263C14.722 10.684 16 8.677 16 6.533 16 2.931 12.411 0 8 0"
              ></path>
            </symbol>
            <symbol id="icon_feedback" viewBox="0 0 16 16">
              <path
                d="M1.4,15l0-1l14,0v1H1.4z M2.5,13H2l0-0.5c0-0.1,0-0.2,0-0.3c0-0.3,0.1-0.8,0.2-1.3c0.1-0.7,0.4-1.7,0.4-2 C2.7,8.7,2.8,8.4,3,8.3l8-8c0.3-0.3,0.8-0.3,1.1,0l2.7,2.7c0.3,0.3,0.3,0.8,0,1.1l0,0l-8,8c-0.1,0.1-0.4,0.3-0.6,0.4 c-0.7,0.2-1.4,0.3-2.1,0.4c-0.5,0.1-1,0.2-1.3,0.2C2.7,13,2.6,13,2.5,13z M11.6,1.1L3.7,9c0,0.1-0.1,0.1-0.1,0.2 c-0.1,0.2-0.3,1.1-0.4,1.9c-0.1,0.3-0.1,0.6-0.1,0.9c0.3,0,0.6-0.1,0.9-0.1c0.7-0.1,1.3-0.2,2-0.4c0,0,0.1-0.1,0.2-0.1L14,3.5 L11.6,1.1z M14.1,3.3C14.1,3.3,14.1,3.3,14.1,3.3L14.1,3.3z M11.4,0.9C11.4,0.9,11.4,0.9,11.4,0.9L11.4,0.9z"
              ></path>
            </symbol>
          </defs>
        </svg>
    
        <ul class="elevator_list">
          <template
            v-for="({ name, imgSrc, link, icon, floorRef }, index) in floors"
            :key="index"
          >
            <li
              v-if="name && !link"
              class="elevator_item"
              @click="navToFloor(floorRef)"
            >
              <a
                class="elevator_lk"
                href="javascript:void(0);"
                clstag="h|keycount|core|elvt_01"
                tabindex="-1"
                aria-hidden="true"
              >
                <div>
                  <span class="elevator_lk_bg"></span>
                  <span class="elevator_lk_txt">{{ name }}</span>
                </div>
              </a>
            </li>
    
            <li
              v-else-if="imgSrc"
              class="elevator_item"
              @click="navToFloor(floorRef)"
            >
              <a
                class="elevator_lk elevator_promotional"
                href="javascript:void(0);"
                clstag="h|keycount|core|elvt_08"
                tabindex="-1"
                aria-hidden="true"
                @mouseover="imgHovered = true"
                @mouseout="imgHovered = false"
              >
                <img v-if="imgHovered" :src="imgSrc[1]" alt="" />
                <img v-else :src="imgSrc[0]" alt="" />
              </a>
            </li>
    
            <li v-else class="elevator_item">
              <a
                class="elevator_lk elevator_lk2"
                :href="link"
                target="_blank"
                clstag="h|keycount|core|elvt_06"
                ><span class="elevator_lk_bg"></span>
                <svg>
                  <use :xlink:href="icon"></use>
                </svg>
                <span class="elevator_lk_txt">{{ name }}</span>
              </a>
            </li>
          </template>
        </ul>
        <a
          class="elevator_totop"
          href="javascript: void(0);"
          clstag="h|keycount|core|elvt_07"
          tabindex="-1"
          aria-hidden="true"
          @click="toTop"
        >
          <span class="elevator_totop_icon"></span>
          <span class="elevator_totop_txt">顶部</span>
        </a>
      </div>
    </template>
    
    <script setup>
    import { reactive, toRefs } from "vue";
    
    /* 无法使用模块化 */
    // import { yScrollTo } from "../utils/scrollUtil.js";
    // import "../css/first-screen.chunk.css"
    // import "../css/index.chunk.css"
    
    let timer = null;
    const yScrollTo = (y, timespan = 1000) => {
      if (timer) clearInterval(timer);
    
      let current = document.documentElement.scrollTop;
      let step = (y - current) / (timespan / 40);
    
      timer = setInterval(() => {
        if (Math.abs(y - current) >= Math.abs(step)) {
          current += step;
          window.scrollTo(0, current);
        } else {
          clearInterval(timer);
          timer = null;
          window.scrollTo(0, y);
        }
      }, 40);
    };
    
    const name = "Elevator";
    
    const { fix, floors, scrollSpeed } = defineProps({
      fix: Boolean,
      floors: Array,
      scrollSpeed: Object,
    });
    
    const { imgHovered } = toRefs(
      reactive({
        imgHovered: false,
      })
    );
    
    const navToFloor = (ref) => {
      // console.log("navToFloor", ref);
      // window.scrollTo(0,document.documentElement.scrollTop + ref.$el.getBoundingClientRect().top - 50)
      yScrollTo(
        document.documentElement.scrollTop +
          ref.$el.getBoundingClientRect().top -
          50,
        scrollSpeed.toFloor || 1000
      );
    };
    
    const toTop = () => {
      yScrollTo(0, scrollSpeed.toTop || 500);
    };
    </script>
    
    <style lang="scss" scoped>
    .elevator_promotional:hover img {
      z-index: 2;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157

    index.css内容较多,请移步源码地址自行查阅

    index.js

    import Elevator from "./index.vue";
    
    Elevator.install = function (Vue) {
      Vue.component(Elevator.name, Elevator);
    };
    
    export default Elevator;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    main.js

    import Elevator from "./components/Elevator/index.js";
    
    import "./components/Elevator/index.css";
    // import "./css/first-screen.chunk.css"
    // import "./css/index.chunk.css"
    
    import { version } from "../package.json";
    
    const components = [Elevator];
    
    const install = function (Vue) {
      components.forEach((component) => {
        Vue.component(component.name, component);
      });
    };
    if (typeof window !== "undefined" && window.Vue) {
      install(window.Vue);
    }
    export { Elevator, install };
    export default { version, install };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    执行打包

    npm i
    npm run build
    
    • 1
    • 2

    打包成功后会在lib目录下生成bundle.jsbundle.cjs.js两个文件,即代码中真正使用的文件

    发布包

    npm publish
    
    // 开源发布
    npm publish --access=public
    
    • 1
    • 2
    • 3
    • 4

    取消发布

    npm unpublish jdzb-ui --force
    
    • 1

    一些可能的报错处理

    在Vue项目中使用自定义组件库

    npm i jdzb-ui
    
    • 1

    入口文件main.js

    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    /* 全局引入 main.js */
    import JdzbUI from "jdzb_ui";
    
    // 引入全局样式
    // import "jdzb-ui/lib/first-screen.css";
    
    createApp(App).use(store).use(router).use(JdzbUI).mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在组件中使用自定义组件

    import { Elevator } from "jdzb_ui";
    
    • 1

    在模板中部署

    <!-- Elevator -->
    <Elevator
    :fix="fixTitleBar"
    :floors="floors"
    :scrollSpeed="{ toFloor: 200, toTop: 500 }"
    ></Elevator>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    “这不需要测试,肯定是好的,不必担心”

    在这里插入图片描述

  • 相关阅读:
    【代码随想录】算法训练计划15
    win10怎么设置不睡眠熄屏?win10设置永不睡眠的方法
    Java案例找素数(三种方法)
    vs code
    Java日期处理
    斗鱼 H5 直播原理解析,它是如何省了 80% 的 CDN 流量?
    图_图的存储_添加边_图的遍历_DFS_树的重心_BFS_图中点的层次
    js实现瀑布流
    kubernetes之crontab
    聚焦养老主业,平安养老险构建一体化养老生态圈
  • 原文地址:https://blog.csdn.net/u010986776/article/details/126516477