当前位置: 移动技术网 > IT编程>开发语言>JavaScript > UI组件库框架设计

UI组件库框架设计

2020年09月21日  | 移动技术网IT编程  | 我要评论
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-press、、dumigitbook,开箱即用来一套就完事儿了

可以用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稍微简单了

在这里插入图片描述

在这里插入图片描述
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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网