前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Vue CLI 3 封装组件

使用 Vue CLI 3 封装组件

原创
作者头像
kmokidd
发布2019-04-18 10:01:51
3K0
发布2019-04-18 10:01:51
举报
文章被收录于专栏:无人打理的花园

存个档

在时不时遇到”似曾相识“的 UI 模块时,我们下意识的反应一定是”不然把它抽成一个组件吧“。Element-UI 就是这样想法的集大成者。

感谢 Vue 的单文件组件,让开发者能把 HTML+CSS+JS 编写在同一个地方,方便开发、管理和引用。本文将要分享的是笔者使用 Vue CLI 3 打包-发布运营活动中常见的走马灯抽奖组件 — vmgr

组件的实现

实现过程概括来说,用 CSS Grid+CSS Variables 做布局;用 TweenJS 做动画。

如何打包

在执行打包之前,我们先明确组件是在哪里注册哪里调用的。

组件的入口文件为 index.js,在这里,完成组件的全局注册:

代码语言:javascript
复制
// index.js
import vmgr from "./components/vmgr.vue";
vmgr.install = Vue => Vue.component("vmgr", vmgr);

export default vmgr;

然后在应用入口文件 main.js 中完成调用:

代码语言:javascript
复制
// main.js
import Vue from "vue";
import App from "./App.vue";

// component
import vmgr from "./index";
Vue.use(vmgr);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

打包组件的方式有两种,一种是 lib,另一种是 Web Components。因为考虑到后续的使用场景基本是在 Vue Cli 框架下,所以我采用了打包成库(也就是第一种)方式。在 package.json 中增加一行命令:

代码语言:javascript
复制
...
"scripts": {
    ...
	"pkg": "vue-cli-service build --target lib --name vmgr --dest pkg ./src/index.js"
    ...
},
... 

由于在 vue.config.js 中将 css extract 设置为 false,所以样式被强制内联:

代码语言:javascript
复制
// vue.config.js
...
css: {:
    ...
    // 是否使用 css 分离插件 ExtractTextPlugin,采用独立样式文件载入,不采用 <style> 方式内联至 html 文件中
    extract: false,
    ...
 },
 ...

最终打包生成一下三份文件:

可以从官方文档上看到对于这三个文件的解释:

构建一个库会输出:

dist/myLib.common.js:一个给打包器用的 CommonJS 包 (不幸的是,webpack 目前还并没有支持 ES modules 输出格式的包)

dist/myLib.umd.js:一个直接给浏览器或 AMD loader 使用的 UMD 包

dist/myLib.umd.min.js:压缩后的 UMD 构建版本

Web Components 的构建方式请参考官方文档

优化打包体积

第一次打包以后,我发现组件的体积比预想中大了不少(此处应有图,但当时忘截了)。

因为使用了 TweenJS(不可避免的也要使用到 RAF 的兼容库),把它们一起打包进去了。如果使用的时候,页面上只有走马灯用上了 Tween 也还好说,但要是同一页面上其他地方也需要,就会导致重复引入代码冗余。于是这里我选择全局引入。

在 vue.config.js 中配置 configureWebpack

代码语言:javascript
复制
const webpack = require("webpack");

module.exports = {
	...
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                TWEEN: "@tweenjs/tween.js",
                requestAnimationFrame: "raf"
            })
        ]
    }
    ...   
} 

打包方案也要因地制宜。上述场景会发生是因为全局引入的 TweenJS 和 RAF 方便在页面上随处可用。也许与你的组件关联的第三方库只会服务于这个组件,其他地方不大可能调用到,那自然和组件一起封装会更合理。但这样会有一个问题,需要通知使用者该组件依赖 Tween 和 raf,使用者要提前引入这两个库。

发布到 npm 上

非常简单,顺带提一下,更新 ReadMe,在 package.json 中填上必要的发布信息:

代码语言:javascript
复制
// package.json
{
    "name": "vmgr",
    "version": "0.1.821",
    "private": false,
    "main": "dist/vmgr.umd.min.js",
    "description": "merry-go-round for activities",
    ...
}

写个 demo 试试你的组件

  1. vue create 命令创建一个空项目;
  2. tnpm install --save @tencent/vmgr , 记得在 vue.config.js 中引入 TWEEN 和 raf 哦(见“优化打包体积”);
  3. 在入口文件 main.js 中全局引入 @tencent/vmgr,或者在需要的 .vue 文件中通过 import vmgr from 'vmgr' 引入,之后添加 componet 结构并传入数据:
代码语言:javascript
复制
// App.vue --- 语法高亮没有支持 .vue,将就看
<template>
  <div id="app">
    <vmgr
      :count="count"
      :options="options"
      ref="vmgr1"
      :animOpt="animOpt"
    ></vmgr>
  </div>
</template>
<script>
export default = {
    name: "app",
    data() {
        return {
            count: 10,
            animOpt: {
            startIndex: 6,
            stopIndex: 1 // 以排好序的index来算 1~12
        },
        options: []
        };
    },
	....
}
</script> 
  1. 在走马灯的例子上,图片资源一般是走配置系统/后台拉取,所以用 mockjsaxios 模拟,安装成功后:
代码语言:javascript
复制
// mock.js
const Mock = require("mockjs");
const Random = Mock.Random;

const getParam = function(url) {
  let paramArr = url.slice(url.indexOf("?") + 1).split("&");
  let paramObj = {};
  paramArr.forEach(param => {
    let tmp = param.split("=");
    if (tmp[1]) paramObj[tmp[0]] = tmp[1];
  });

  return paramObj;
};

Mock.mock(/api\/data/, "get", (req, res) => {
  const paramObj = getParam(req.url);
  let list = [];
  for (let i = 0; i < paramObj.len; i++) {
    let listObj = {
      name: Random.csentence(2, 5),
      backgroundImage: Random.dataImage("80x80", Random.csentence(2, 5))
    };
    list.push(listObj);
  }

  return {
    data: list
  };
});



// App.vue
...
<script>
require("./mock.js");
import axios from "axios";

export default = {
    ....
    mounted() {
        axios({
            method: "get",
            url: "/api/data?len=12",
            responseType: "json"
        })
        .then(res => {
            this.options = res.data.data;
            setTimeout(() => {
                this.$refs.vmgr1.start();
            }, 0);
        })
        .catch(res => {
            console.log("error happens!");
            console.log(res);
		});
    }
}
</script>

成功调用的效果大致如下:

参考资料
  1. Vue CLI 3 webpack 相关
  2. npm-publish
  3. 在vue-cli项目下简单使用mockjs模拟数据
  4. 优化 Vue 项目编译文件大小

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件的实现
  • 如何打包
  • 优化打包体积
  • 发布到 npm 上
  • 写个 demo 试试你的组件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档