欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

UI组件库框架设计

程序员文章站 2022-06-23 18:06:44
Vue组件库搭建实践vue代码风格一个组件框架的设计:搭建框架–> 编写组件 --> 测试组件 --> 发布上线 --> site预览和文档目录结构└── build/ ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js ├── webpack.umd.conf.js ├── webpack.theme.conf.js ├── web...

vue代码风格

组件库的创建步骤:搭建框架–> 编写组件 --> 测试组件 --> 发布测试 --> 文档中心 --> 组件预览 --> 持续改进

开发环境配置

项目目录

└── build/
    ├── webpack.base.conf.js
    ├── webpack.dev.conf.js
    ├── webpack.prod.conf.js
    ├── webpack.umd.conf.js
    ├── webpack.theme.conf.js
    ├── webpack.style.conf.js
└── config/
    ├── index.env.js  
    ├── dev.env.js    
    ├── pro.env.js   
└── src/
    ├── button
    |   ├── index.scss
    |   ├── button.vue
    |   ├── index.js 
    ├── index.js
// src/button/index.js
import Button from './src/button';

/* istanbul ignore next */
Button.install = function (Vue) {
  Vue.component(Button.name, Button);
};

export default Button;
// src/index.js
import Button from '../src/button';

const components = [Button]

const install = function (Vue, opts = {}) { // eslint-disable-line no-unused-vars
  /* istanbul ignore if */
  if (install.installed) return;

  components.map(component => Vue.component(component.name, component));

  Vue.use(Loading.directive);
/*
  Vue.prototype.$loading = Loading.service;
  Vue.prototype.$msgbox = MessageBox;
  Vue.prototype.$alert = MessageBox.alert;
  Vue.prototype.$confirm = MessageBox.confirm;
  Vue.prototype.$prompt = MessageBox.prompt;
  Vue.prototype.$notify = Notification;
  Vue.prototype.$message = Message;
*/
};

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}

export default {
  version: '1.0.0',
  install,
  version,
  Button
};

打包配置

最后输出:
1、你可能需要提供不同模块类型的包:commonjs、umd、es模块;
2、你需要对各组件(js/css)单独打包处理,方便用户按需加载;
3、需要打包一份全部的组件js、css样式(index.css/handy.js/handy.min.js)

handy
└── es/    # es module规范的文件
    ├── button
    |   ├── index.css
    |   ├── index.js
└── lib/    # commonjs规范的文件
    ├── button
    |   ├── index.css
    |   ├── index.js
    ├── utils
    ├── index.css
    ├── index.js
    ├── handy.js
    ├── handy.min.js
└── types  
    ├── index.d.ts
    ├── notify.d.ts
└── package.json   // "typings": "types/index.d.ts", package中字段typing或types,两者是等价的
"build:umd": "cross-env NODE_ENV=production webpack --config ./build/webpack.umd.conf.js",
"build:lib": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.conf.js",
"build:theme": "cross-env NODE_ENV=production webpack --config ./build/webpack.theme.conf.js",
"build:style": "cross-env NODE_ENV=production webpack --config ./build/webpack.style.conf.js",

package.json 中,“main”: "dist/index.js"就是库使用的文件(这个文件符合 commonjs 的模块规范)
“module”: “es/index.js” 提供一个ES Module规范的使用文件,就不需要将commonjs转为ES Module

如果开发多端组件库,还要配置打包ios、android、rn

加载

  • 全局加载
import handyVue from '@handyu/handy-vue';
import '@handyu/handy-vue/handy-vue.default.css'; // 引入全局样式
Vue.use(handyVue);
// plugin的作用实际就是转换成require,就是
import { Button } from 'components'

// 转换成
var button = require('components/lib/button')
require('components/lib/button/style.css')
//  .babelrc 
{
  // ...
  "plugins": [["component", {
      "libraryName": "@handyu/handy-vue",
      "styleLibraryName": "theme"
    }
  ]]
}

// main.js
import { Button, Alert } from '@handyu/handy-vue'
Vue.use(Button)
Vue.use(Alert)
  • 也可以通过cdn引入umd模块
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/@handyu/handy-vue/handy-vue.default.css">
  <script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>
  <script src="https://unpkg.com/@handyu/handy-vue/handy-vue.umd.js"></script>
</head>
<body>
  <div id="app">
      <ha-button theme="primary">普通按钮</ha-button>
  </div>
</body>
<script>
  new Vue({
    el: '#app'
  })
</script>
</html>

组件编写

  • 基础UI组件:最小化的组件,不依赖其他组件
  • 复合组件:由多个组件组成,依赖现有组件
  • 业务组件:带有业务功能的大量重复使用组件
    业务组件,可能在组件中内置一些内容:用户名、密码的前端校验规则;对后端响应或错误规则的响应处理
    对于数据的请求和处理的方式,决定它是否能成为一个业务组件
└── src/
    ├── button
    |   ├── __test__
    |		 ├── index.spec.js
    |   ├── style
    |   ├── index.ts 
    |   ├── index.vue
    |   ├── button.md
// button/src/index.vue
<template>
  <div>
    <button class="ha-button">{{msg}}</button>
  </div>
</template>

<script>
  export default {
    name: "Button",
    props: {
      msg: String
    }
  }
</script>

测试环境

TDD(Test-Driven Development):测试驱动开发,注重输出结果。
BDD(Behavior Driven Development):行为驱动开发,注重测试逻辑。

使用TDD:先写测试再去开发组件(测试驱动开发)

// 安装
npm i jest @types/jest  @vue/test-utils@^2.0.0-beta.2  vue-jest@^5.0.0-alpha.1  -D

// package.json
"test": "jest --config jest.config.js",

// jest.config.js
module.exports = {
   clearMocks: true,
  moduleFileExtensions: ['vue', 'js', 'json', 'jsx', 'ts', 'tsx', 'node'],
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
    '^.+\\.(js|jsx|ts|tsx)?$': 'babel-jest'
  },
  testEnvironment : 'jsdom',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  snapshotSerializers: ['jest-serializer-vue'],
  transformIgnorePatterns: ['<rootDir>/node_modules/'],
  testMatch: [
    // '**/test/**/*.js',
    '<rootDir>/src/**/**/*.spec.js',
    '<rootDir>/src/**/**/*.spec.ts'
  ],
};
// button/__test__/index.spec.js
import {shallowMount} from '@vue/test-utils'
import Button from '../src/index.vue'

describe('Button.vue', ()=>{
  it('renders props.msg when passed', ()=>{
    const msg = 'new button'
    const wrapper = shallowMount(Button, {
      propsData: { msg }
    })
    expect(wrapper.findAll('.ha-button').length).toBe(1)
  })
})

// 测试
npm run test

发布包

如果发布带@xxx/xxx的为范围内的包,需要注册一个npm用户帐户,且创建一个npm Org组织

// package.json
"name": "@abc/vue", // @组织名/包名
"version": "1.0.0-alpha.0", // 每一次的版本都要比上一次高
"main": "handy-vue.umd.js",  // umd指定的位置
"module": "lib/handy-vue.common.js", // es module指定的位置
"style": "handy-vue.default.css", // 样式指定的位置
"typings": "types/index.d.ts", // 声明文件指定的位置
/* "files": [ // files 字段指定工程目录下面哪些文件需要发布到npm
    "index.js",
    "index.d.ts",
    "README.md"
]*/

npm login  // 输入账号名、密码、邮箱
npm publish  
npm publish --access public

发布完就可以上npm查看到刚发布的包了
发布范围内的公共包(即组织包)

创建文档

图省事的,可以使用市面上的 vue-pressmarkdown-itdumigitbook,开箱即用来一套就完事儿了

可以用webpack搭建一套可扩展的网站,网站需要展示两个模块:

  • PC端展示组件API文档
  • 移动端的展示组件Demo

PC端展示组件API文档:
1)可以使用vue-cli构建一个带router、store、ts的项目,把src改名为site挪回ui组件库里,其余的删掉
2)pc端共有三个部分,头部、侧边目录、内容区域(读取md文件作为内容和展示移动端预览的区域)

  • 侧边栏:构建json数据结构作为目录的数据,使用v-for循环获取目录
  • 内容区域:点击侧边栏目录时,跳转到对应组件内容页面,再把md文件当作组件展示出来(重点是md的loader处理,可以自己造一个)
  • 移动端展示:获取点击后传过来的组件名,拼接url地址,使用iframe展示移动端页面

3)文档的响应式处理:判断是不是移动设备,如果是就跳转到移动端的页面

  <script>
    var CONFIG = {
      pathname: '<%= htmlWebpackPlugin.options.pathname %>',
    };
    if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
      window.location.href = CONFIG.pathname + 'demo.html';
    }
  </script>

移动端部分的构建和pc端的一样,只是比pc稍微简单了

UI组件库框架设计

UI组件库框架设计
github参考

其他

扩展:

  1. peerDependencies可以理解为同伴依赖,它表示包和包之间的宿主关系。主要用于npm插件告诉使用者, npm插件本身依赖哪些模块, 并且需要安装它。
// ant-design 这个表明使用ant-design 中的react建议大于等于16.0.0版本
"peerDependencies": {
    "react": ">=16.0.0",
    "react-dom": ">=16.0.0"
}
  1. vue-cli-service机制

本文地址:https://blog.csdn.net/qq_14993375/article/details/108468152

相关标签: js