【Vue】使用vue封裝插件併發布到NPM

前言

多個平臺都用到的一些公共的功能,又不想用git的子模塊,就有了開發成npm插件的想法

放個效果圖
clipboard.pngjavascript

開始動手

由於需求很明確,就是作一個公共的回頂部的插件,因此就使用了簡潔版的webpack配置建立工程css

vue init webpack-simple x-backtotop
爲何用簡潔版,以及簡潔版和完整版有什麼區別, 能夠去這篇文章看看
  1. 運行腳本後會讓配置一些基礎信息,直接確認就行
    clipboard.png
  2. 看看初始化後的目錄結構

    clipboard.png

  3. 新建一個lib文件夾,存放咱們的插件

    clipboard.png

  4. index.jshtml

    import toTop from './x-backToTop.vue'
    
    const comment = {
      install: function (Vue) {
        Vue.component(toTop.name, toTop)
      }
    }
    // global 狀況下 自動安裝
    if (typeof window !== 'undefined' && window.Vue) {
      window.Vue.use(comment)
    }
    
    export default comment

    Tips:
    此處須要注意的是 install。 Vue的插件必須提供一個公開方法 install,該方法會在你使用該插件,也就是 Vue.use(yourPlugin)時被調用。這樣也就給 Vue全局注入了你的全部的組件。vue

  5. x-backtotop.vuejava

    <template>
      <div class="backToTop" :style="'z-index: ' + zIndex" @click="backToTop" v-show="bVisible">
        <div class="icon"></div>
      </div>
    </template>
    
    <script>
      export default {
        name: 'back-to-top',
        props: {
          zIndex: {
            type: Number,
            default: 9999
          },
          triggerHeight: {
            type: Number
          },
          smooth: {
            type: Boolean,
            default: true
          },
          scrollInterval: {
            type: Number,
            default: 10
          },
          scrollHeight: {
            type: Number,
            default: 100
          }
        },
        data () {
          return {
            interval: null, // 計時器
            bVisible: false // 按鈕顯示狀態
          }
        },
        methods: {
          resetToTop () {
            window.pageYOffset = 0;
            document.documentElement.scrollTop = 0;
            document.body.scrollTop = 0;
          },
          buttonStatus () {
            var currentHeight = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            let browserHeight = this.triggerHeight || (window.outerHeight / 4);
            this.bVisible = currentHeight > browserHeight;
          },
          backToTop () {
            if (this.smooth) {
              var that = this,
                _interval = this.scrollInterval,
                _height = this.scrollHeight;
              // 間隔{_interval}移動{_height}
              this.interval = setInterval(function () {
                that.smoothScroll(_height)
              }, _interval)
            } else {
              this.resetToTop();
            }
          },
          smoothScroll (y) {
            if (window.pageYOffset > 0) {
              window.pageYOffset = window.pageYOffset - y;
            }
            if (document.documentElement.scrollTop > 0) {
              document.documentElement.scrollTop = document.documentElement.scrollTop - y;
            }
            if (document.body.scrollTop > 0) {
              document.body.scrollTop = document.body.scrollTop - y;
            }
            var positionNow = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            if (positionNow <= 0) {
              clearInterval(this.interval);
              // 清除計時器後,所有重置爲零,預防回滾爲負數時,再也不顯示的bug
              this.resetToTop();
            }
          }
        },
        created () {
          window.addEventListener('scroll', this.buttonStatus)
        },
        destroyed () {
          window.removeEventListener('scroll', this.buttonStatus);
        }
      }
    </script>
    
    <style lang="scss" scoped>
      .backToTop {
        position: fixed;
        right: 100px;
        bottom: 150px;
        width: 40px;
        height: 40px;
        size: 40px;
        border-radius: 20px;
        cursor: pointer;
        transition: .3s;
        box-shadow: 0 0 6px rgba(0,0,0,.12);
        background-color: #FFF;
        overflow: hidden;
        .icon{
          position: absolute;
          margin: auto;
          left: 0;
          top: -8px;
          bottom: 0;
          right: 0;
          width: 0;
          height: 0;
          border-width: 8px;
          border-style: solid;
          border-color: transparent #0099CC transparent transparent;
          transform: rotate(90deg); /*順時針旋轉90°*/
        }
      }
      .backToTop:hover{
        box-shadow: 0 0 20px #000;
      }
    </style>

    這裏須要注意的有幾個點:
    1.這裏使用的是addEventListener而不是window.onscroll方法,由於寫成window.onscroll在離開當前界面的時候,還會觸發一次這個監聽,雖然沒有影響,可是由於不清楚緣由,因此使用addEventListener方式
    2.使用平滑的移動到頂端,因爲個人寫法是每隔一段時間減小定高,因此會出現負數的狀況,這個時候再怎麼滾動,都不會再變動這個值,因此在回到頂部後,將數值重置爲0
    3.這裏使用的是v-show而不是v-if,具體區別能夠查看下官方文檔,簡單來講就是常常須要變動的建議用v-showwebpack

  6. 插件自測試
    我這裏是直接在App.vue中引用,效果圖以下

    clipboard.png

  7. 修改webpack.config.js,注意的就幾個字段

    clipboard.png

  8. 修改package.json
    clipboard.png
  9. 發佈到npmgit

    這裏就不過多介紹怎麼建立npm帳號了,在項目根路徑下運行web

    npm login

    填寫用戶名密碼vue-cli

    whoami

    確認是否登錄成功,帳號是否正確npm

    npm publish

    最後進行發佈就行

發佈中可能遇到的問題

  1. no_perms Private mode enable, only admin can publish this module
    緣由:由於鏡像設置成淘寶鏡像了,設置回來便可
    方案:npm config set registry http://registry.npmjs.org
  2. npm publish failed put 500 unexpected status code 401
    緣由:通常是沒有登陸
    方案:從新登錄一次
  3. npm ERR! you do not have permission to publish 「your module name」. Are you logged in as the correct user?
    緣由:包名被佔用
    方案:修改包名便可

發佈後的一些修改

發佈完成後,想要本身npm run dev,發現報錯
clipboard.png
緣由是由於index.html中沒有修改資源路徑
修改前

<script src="/dist/build.js"></script>

修改後

<script src="/dist/backToTop.js" type="text/javascript"></script>

參考文章

我的疑問

若是想將別人已經發布在npm上的插件,封裝到本身插件內部使用,除了手動實現該功能,有別的什麼更好的方案嗎,但願大佬解惑

寫在最後

目前該插件已經發布到npm上了,歡迎你們使用

以上就是我將vue插件封裝併發布到npm的總結,若有什麼疑問歡迎評論留言。
相關文章
相關標籤/搜索