本篇文章给大家带来了关于ui组件的相关知识,其中主要跟大家聊聊怎么从零开始搭建一套ui组件库,有代码示例,感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。
// 全局安装 vue-cli
npm install --global vue-cli
// 基于 webpack 创建一个的新项目
vue init webpack my-project
// 安装依赖
npm install
// 运行
npm run dev
安装过程相关选项如下:
我们默认安装jest做为我们组件库的单元测试框架,代码检查工具默认eslint
1.2 目录的优化
创建项目成功后,现在我们新项目的目录结构应该是这样的:
- build 打包相关目录以及配置
- config 配置文件目录
- node_modules 项目中安装的依赖模块
- src 源码目录
- static 静态文件目录
- test 单元测试目录
我们需要对现有目录做一些调整,首先我们接触过一些主流的ui组件库比如 vant/ant,我们知道在这些组件库的官网上都提供了很直观的示例页面,此时我们的组件库将src目录改名为examples,作为我们的官方示例目录。
另外我们新增一个packages目录用户存放我们的组件。
现在我们目录结构变成如下:
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const createLintingRule = () => ({
test: /.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('examples'), resolve('packages'),resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './examples/main.js' // 打包入口
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('examples'),
}
},
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /.js$/,
loader: 'babel-loader',
include: [resolve('examples'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
重新运行,编译通过。
1.3 组件文档的编写
在搭建完基础的代码环境后,我们要考虑我们新增组件的组件文档如何编写。
我们推荐使用 markdown来编写组件文档,然后我们如何在vue中使用markdown来编写我们的组件文档呢?这里我们推荐一个好用的工具。
vue-markdown-loader
1.3.1 安装方式
# vue1版本
npm i vue-markdown-loader@0 -D
# vue2版本
npm i vue-markdown-loader -D
npm i vue-loader vue-template-compiler -D
1.3.2 webpack 配置
我们在对webpack.base.conf作如下修改:
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module: {
rules: [
...,
{
test: /.md$/,
use: [
{
loader: 'vue-loader'
},
{
loader: 'vue-markdown-loader/lib/markdown-compiler',
options: {
raw: true
}
}
]
},
...
]
},
plugins: [new VueLoaderPlugin()]
1.3.3 编写组件文档
在我们配置完工具后,我们开始测试下组件文档的编写,
首先,我们在examples目录下新增一个docs文件夹,用于存放我们的组件文档。
新建一个test.md
# hello world
接下来我们在router文件夹新增一个 docs.js路由文件,用来存放我们组件文档的路径,并将它引入到根路由文件中。
const docs = [
{
path: '/test',
name: 'test',
component: r => require.ensure([], () => r(require('../docs/test.md')))
}
]
export default docs
浏览器中运行,我们便可以看到我们组件库的第一个组件文档...
<template>
<div :class="[size]" @click="click()">
<span><slot></slot></span>
</div>
</template>
<script>
/**
* 全局统一弹窗
*/
export default {
name: 'sgButton',
props: {
size: {
type: String,
default: ''
} // 按钮大小 :small large
},
methods: {
click () {
this.$emit('click')
}
}
}
</script>
<style scoped>
.container{
height: 50px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #ccc;
}
.container.small{
height: 40px;
}
.container.large{
height: 60px;
}
</style>
2.2 组件导出
然后我们要怎么用这个组件呢?
考虑的是组件库,所以我们需要让我们的组件支持全局引入和按需引入,如果全局引入,那么所有的组件需要要注册到Vue component 上,并导出:
我们需要在组件的入口文件index.js添加如下代码:
// 导入组件,组件必须声明 name
import sgButton from './src'
// 为组件提供 install 安装方法,供按需引入
sgButton.install = function (Vue) {
Vue.component(sgButton.name, sgButton)
}
// 导出组件
export default sgButton
然后我们在packages目录下新增入口文件,统一处理导出所有组件:
// 导入button组件
import sgButton from './sg-button'
// 组件列表
const components = [
sgButton
]
// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,那么所有的组件都会被注册
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,才能被 Vue.use() 方法安装
install,
// 以下是具体的组件列表
sgButton
}
2.3 组件引入
按需引入:
import sgUi from '../packages/index'
Vue.use(sgUi.sgButton)
全部引入:
import sgUi from '../packages/index'
Vue.use(sgUi)
2.4 测试代码
我们在examples目录的入口文件中全局引入了组件库
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import sgUi from '../packages/index'
Vue.config.productionTip = false
Vue.use(sgUi)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
然后我们编写一个vue页面来看看是否引入成功。
首先examples中新增pages目录,存放我们以后为每个组件单独编写的示例页面,新增examples/pages/buttonExample/index.vue 页面
<template>
<div class="container">
<sg-button>默认按钮</sg-button>
<sg-button :size="'large'">大按钮</sg-button>
<sg-button :size="'small'">小按钮</sg-button>
</div>
</template>
<script>
/**
* button 示例
*/
export default {
name: 'buttonExample',
methods: {
}
}
</script>
在这里我们直接调用了三种尺寸的button,运行看下效果:
// 本地编译组件库代码
yarn lib
// 登录
npm login
// 发布
npm publish
// 如果发布失败提示权限问题,请执行以下命令
npm publish --access public
单元测试
Vue Test Utils 安装
发表评论 取消回复