发布自己第一个npm 组件包(基于Vue的文字跑马灯组件)

一、前言

总结下最近工作上在移动端实现的一个跑马灯效果,最终效果如下:

888.gif
888.gif

印象中好像HTML标签的‘marquee’的直接可以实现这个效果,不过 HTML标准中已经废弃了‘marquee’标签
既然HTML标准已经废弃了这个标签,现在工作上用的是Vue,所以想着能不能自己也发布一个基于Vue的文字跑马灯组件包,这样别人可以通过npm install ...就可以用,想想还有点激动,于是开始我的第一个npm组件之旅!

二、用npm发布一个包

有点惭愧,之前通过npm install ...安装package包时,我是不知道package包存在哪里,在github上?折腾一番才知道是在npm上发布的。

2.1 npm发布包流程

  1. 进入官网,注册帐号

    如图
    如图

  2. 进入已经写好的组件, 登录npm帐号


    如图
    如图
  3. 执行npm publish,最先遇到问题好像是这个


    如图
    如图

    这里注意的是因为国内网络问题,许多小伙伴把npm的镜像代理到淘宝或者别的地方了,这里要设置回原来的镜像。npm config set registry=http://registry.npmjs.org

    后面又遇到

    如图
    如图

    这里我还特意查了下ENEEDAUTH错误,可是却没看后面的提示:You need to authorize this machine using 'npm adduser'
    所以这里需要npm adduser

    如图
    如图

    (发布的包的名字也要注意,有可能会有重名问题,像我这个组件包本来取名为vue-marquee,后面在npm上搜到已经有这个包了,不过他做的是垂直方向的跑马灯。所以我把这个为了区分这个组件包是水平方向的,改名为vue-marquee-ho)

三、基于Vue的文字跑马灯组件

大致了解怎么发组件包以后,我们再来看看需要发布出去的组件包怎么写的。

3.1初始化组件

这里我还是用到vue-cli,虽然有很多东西不需要,因为对这个比较熟悉,所以还是按照这个步骤来,初始化该组件

vue init webpack vue-marquee-ho
cd vue-marquee-ho
cnpm install // 安装依赖包
npm run dev // 启动服务

3.2修改配置文件

首先看package.json

  "name": "vue-marquee-ho",
  "version": "1.2.1",
  "description": "A Vue component to marquee",
  "author": "wangjuan",
  "private": false,
  "license": "MIT",
  "main": "dist/vue-marquee.min.js",
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "test": "node build/test.js"
  },
  "dependencies": {
    "vue": "^2.2.6"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/wj704/vue-marquee-ho.git"
  },

因为这个组件包是能公用的,所以"private": false,
然后 "main": "dist/vue-marquee.min.js", 这里的配置意思是,别人用这个包 import VueMarquee from 'vue-marquee-ho'; 时,引入的文件。
可以看出,这个vue-marquee-ho最终需要打包出一个js文件,所以我们需要修改webpack.prod.config.js文件

var webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  // output: {
  //   path: config.build.assetsRoot,
  //   filename: utils.assetsPath('js/[name].[chunkhash].js'),
  //   chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  // },
   output: {
    path: config.bundle.assetsRoot,
    publicPath: config.bundle.assetsPublicPath,
    filename: 'vue-marquee.min.js',
    library: 'VueMarquee',
    libraryTarget: 'umd'
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      // filename: utils.assetsPath('css/[name].[contenthash].css')
       filename: 'vue-marquee.min.css'
    }),
    new OptimizeCSSPlugin()
  ]
})
module.exports = webpackConfig

可以看到我的output输出配置改了下,然后有很多webpack.prod.config.js之前不需要的代码去掉了,再看下对应的config配置,文件是config/index.js

bundle: {
    env: require('./prod.env'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsPublicPath: '/',
    assetsSubDirectory: '/',
    productionSourceMap: true,
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    bundleAnalyzerReport: process.env.npm_config_report
  },

至此配置差不多修改好了。接下来我们看看实现关键功能的Marquee组件

3.3 Marquee组件

思路:<span>标签里的文字所占的宽度超过外面的div宽度时,增加一个内容相同的<span>标签。这里span标签设置为display: inline-block;,可以计算其宽度,把span标签外面的父元素设置为font-size: 0;display: inline-block;,父级元素的宽度即为两者宽度之和,也就是一个span标签宽度的两倍,然后将其父级元素通过CSS3动画设置:

@keyframes marquee {
    0%  { transform: translateX(0); }
    100% { transform: translateX(-50%);}
}

即可完美实现跑马灯效果。
具体代码:

<template>
  <div class="marquee-box">
    <div class="marquee-content" ref="out">
      <p :class="run?speed:''">
        <span class="text1" ref="in" >{{content}}</span>
        <span class="text2" v-if="showtwo||run">{{content}}</span>
      </p>
    </div>
  </div>
</template>

js:

<script>
  export default {
    name: 'VueMarquee',
    data (){
      return{
        run: false,
        pWidth: '',
      }
    },
    props: {
      content: {
        default: "暂无内容",
        type: String
      },
      speed: {
        default: 'middle',
        type: String
      },
      showtwo: {
        default: true
      }
    },
    mounted (){
      // let out = document.getElementById(this.pid.out).clientWidth;
      // let _in = document.getElementById(this.pid.in).clientWidth;
      var _this = this;
      this.$nextTick(()=>{
        let out = _this.$refs.out.clientWidth;
        let _in = _this.$refs.in.clientWidth;
        _this.run=_in>out?true:false;
      });
    }
  }
</script>

css:

<style>
  .marquee-box {
    height: 50px;
    line-height: 50px;
    color: #000;
    font-size: 24px;
    background-size: 24px 24px;
  }
  .marquee-content{
    overflow: hidden;
    width:100%
  }
  .marquee-content p{
    display: inline-block;
    white-space: nowrap;
    margin: 0;
    font-size: 0;
  }
  .marquee-content span{
    display: inline-block;
    white-space: nowrap;
    padding-right: 40px;
    font-size: 24px;
  }
  .quick{
    -webkit-animation: marquee 5s linear infinite;
    animation: marquee 5s linear infinite;
  }
  .middle{
    -webkit-animation: marquee 8s linear infinite;
    animation: marquee 8s linear infinite;
  }
  .slow{
    -webkit-animation: marquee 25s linear infinite;
    animation: marquee 25s linear infinite;
  }
  @-webkit-keyframes marquee {
    0%  { -webkit-transform: translate3d(0,0,0); }
    100% { -webkit-transform: translate3d(-50%,0,0); }
  }
  @keyframes marquee {
    0%  { transform: translateX(0); }
    100% { transform: translateX(-50%);}
  }
</style>

我们知道 webpack.base.conf.js 中入口文件默认指定为:

entry: {
    app: './src/main.js'
  },

所以,我们只需要将main.js引入Marquee.vue组件就可以。有两种方式引入:

import VueMarquee from './Marquee.vue'
export default VueMarquee;

// var VueMarquee = require('./Marquee.vue');
// module.exports = VueMarquee

注意import 和module.exports不要一起用,github看到其他人提交的组件是这两个一起用的,这样在windows下会报错,好像mac不会有问题。

3.4 打包生成dist/vue-marquee.min.js

通过npm run build 即可看到目录下生成了dist文件,dist文件里有四个文件,分别是:

vue-marquee.min.js
vue-marquee.min.js.map
vue-marquee.min.css
vue-marquee.min.css.map

我们知道有一个这样的文件.gitignore,里面包含npm install时,不会安装的东西,因为这里要用到dist文件,于是我把.gitignore 里的dist/去掉了。

.DS_Store
node_modules/

npm-debug.log*
yarn-debug.log*
yarn-error.log*

打包好了后,通过npm publish 提交到npm上

如图
如图

需要多次提交时注意修改package.json中的"version": "1.2.1", 我这里已经提交了21次了(捂脸哭(┬_┬))

四、使用组件

通过npm install vue-marquee-ho -s 安装到相应的项目下,安装成功如下图所示:

如图
如图

到项目中的node_modules/目录下将可以看到:

如图
如图

需要用到该组件时可以这样引入(注意引入样式)

import VueMarquee from 'vue-marquee-ho';
import Css from 'vue-marquee-ho/dist/vue-marquee.min.css'
export default {
  name: 'app',
  components:{
      "vue-marquee": VueMarquee
    },
}

看一个demo:

<template>
  <div id="app">
    <div class="marquee-wrap" style="width: 100px;"><vue-marquee content="33333" class="two"  :showtwo="false"></vue-marquee></div>
    <div class="marquee-wrap" style="width: 100px;"><vue-marquee content="22222" class="two"  :showtwo="false"></vue-marquee></div>
    <div class="marquee-wrap" style="width: 100px;"><vue-marquee content="1" class="two"  :showtwo="false"></vue-marquee></div>
    <router-view></router-view>
  </div>
</template>

<script>
import VueMarquee from 'vue-marquee-ho';
import Css from 'vue-marquee-ho/dist/vue-marquee.min.css'
export default {
  name: 'app',
  components:{
      "vue-marquee": VueMarquee
    },
}
</script>

效果:

如图
如图

五、总结

总算发布出去,能正常使用了!花了挺多时间的,虽然这个组件思路比较简单,但是说不定别人能用上呢。这个组件的雏形代码比现在多,不过之前在项目中直接引用也能正常使用。但是把他打包发布出去再使用的过程,出了很多问题,反复修改代码,精简代码,最终终于成功了!21次的提交记录,不容易呀,源代码地址:

vue-marquee-ho

希望能得到大家的star _

参考资料:
1、http://www.jianshu.com/p/36d3e0e00157
2、http://www.cnblogs.com/marymei0107/p/6339710.html
3、http://blog.csdn.net/gamesdev/article/details/49018629
4、https://segmentfault.com/a/1190000006250554
5、https://stackoverflow.com/questions/22636885/howto-publish-private-projects-to-sinopia-npm-adduser-for-private-registry-fail
6、http://www.mamicode.com/info-detail-1694072.html
7、http://blog.csdn.net/crper/article/details/50722753 (虽然调试技巧我还是没学会(✿◡‿◡))
8、https://github.com/xiaokaike/vue-color
9、https://github.com/li-xianfeng/vue-marquee

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容