├── .jscpd ├── hashes_css │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 ├── hashes_scss │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 ├── statistic │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 ├── hashes_markdown │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 ├── hashes_markup │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 └── hashes_javascript │ ├── LOCK │ ├── CURRENT │ ├── LOG │ └── MANIFEST-000002 ├── static ├── img │ ├── logo.png │ ├── gakki.jpg │ ├── loading.gif │ └── u=4046980169,286278015&fm=26&gp=0.jpg └── fonts │ ├── montserrat-regular-webfont.woff2 │ └── montserrat-semibold-webfont.woff2 ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── src ├── components │ ├── common │ │ ├── utils.js │ │ ├── demo-common.js │ │ ├── demo-row.vue │ │ └── demo-block.vue │ ├── mixins │ │ ├── iconMap.js │ │ └── popupbox.js │ ├── Hover-tip │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Breadcrumb │ │ ├── README.md │ │ ├── index.scss │ │ ├── index.js │ │ └── demo.vue │ ├── icon │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Date-picker │ │ ├── README.md │ │ ├── panel │ │ │ ├── basic.js │ │ │ └── panel.js │ │ ├── demo.vue │ │ └── CONST.json │ ├── button │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── Table │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Slider │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── Scroll-view │ │ ├── README.md │ │ ├── demo.vue │ │ ├── bar.vue │ │ └── index.vue │ ├── Input │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── Message │ │ ├── README.md │ │ ├── index.js │ │ ├── demo.vue │ │ └── message.vue │ ├── Pagination │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── Radio-group │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Checkbox-group │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Input-number │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── File-reader │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Message-box │ │ ├── README.md │ │ ├── index.js │ │ ├── messagebox.vue │ │ └── demo.vue │ ├── toast │ │ ├── README.md │ │ ├── index.js │ │ ├── demo.vue │ │ └── toast.vue │ ├── Tabs │ │ ├── README.md │ │ ├── index.vue │ │ └── demo.vue │ ├── Tab │ │ └── index.vue │ ├── Dropdown │ │ ├── README.md │ │ └── index.vue │ ├── Table-column │ │ └── index.vue │ ├── Select │ │ ├── README.md │ │ ├── demo.vue │ │ └── index.vue │ ├── utils.js │ ├── Dropdown-option │ │ └── index.vue │ ├── Radio │ │ └── index.vue │ ├── Option │ │ └── index.vue │ └── Checkbox │ │ └── index.vue ├── utils │ └── index.js ├── assets │ └── styles │ │ ├── var.scss │ │ └── common.scss ├── router │ └── index.js ├── plugin.js ├── main-page │ └── index.vue ├── main.js └── App.vue ├── .editorconfig ├── .gitignore ├── .babelrc ├── .postcssrc.js ├── index.html ├── README.md └── package.json /.jscpd/hashes_css/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/hashes_scss/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/statistic/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/hashes_markdown/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/hashes_markup/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/hashes_javascript/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jscpd/hashes_css/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_scss/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/statistic/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_javascript/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_markdown/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_markup/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000002 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_css/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:13.900 928 Delete type=3 #1 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_scss/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:14.220 928 Delete type=3 #1 2 | -------------------------------------------------------------------------------- /.jscpd/statistic/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:13.861 41ec Delete type=3 #1 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_markdown/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:14.422 2850 Delete type=3 #1 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_markup/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:13.861 3e4c Delete type=3 #1 2 | -------------------------------------------------------------------------------- /.jscpd/hashes_javascript/LOG: -------------------------------------------------------------------------------- 1 | 2019/01/10-15:12:13.914 2850 Delete type=3 #1 2 | -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/img/logo.png -------------------------------------------------------------------------------- /static/img/gakki.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/img/gakki.jpg -------------------------------------------------------------------------------- /static/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/img/loading.gif -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /.jscpd/statistic/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/statistic/MANIFEST-000002 -------------------------------------------------------------------------------- /.jscpd/hashes_css/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/hashes_css/MANIFEST-000002 -------------------------------------------------------------------------------- /.jscpd/hashes_scss/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/hashes_scss/MANIFEST-000002 -------------------------------------------------------------------------------- /.jscpd/hashes_markup/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/hashes_markup/MANIFEST-000002 -------------------------------------------------------------------------------- /.jscpd/hashes_markdown/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/hashes_markdown/MANIFEST-000002 -------------------------------------------------------------------------------- /.jscpd/hashes_javascript/MANIFEST-000002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/.jscpd/hashes_javascript/MANIFEST-000002 -------------------------------------------------------------------------------- /src/components/common/utils.js: -------------------------------------------------------------------------------- 1 | export const StringToCode = string => { 2 | return ` \`\`\` 3 | ${string} 4 | \`\`\` `; 5 | } 6 | -------------------------------------------------------------------------------- /static/fonts/montserrat-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/fonts/montserrat-regular-webfont.woff2 -------------------------------------------------------------------------------- /static/fonts/montserrat-semibold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/fonts/montserrat-semibold-webfont.woff2 -------------------------------------------------------------------------------- /static/img/u=4046980169,286278015&fm=26&gp=0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumari/UI-Library/HEAD/static/img/u=4046980169,286278015&fm=26&gp=0.jpg -------------------------------------------------------------------------------- /src/components/mixins/iconMap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | warn: "warning", 3 | info: "info", 4 | success: "check_circle", 5 | error: "error" 6 | } 7 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | export const getFileName = url => { 2 | const start = url.indexOf('/') 3 | const end = url.lastIndexOf('/') 4 | const name = url.substring(start + 1, end) 5 | 6 | return name 7 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/components/Hover-tip/README.md: -------------------------------------------------------------------------------- 1 | > 易拓展的提示框。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `type` | 提示框展示方向 | String | top-center、bottom-center、right-center、left-center | top-center -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/README.md: -------------------------------------------------------------------------------- 1 | > 基于Vue-router实现的面包屑。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `paths` | Breadcrumb的路径 | Array | - | [] 8 | `separator` | Breadcrumb各个路径之间的分隔符 | String | - | / 9 | `separatorComponent` | Breadcrumb各个路径之间的分割组件 | Object | - | - -------------------------------------------------------------------------------- /src/components/common/demo-common.js: -------------------------------------------------------------------------------- 1 | import DemoBlock from "./demo-block"; 2 | import DemoRow from "./demo-row"; 3 | import { 4 | StringToCode 5 | } from "./utils"; 6 | 7 | export default { 8 | components: { 9 | DemoBlock, 10 | DemoRow 11 | }, 12 | methods: { 13 | _StringToCode: StringToCode 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/icon/README.md: -------------------------------------------------------------------------------- 1 | > 基于material-design-icons构造的图标组件 2 | > 具体icon类型,参考[material-design-icons-图标库](https://material.io/tools/icons/?icon=important_devices&style=baseline) 3 | 4 | #### Attributes 属性 5 | 6 | 参数 | 说明 | 类型 | 可选值 | 默认值 7 | --- | --- | --- | --- | --- 8 | `name` | 指定图标类型 | String | - | * 9 | `size` | 图标大小 | String/Number | - | * -------------------------------------------------------------------------------- /src/components/Date-picker/README.md: -------------------------------------------------------------------------------- 1 | > 用于选择日期 2 | 3 | ## Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `lang` | 日期选择器的语言 | String | CN/EN | CN 8 | `value` | 当前日期选择器的值 | Date | - | - 9 | `disabled` | 是否禁用 | Boolean | true/false | false 10 | `placeholder` | 提示文案 | String | - | - 11 | 12 | 13 | ## Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `select` | 选中日期时触发事件 | 选中日期 -------------------------------------------------------------------------------- /src/components/button/README.md: -------------------------------------------------------------------------------- 1 | > 常用的操作按钮。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `size` | button尺寸类型 | String | mini, small, medium, large | medium 8 | `type` | button形式类型 | String | primary, success, warning, error, text, normal | normal 9 | `disabled` | 是否禁用状态 | boolean | - | false 10 | 11 | #### Events 事件 12 | 13 | 事件名称 | 说明 | 回调函数参数 14 | --- | --- | --- | 15 | `onClick` | 当点击button时触发 | - -------------------------------------------------------------------------------- /src/components/Table/README.md: -------------------------------------------------------------------------------- 1 | > 基于Table标签的展示数据组件 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `data` | 显示的数据 | `Array` | - | `[]` 8 | `align` | 文字对齐方向 | `String` | - | `"left"` 9 | `stripe` | 是否展示斑马纹 | `Boolean` | - | `false` 10 | 11 | > 基于Tb标签的Table-column表格行 12 | 13 | #### Attributes 属性 14 | 15 | 参数 | 说明 | 类型 | 可选值 | 默认值 16 | --- | --- | --- | --- | --- 17 | `label` | 显示的标题| `String` | - | - 18 | -------------------------------------------------------------------------------- /src/assets/styles/var.scss: -------------------------------------------------------------------------------- 1 | $primary-color: #92cc41; 2 | $success-color: #209cee; 3 | $warn-color: #f7d51d; 4 | $error-color: #e76e55; 5 | $disabled-color: #c0c4cc; 6 | $main-color: #ccc; 7 | $font-color: rgba(0, 0, 0, 0.65); 8 | $hover-color: rgba(0, 0, 0, 0.1); 9 | 10 | $s-offset: 8px; 11 | $m-offset: 12px; 12 | $l-offset: 16px; 13 | $xl-offset: 18px; 14 | 15 | $font-size-s: 12px; 16 | $font-size-m: 14px; 17 | $font-size-l: 16px; 18 | 19 | $base-radius: 4px; -------------------------------------------------------------------------------- /src/components/Slider/README.md: -------------------------------------------------------------------------------- 1 | > 基于input标签的滑动组件 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `showTooltip` | 是否显示 tooltip | Boolean | - | false 8 | `disabled` | 是否禁用 | Boolean | - | false 9 | `min` | 最小值 | Number | - | * 10 | `max` | 最大值 | Number | - | * 11 | `step` | 步长 | Number | - | 1 12 | 13 | #### Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `change` | 滑动后触发 | - 18 | `input` | 滑动时触发 | - 19 | -------------------------------------------------------------------------------- /src/components/Scroll-view/README.md: -------------------------------------------------------------------------------- 1 | > 基于input标签的滑动组件 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `showTooltip` | 是否显示 tooltip | Boolean | - | false 8 | `disabled` | 是否禁用 | Boolean | - | false 9 | `min` | 最小值 | Number | - | * 10 | `max` | 最大值 | Number | - | * 11 | `step` | 步长 | Number | - | 1 12 | 13 | #### Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `change` | 滑动后触发 | - 18 | `input` | 滑动时触发 | - 19 | -------------------------------------------------------------------------------- /src/components/Input/README.md: -------------------------------------------------------------------------------- 1 | > 基于原生的 HTML 标签进行拓展的 Input 组件。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `type` | 类型 | String | text,textarea 和其他 原生 input 的 type 值 | text 8 | `prefix-icon` | 输入框头部图标 | String | - | - 9 | `suffix-icon` | 输入框尾部图标 | String | - | - 10 | 11 | #### Events 事件 12 | 13 | 事件名称 | 说明 | 回调函数参数 14 | --- | --- | --- | 15 | `change` | 在 Input 值改变时触发 | event 16 | `focus` | 在 Input 获得焦点时触发 | event 17 | `blur` | 在 Input 失去焦点时触发 | event -------------------------------------------------------------------------------- /src/components/Message/README.md: -------------------------------------------------------------------------------- 1 | > 与 Toast 的区别是后者更多用于系统级通知的被动提醒,常用于后台报错等情景。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `type` | Message 类型 | "info" / "success" / "warn" / "error" | "info" 8 | `content` | Message 内容 | String / HTML | - | * 9 | `duration` | Message 持续时间 | Number | - | 2000 10 | `verticalOffset` | Message 垂直偏移量 | Number | - | 32 11 | 12 | #### Events 事件 13 | 14 | 事件名称 | 说明 | 回调函数参数 15 | --- | --- | --- | 16 | `onClose` | 当Message关闭时触发 | - -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ui-library 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/components/Pagination/README.md: -------------------------------------------------------------------------------- 1 | > 当数据过多时,使用翻页器来进行数据的展示。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `value` | v-model所绑定的值 | Number | - | 1 8 | `total` | | 总条目数 | Number | - 9 | `pageCount` | 页码按钮的数量,当总页数超过该值时会折叠 | Number | 大于等于 5 且小于等于 21 的奇数 | 7 10 | `pageSize` | 每页显示个数选择器的选项设置 | Number | - | 10 11 | `background` | 是否为分页按钮添加背景色 | Boolean | true/false | false 12 | 13 | #### Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `change` | 在 Pagination 值改变时触发 | current page -------------------------------------------------------------------------------- /src/components/Radio-group/README.md: -------------------------------------------------------------------------------- 1 | > Radio的单选框,互斥选项。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `value` | 当前 Radio 的值 | String/value | - | - 8 | `disabled` | 是否禁用 Radio | Boolean | - | false 9 | `propValue` | `v-model` 绑定的值 | String/value | - | - 10 | 11 | > 多个Radio的单选框构成的Radio-Group,互斥选项。 12 | 13 | #### Attributes 属性 14 | 15 | 参数 | 说明 | 类型 | 可选值 | 默认值 16 | --- | --- | --- | --- | --- 17 | `value` | 当前 RadioGroup 的值 | String/value | - | - 18 | `disabled` | 是否禁用 RadioGroup | Boolean | - | false -------------------------------------------------------------------------------- /src/components/Checkbox-group/README.md: -------------------------------------------------------------------------------- 1 | > Checkbox的复选框。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `value` | 当前 Checkbox 的值 | String/Number | - | - 8 | `disabled` | 是否禁用 Radio | Boolean | - | false 9 | `propValue` | `v-model` 绑定的值 | Boolean | - | - 10 | 11 | > 多个Checkbox的单选框构成的Checkbox-Group,多选。 12 | 13 | #### Attributes 属性 14 | 15 | 参数 | 说明 | 类型 | 可选值 | 默认值 16 | --- | --- | --- | --- | --- 17 | `value` | 当前 CheckboxGroup 的值 | Array | - | - 18 | `disabled` | 是否禁用 CheckboxGroup | Boolean | - | false -------------------------------------------------------------------------------- /src/components/Input-number/README.md: -------------------------------------------------------------------------------- 1 | > 基于 Input 组件进行拓展的 InputNumber 组件。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `value` | 绑定值 | Number | - | - 8 | `min` | 设置计数器允许的最小值 | Number | - | -Infinity 9 | `max` | 设置计数器允许的最大值 | Number | - | Infinity 10 | `disabled` | 是否禁用计数器 | Boolean | - | false 11 | `step` | 计数器步长 | Number | - | 1 12 | 13 | #### Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `change` | 在 Input 值改变时触发 | InputNumber的值 18 | `focus` | 在 Input 获得焦点时触发 | event 19 | `blur` | 在 Input 失去焦点时触发 | event -------------------------------------------------------------------------------- /src/components/File-reader/README.md: -------------------------------------------------------------------------------- 1 | > 读取本地文件,支持多种上传方式,以及多个上传。 2 | 3 | ## Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `size` | 上传文件的大小 | Number | - | 0 8 | `limit` | 上传文件个数的限制 | Number | - | 1 9 | `disabled` | 是否禁用状态 | Boolean | true/false | false 10 | `dragable` | 是否可拖拽上传 | Boolean | true/false | false 11 | `accept` | 上传文件类型限制 | String | - | - 12 | `multiple` | 是否允许上传多个文件 | Boolean | true/false | false 13 | 14 | ## Events 事件 15 | 16 | 事件名称 | 说明 | 回调函数参数 17 | --- | --- | --- | 18 | `success` | 上传成功时触发 | files data 19 | `error` | 上传失败时触发 | files error info -------------------------------------------------------------------------------- /src/components/Message-box/README.md: -------------------------------------------------------------------------------- 1 | > 用于提示用户,完成确认的任务。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `title` | MessageBox 标题 | String | - | 提示 8 | `content` | MessageBox 内容 | String / HTML | - | * 9 | `confirmButtonText` | 确认按钮 文字 | String | - | 确定 10 | `cancelButtonText` | 取消按钮 文字 | String | - | 取消 11 | `cancelClose` | 取消确认、取消、关闭点击后的关闭 | Boolean | true / false | false 12 | 13 | #### Events 事件 14 | 15 | 事件名称 | 说明 | 回调函数参数 16 | --- | --- | --- | 17 | `onClose` | 当弹窗关闭时触发 | - 18 | `onConfirm` | 当点击确认按钮时触发 | - 19 | `onCancel` | 当点击取消按钮时触发 | - 20 | -------------------------------------------------------------------------------- /src/components/icon/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | 27 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: flex; 3 | align-items: center; 4 | 5 | .breadcrumb__separator { 6 | display: inline-block; 7 | margin: 0 $s-offset; 8 | font-weight: 700; 9 | color: #c0c4cc; 10 | font-size: 0.8em; 11 | } 12 | 13 | .breadcrumb__item { 14 | color: #1f2f3d; 15 | text-decoration: none; 16 | 17 | &.is-navigative { 18 | &:hover { 19 | color: $success-color; 20 | cursor: pointer; 21 | } 22 | } 23 | 24 | &.router-link-active { 25 | font-weight: 600; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/mixins/popupbox.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data() { 3 | return { 4 | visible: true 5 | } 6 | }, 7 | watch: { 8 | visible(newValue) { 9 | if (!newValue) { 10 | this.$el.addEventListener('transitionend', this.destroyElement) 11 | } 12 | } 13 | }, 14 | mounted() { 15 | document.body.appendChild(this.$el) 16 | }, 17 | destroyed() { 18 | this.$el.parentNode.removeChild(this.$el) 19 | }, 20 | methods: { 21 | destroyElement() { 22 | this.$destroy() 23 | }, 24 | close() { 25 | this.visible = false 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/toast/README.md: -------------------------------------------------------------------------------- 1 | > 用于提示、通知的空间。 2 | 3 | #### Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `type` | toast提示类型 | String | normal, info, warn, success, error | normal 8 | `title` | 弹窗标题 | String | - | * 9 | `content` | 弹窗内容 | String | - | * 10 | `autoClose` | 是否允许自动关闭 | Boolean | true / false | true 11 | duration | 允许自动关闭后弹窗停留时长,单位ms | Number | - | 2500 12 | position | 弹窗在页面的位置 | String | top-left, top-right | top-right 13 | showClose | 是否允许用户关闭 | Boolean | true / false | true 14 | 15 | #### Events 事件 16 | 17 | 事件名称 | 说明 | 回调函数参数 18 | --- | --- | --- | 19 | `onClose` | 当弹窗关闭时触发 | - 20 | -------------------------------------------------------------------------------- /src/components/Tabs/README.md: -------------------------------------------------------------------------------- 1 | > Tabs组件,支持动态删减以及自定义切换。 2 | 3 | #### Tabs Attributes 属性 4 | 5 | 参数 | 说明 | 类型 | 可选值 | 默认值 6 | --- | --- | --- | --- | --- 7 | `value` | 初始化时Tab显示的页 | String | - | - 8 | `card` | 是否为标签模式 | Boolean | - | false 9 | 10 | #### Tab Attributes 属性 11 | 12 | 参数 | 说明 | 类型 | 可选值 | 默认值 13 | --- | --- | --- | --- | --- 14 | `label` | Tab页的标题 | String | - | * 15 | `id` | Tab页的id | String / Number | - | * 16 | `disabled` | 是否禁用 | Boolean | true / false | false 17 | `closable` | 是否显示关闭按钮(只在标签页情况下) | Boolean | true / false | false 18 | 19 | #### Events 事件 20 | 21 | 事件名称 | 说明 | 回调函数参数 22 | --- | --- | --- | 23 | `change` | Tab切换后触发 | - 24 | `select` | Tab选中后触发 | - 25 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import mainPage from '@/main-page/index' 4 | 5 | Vue.use(Router) 6 | 7 | const context = require.context('@/components/', true, /demo\.vue$/) 8 | const componentRouters = context.keys().map(url => { 9 | const start = url.indexOf('/') 10 | const end = url.lastIndexOf('/') 11 | const name = url.substring(start + 1, end) 12 | const path = `/${name}` 13 | 14 | return { 15 | name, 16 | path, 17 | component: require(`@/components${path}/demo`).default 18 | } 19 | }) 20 | 21 | export default new Router({ 22 | routes: [{ 23 | path: '/', 24 | name: 'mainPage', 25 | component: mainPage 26 | }, 27 | 28 | ...componentRouters 29 | ] 30 | }) 31 | -------------------------------------------------------------------------------- /src/components/Radio-group/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 24 | 37 | -------------------------------------------------------------------------------- /src/components/Tab/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | 35 | -------------------------------------------------------------------------------- /src/components/Dropdown/README.md: -------------------------------------------------------------------------------- 1 | > 向下弹出的列表。 2 | 3 | #### Attributes 属性 4 | 5 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 6 | | ------------- | ------------------------------------------------- | ------ | ------------ | -------- | 7 | | `placeholder` | 占位符 | String | - | 下拉菜单 | 8 | | `trigger` | 触发形式 | String | hover, click | hover | 9 | | `optionKey` | 作为 value 唯一标识的键名,绑定值为对象类型时必填 | String | - | value | 10 | 11 | #### Dropdown-Option Attributes 属性 12 | 13 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 14 | | ---------- | -------------- | ------- | ------ | ------ | 15 | | `value` | option 的值 | String | - | - | 16 | | `label` | option 的label | String | - | - | 17 | | `disabled` | 是否禁用状态 | boolean | - | - | -------------------------------------------------------------------------------- /src/components/Table-column/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 34 | 39 | -------------------------------------------------------------------------------- /src/components/Date-picker/panel/basic.js: -------------------------------------------------------------------------------- 1 | export default function GeneratorRows(_h, type, list, itemNum) { 2 | let rows = [] 3 | let row = [] 4 | 5 | list.forEach((elem, index) => { 6 | let dom = index < itemNum ? 'th' : 'td' 7 | let className = index < itemNum && type === 'day' ? 'date-table-head__item' : `date-table-data__item ${elem.type}` 8 | let label = elem.label || elem.value 9 | 10 | row.push( 11 | _h( 12 | dom, { 13 | attrs: { 14 | class: className, 15 | dateType: elem.type, 16 | index: elem.value, 17 | } 18 | }, 19 | label 20 | ) 21 | ) 22 | if (row.length % itemNum === 0 && row.length) { 23 | 24 | rows.push( 25 | _h( 26 | 'tr', { 27 | attrs: { 28 | class: "panel-content-row" 29 | } 30 | }, 31 | row 32 | ) 33 | ) 34 | row = [] 35 | } 36 | }) 37 | return rows 38 | } 39 | -------------------------------------------------------------------------------- /src/components/Checkbox-group/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 37 | 43 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | import marked from 'marked'; 2 | import hljs from 'highlight.js/lib/highlight'; 3 | import 'highlight.js/styles/atelier-estuary-light.css'; 4 | import javascript from 'highlight.js/lib/languages/javascript'; 5 | import xml from 'highlight.js/lib/languages/xml'; 6 | 7 | hljs.registerLanguage('javascript', javascript); 8 | hljs.registerLanguage('xml', xml); 9 | 10 | export default { 11 | install(Vue) { 12 | const rendererMD = new marked.Renderer(); 13 | marked.setOptions({ 14 | renderer: rendererMD, 15 | gfm: true, 16 | tables: true, 17 | breaks: false, 18 | pedantic: false, 19 | sanitize: false, 20 | smartLists: true, 21 | smartypants: false, 22 | }); 23 | Vue.prototype.$marked = marked; 24 | 25 | Vue.directive('highlight', { 26 | bind(el) { 27 | let blocks = el.querySelectorAll('code'); 28 | Array.prototype.forEach.call(blocks, block => { 29 | hljs.highlightBlock(block); 30 | }); 31 | }, 32 | }); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/components/Select/README.md: -------------------------------------------------------------------------------- 1 | > 当选项过多时,使用下拉菜单展示并选择内容。 2 | 3 | #### Attributes 属性 4 | 5 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 6 | | -------------- | ------------------------------------------------- | ------- | ---------- | ------ | 7 | | `placeholder` | 占位符 | String | - | 请选择 | 8 | | `optionKey` | 作为 value 唯一标识的键名,绑定值为对象类型时必填 | String | - | value | 9 | | `disabled` | 是否禁用 | Boolean | true/false | true | 10 | | `multiple` | 是否多选 | Boolean | true/false | false | 11 | | `collapseTags` | 是否缩略已选项 | Boolean | true/false | true | 12 | 13 | #### Events 事件 14 | 15 | | 事件名称 | 说明 | 回调函数参数 | 16 | | -------- | ------------------------ | -------------- | 17 | | `change` | 在 Select 值改变时触发 | Select Options | 18 | | `focus` | 在 Select 获得焦点时触发 | event | 19 | | `blur` | 在 Select 失去焦点时触发 | event | -------------------------------------------------------------------------------- /src/main-page/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 26 | 27 | 28 | 43 | -------------------------------------------------------------------------------- /src/components/Message/index.js: -------------------------------------------------------------------------------- 1 | import Message from './message' 2 | 3 | export default { 4 | install (Vue) { 5 | const constructor = Vue.extend(Message) 6 | let instance = null 7 | let initIndex = 0 8 | 9 | function generateInstance (options) { 10 | let instance = new constructor({ 11 | propsData: options 12 | }).$mount(document.createElement('div')) 13 | if (typeof options.onClose === 'function') instance.onClose = options.onClose 14 | 15 | let id = 'message' + initIndex++ 16 | instance.id = id 17 | 18 | instance.$once('messageClose', function () { 19 | const curInstance = this 20 | typeof curInstance.onClose === 'function' && curInstance.onClose() 21 | }) 22 | return instance 23 | } 24 | 25 | Vue.prototype.$message = (options = {}) => { 26 | instance && instance.$destroy() 27 | instance = generateInstance(options) 28 | } 29 | Vue.prototype.$closeMessage = () => { 30 | instance && instance.$destroy() 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/Date-picker/demo.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 40 | -------------------------------------------------------------------------------- /src/components/Date-picker/panel/panel.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import GeneratorRows from './basic' 3 | 4 | export default Vue.component('panel', { 5 | functional: true, 6 | render: function (_h, context) { 7 | const { 8 | data: list, 9 | type 10 | } = context.props 11 | let result = null 12 | let num = type === 'day' ? 7 : 3 13 | 14 | const clickHandler = (e) => { 15 | if (e.target.attributes.index) { 16 | let value = e.target.attributes.index.value 17 | let params = { 18 | type, 19 | value 20 | } 21 | 22 | type === 'day' && Object.assign(params, { 23 | dateType: e.target.attributes.dateType.value 24 | }) 25 | context.listeners.select(params) 26 | } 27 | e.stopPropagation() 28 | } 29 | 30 | result = _h('table', { 31 | attrs: { 32 | class: context.data.staticClass, 33 | cellspacing: 0, 34 | cellpadding: 0 35 | }, 36 | on: { 37 | click: clickHandler 38 | } 39 | }, GeneratorRows(_h, type, list, num)) 40 | 41 | return result 42 | }, 43 | props: { 44 | data: { 45 | type: Array, 46 | default: () => [] 47 | }, 48 | type: { 49 | type: String 50 | } 51 | } 52 | }) -------------------------------------------------------------------------------- /src/components/utils.js: -------------------------------------------------------------------------------- 1 | export const isNum = num => 2 | !isNaN(num * 1) && 3 | Object.prototype.toString.call(num * 1) === "[object Number]" 4 | 5 | export const isEqualDay = function ({ 6 | year, 7 | month, 8 | day 9 | }, anotherDay) { 10 | return !!anotherDay && year === anotherDay.getFullYear() && month === anotherDay.getMonth() && day === anotherDay.getDate() 11 | } 12 | 13 | export const dateToObj = function (date) { 14 | return { 15 | year: date.getFullYear(), 16 | month: date.getMonth(), 17 | day: date.getDate() 18 | } 19 | } 20 | 21 | export const getScrollBarWidth = function () { 22 | const outer = document.createElement('div'); 23 | outer.className = 'el-scrollbar__wrap'; 24 | outer.style.visibility = 'hidden'; 25 | outer.style.width = '100px'; 26 | outer.style.position = 'absolute'; 27 | outer.style.top = '-9999px'; 28 | document.body.appendChild(outer); 29 | 30 | const widthNoScroll = outer.offsetWidth; 31 | outer.style.overflow = 'scroll'; 32 | 33 | const inner = document.createElement('div'); 34 | inner.style.width = '100%'; 35 | outer.appendChild(inner); 36 | 37 | const widthWithScroll = inner.offsetWidth; 38 | outer.parentNode.removeChild(outer); 39 | return widthNoScroll - widthWithScroll; 40 | }; 41 | 42 | export const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); -------------------------------------------------------------------------------- /src/components/Message-box/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import messageBox from './messagebox.vue'; 3 | 4 | const Constructor = Vue.extend (messageBox); 5 | 6 | function generateInstance (options, type = 'alert') { 7 | let instance = new Constructor ({ 8 | propsData: Object.assign (options, { 9 | type, 10 | }), 11 | }).$mount (document.createElement ('div')); 12 | 13 | instance.onConfirm = options.onConfirm; 14 | instance.onCancel = options.onCancel; 15 | instance.onClose = options.onClose; 16 | 17 | if (typeof options.onConfirm === 'function') { 18 | instance.onConfirm = options.onConfirm; 19 | instance.$on ('confirm', function () { 20 | instance.onConfirm (); 21 | }); 22 | } 23 | 24 | if (typeof options.onCancel === 'function') { 25 | instance.onCancel = options.onCancel; 26 | instance.$on ('cancel', function () { 27 | instance.onCancel (); 28 | }); 29 | } 30 | 31 | if (typeof options.onClose === 'function') { 32 | instance.onClose = options.onClose; 33 | instance.$on ('close', function () { 34 | instance.onClose (); 35 | }); 36 | } 37 | 38 | return instance; 39 | } 40 | 41 | export default { 42 | install (Vue) { 43 | Vue.prototype.$alert = (options = {}) => generateInstance (options); 44 | Vue.prototype.$confirm = (options = {}) => 45 | generateInstance (options, 'confirm'); 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.js: -------------------------------------------------------------------------------- 1 | import './index.scss'; 2 | 3 | export default { 4 | functional: true, 5 | render: function (_h, context) { 6 | const {props: {paths, separator, separatorComponent}} = context; 7 | let elements = paths.map (path => { 8 | const {label, to} = path; 9 | const element = to ? 'router-link' : 'span'; 10 | const props = to 11 | ? { 12 | to, 13 | } 14 | : {}; 15 | 16 | return _h ( 17 | element, 18 | { 19 | class: { 20 | breadcrumb__item: true, 21 | 'is-navigative': !!to 22 | }, 23 | props, 24 | }, 25 | label 26 | ); 27 | }); 28 | 29 | const _separator = separatorComponent 30 | ? separatorComponent 31 | : _h ('span', { 32 | class: { 33 | 'breadcrumb__separator': true, 34 | }, 35 | domProps: { 36 | innerHTML: separator, 37 | }, 38 | }); 39 | 40 | elements = elements.reduce ((pre, cur) => { 41 | const element = pre.length % 2 ? [_separator, cur] : [cur]; 42 | 43 | return [...pre, ...element]; 44 | }, []); 45 | 46 | return _h ( 47 | 'div', 48 | { 49 | class: { 50 | 'breadcrumb': true, 51 | }, 52 | }, 53 | elements 54 | ); 55 | }, 56 | props: { 57 | paths: { 58 | type: Array, 59 | default: () => [], 60 | }, 61 | separator: { 62 | type: String, 63 | default: '/', 64 | }, 65 | separatorComponent: { 66 | type: Object, 67 | }, 68 | }, 69 | }; 70 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/demo.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 54 | 56 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue'; 4 | import App from './App'; 5 | import router from './router'; 6 | 7 | import '@/assets/styles/common.scss'; 8 | import 'reset-css'; 9 | import 'github-markdown-css'; 10 | import 'material-design-icons/iconfont/material-icons.css'; 11 | import plugin from './plugin'; 12 | import { 13 | getFileName 14 | } from '@/utils/index'; 15 | 16 | Vue.config.productionTip = false; 17 | Vue.use(plugin); 18 | 19 | const context = require.context('@/components/', true, /index\.*$/); 20 | context.keys().forEach(url => { 21 | const name = getFileName(url); 22 | const path = `/${name}`; 23 | const plugins = ['toast', 'message-box', 'message']; 24 | 25 | if (plugins.some(plugin => plugin === name.toLowerCase())) { 26 | Vue.use(require(`@/components${path}/index`).default); 27 | } else { 28 | const componentName = require(`@/components${path}/index`).default.name || name 29 | 30 | Vue.component( 31 | `fat-${componentName.toLowerCase()}`, 32 | require(`@/components${path}/index`).default 33 | ); 34 | } 35 | }); 36 | 37 | function Store(store) { 38 | Object.keys(store).forEach( key => { 39 | this[key] = store[key] 40 | }) 41 | } 42 | 43 | const store = new Store({ 44 | state: { 45 | count: 0 46 | }, 47 | getters: { 48 | total: state => { 49 | return state.count + 1 50 | } 51 | } 52 | }) 53 | 54 | /* eslint-disable no-new */ 55 | new Vue({ 56 | el: '#app', 57 | router, 58 | components: { 59 | App 60 | }, 61 | template: '', 62 | store 63 | }); 64 | -------------------------------------------------------------------------------- /src/components/Slider/demo.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 58 | 72 | -------------------------------------------------------------------------------- /src/components/Dropdown-option/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 65 | 66 | -------------------------------------------------------------------------------- /src/components/Pagination/demo.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 67 | 77 | -------------------------------------------------------------------------------- /src/components/Dropdown/index.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 46 | 47 | 86 | -------------------------------------------------------------------------------- /src/components/Input-number/demo.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 52 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 原子组件,提供了通用组件的基本原型。 2 | 3 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/FatGe) 4 | [![Build](https://img.shields.io/appveyor/ci/gruntjs/grunt.svg)](https://github.com/FatGe) 5 | [![Dev](https://img.shields.io/badge/dev-FatGe-green.svg)](https://fatge.xyz/) 6 | [![HitCount](http://hits.dwyl.io/FatGe/UI-Library.svg)](http://hits.dwyl.io/FatGe/UI-Library) 7 | 8 | > 在经历过多个业务场景后,总结出的一些组件的实现方法,如果能够给你提供一些实现思路,就是这个项目的意义。 9 | 10 | 11 | ## Build Setup 12 | 13 | ``` bash 14 | # install dependencies 15 | npm install 16 | 17 | # serve with hot reload at localhost:8080 18 | npm run dev 19 | 20 | # build for production with minification 21 | npm run build 22 | 23 | # build for production and view the bundle analyzer report 24 | npm run build --report 25 | 26 | # check for finding duplicated code blocks 27 | npm run check 28 | ``` 29 | 30 |
31 | 32 | > 特性 33 | 34 | * 组件容易扩展,可进行二次封装; 35 | * 每个组件包含对应的开发文档,方便debug。 36 | 37 |
38 | 39 | >开发文档 40 | 41 | + [基本结构以及构建工具](https://juejin.im/post/5c0b8ece5188254f9e2809fe) 42 | + [Toast 实现](https://juejin.im/post/5c036e4fe51d451b80257c45) 43 | + [Slider 实现](https://juejin.im/post/5c19ff516fb9a049cb18b0f8) 44 | + [Tabs 实现](https://juejin.im/post/5c20430c6fb9a049eb3befaa) 45 | + [File-Reader 实现](https://juejin.im/editor/posts/5c218af3f265da61570580a1) 46 | + [Breadcrumb 实现](https://juejin.im/post/5c22df8b5188253ff14792b3) 47 | + [Hover-Tip 实现](https://juejin.im/post/5c249e396fb9a049b506dfc6) 48 | + [Message-Box 实现](https://juejin.im/post/5c2593b7e51d4535c926774f) 49 | + [Input 实现](https://juejin.im/post/5c2b1d1d6fb9a04a07307849) 50 | + [InputNumber 实现](https://juejin.im/post/5c2d9a49f265da6169175ae7) 51 | + [Select 实现](https://juejin.im/post/5c47d524e51d457d105d0e80) 52 | + [Date-picker 实现](https://juejin.im/post/5c482afc6fb9a04a027ab233) 53 | + [Table 实现](https://juejin.im/post/5c4aa685518825254e4d48e8) 54 | + [Pagination 实现](https://juejin.im/post/5c53a9d3518825246b1013e4) 55 | + [RadioGroup 实现](https://juejin.im/post/5c58d62ee51d457fc440edb7) 56 | + [CheckboxGroup 实现](https://juejin.im/post/5c6277975188256284529024) 57 | + [Dropdown 实现](https://juejin.im/post/5ca1833a5188256a9e1bf8a7) -------------------------------------------------------------------------------- /src/components/Message/demo.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 63 | 65 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | 24 | /** 25 | * Source Maps 26 | */ 27 | 28 | // https://webpack.js.org/configuration/devtool/#development 29 | devtool: 'cheap-module-eval-source-map', 30 | 31 | // If you have problems debugging vue-files in devtools, 32 | // set this to false - it *may* help 33 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 34 | cacheBusting: true, 35 | 36 | cssSourceMap: true 37 | }, 38 | 39 | build: { 40 | // Template for index.html 41 | index: path.resolve(__dirname, '../dist/index.html'), 42 | 43 | // Paths 44 | assetsRoot: path.resolve(__dirname, '../dist'), 45 | assetsSubDirectory: 'static', 46 | assetsPublicPath: '/', 47 | 48 | /** 49 | * Source Maps 50 | */ 51 | 52 | productionSourceMap: true, 53 | // https://webpack.js.org/configuration/devtool/#production 54 | devtool: '#source-map', 55 | 56 | // Gzip off by default as many popular static hosts such as 57 | // Surge or Netlify already gzip all static assets for you. 58 | // Before setting to `true`, make sure to: 59 | // npm install --save-dev compression-webpack-plugin 60 | productionGzip: false, 61 | productionGzipExtensions: ['js', 'css'], 62 | 63 | // Run the build command with an extra argument to 64 | // View the bundle analyzer report after build finishes: 65 | // `npm run build --report` 66 | // Set to `true` or `false` to always turn it on or off 67 | bundleAnalyzerReport: process.env.npm_config_report 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/components/Table/index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 64 | 98 | -------------------------------------------------------------------------------- /src/components/icon/demo.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 65 | 83 | -------------------------------------------------------------------------------- /src/components/Radio/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 67 | 68 | 108 | -------------------------------------------------------------------------------- /src/components/toast/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Toast from './toast.vue'; 3 | /* 4 | 设计模型:Toast组件的生命周期中包含它本身在页面中的挂载与销毁,在组件外构建一层代理并提供相关方法用于调用 5 | 其中组件本身dom以及style被封装,只能改变props 6 | */ 7 | /* 定义常量以及获取Toast组件相关的Props */ 8 | const types = ['normal', 'warn', 'success', 'error', 'info']; 9 | const ToastConstructor = Vue.extend(Toast); 10 | const verticalOffset = 16; 11 | let toastPlugin = {}; 12 | let instances = []; 13 | let initIndex = 0; 14 | let requireProps = Object.keys(Toast.props).filter( 15 | elem => Toast.props[elem].required 16 | ); 17 | /* 初始化每个toast对象在页面中的垂直属性 */ 18 | function initVerticalOffset(position) { 19 | let typeInstances = instances.filter(item => item.position === position); 20 | return typeInstances.reduce( 21 | (sum, elem) => elem.$el.offsetHeight + sum + verticalOffset, 22 | verticalOffset 23 | ); 24 | } 25 | /* 更新每个toast对象在页面中的垂直属性 */ 26 | function updateVerticalOffset(removeInstance) { 27 | let index = 0; 28 | let removeHeight = removeInstance.verticalOffset; 29 | 30 | for (; index < instances.length; index++) { 31 | if (instances[index].id === removeInstance.id) break; 32 | } 33 | instances.splice(index, 1); 34 | 35 | for (; index < instances.length; ++index) { 36 | if (instances[index].position === removeInstance.position) { 37 | [instances[index].verticalOffset, removeHeight] = [ 38 | removeHeight, 39 | instances[index].verticalOffset, 40 | ]; 41 | } 42 | } 43 | } 44 | /* 构造单个toast */ 45 | function generateInstance(options) { 46 | let instance = new ToastConstructor({ 47 | propsData: options, 48 | }).$mount(document.createElement('div')); 49 | if (typeof options.onClose === 'function') instance.onClose = options.onClose; 50 | //计算instance verticalOffset 51 | let id = 'toast_' + initIndex++; 52 | instance.id = id; 53 | instance.verticalOffset = initVerticalOffset(instance.position); 54 | 55 | //监听组件close 56 | instance.$once('toastClose', function () { 57 | const curInstance = this; 58 | updateVerticalOffset(curInstance); 59 | typeof curInstance.onClose === 'function' && curInstance.onClose(); 60 | }); 61 | return instance; 62 | } 63 | 64 | toastPlugin.install = function (Vue) { 65 | Vue.prototype.$toast = (options = {}) => { 66 | requireProps.forEach(elem => { 67 | if (!options[elem]) throw `err: options lack ${elem} prop`; 68 | }); 69 | if (options.type && !types.some(elem => elem === options.type)) 70 | throw `err: toast not exist ${options.type} type`; 71 | 72 | /* 将单个toast存入队列中 */ 73 | let instance = generateInstance(options); 74 | instances.push(instance); 75 | }; 76 | }; 77 | 78 | export default toastPlugin; 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-library", 3 | "version": "1.0.0", 4 | "description": "ui components library", 5 | "author": "FatGe ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "check": "jscpd src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "vue": "^2.5.2", 15 | "vue-router": "^3.0.1" 16 | }, 17 | "devDependencies": { 18 | "autoprefixer": "^7.1.2", 19 | "babel-core": "^6.22.1", 20 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 21 | "babel-loader": "^7.1.1", 22 | "babel-plugin-syntax-jsx": "^6.18.0", 23 | "babel-plugin-transform-runtime": "^6.22.0", 24 | "babel-plugin-transform-vue-jsx": "^3.5.0", 25 | "babel-preset-env": "^1.3.2", 26 | "babel-preset-stage-2": "^6.22.0", 27 | "chalk": "^2.0.1", 28 | "commitizen": "^3.1.1", 29 | "copy-webpack-plugin": "^4.0.1", 30 | "css-loader": "^0.28.0", 31 | "cz-conventional-changelog": "^2.1.0", 32 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 33 | "file-loader": "^1.1.4", 34 | "friendly-errors-webpack-plugin": "^1.6.1", 35 | "github-markdown-css": "^2.10.0", 36 | "highlight.js": "^9.13.1", 37 | "html-webpack-plugin": "^3.1.0", 38 | "jscpd": "^1.2.1", 39 | "marked": "^0.6.2", 40 | "material-design-icons": "^3.0.1", 41 | "mini-css-extract-plugin": "^0.4.4", 42 | "node-notifier": "^5.1.2", 43 | "node-sass": "^4.10.0", 44 | "optimize-css-assets-webpack-plugin": "^4.0.0", 45 | "ora": "^1.2.0", 46 | "portfinder": "^1.0.13", 47 | "postcss-import": "^11.0.0", 48 | "postcss-loader": "^2.0.8", 49 | "postcss-url": "^7.2.1", 50 | "reset-css": "^4.0.1", 51 | "resize-observer-polyfill": "^1.5.1", 52 | "rimraf": "^2.6.0", 53 | "sass-loader": "^7.1.0", 54 | "sass-resources-loader": "^2.0.0", 55 | "semver": "^5.3.0", 56 | "shelljs": "^0.7.6", 57 | "text-loader": "^0.0.1", 58 | "uglifyjs-webpack-plugin": "^1.1.1", 59 | "url-loader": "^1.1.2", 60 | "vue": "^2.5.17", 61 | "vue-loader": "^15.4.2", 62 | "vue-style-loader": "^4.1.2", 63 | "vue-template-compiler": "^2.5.2", 64 | "webpack": "^4.24.0", 65 | "webpack-bundle-analyzer": "^2.11.1", 66 | "webpack-cli": "^3.1.2", 67 | "webpack-dev-middleware": "^3.1.2", 68 | "webpack-dev-server": "^3.1.10", 69 | "webpack-merge": "^4.1.0" 70 | }, 71 | "engines": { 72 | "node": ">= 6.0.0", 73 | "npm": ">= 3.0.0" 74 | }, 75 | "browserslist": [ 76 | "> 1%", 77 | "last 2 versions", 78 | "not ie <= 8" 79 | ], 80 | "config": { 81 | "commitizen": { 82 | "path": "./node_modules/cz-conventional-changelog" 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/components/Checkbox-group/demo.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 75 | 91 | -------------------------------------------------------------------------------- /src/components/Radio-group/demo.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 77 | 91 | -------------------------------------------------------------------------------- /src/components/Message-box/messagebox.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 51 | 52 | 104 | -------------------------------------------------------------------------------- /src/components/common/demo-row.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 54 | 125 | -------------------------------------------------------------------------------- /src/components/Scroll-view/demo.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 105 | 112 | -------------------------------------------------------------------------------- /src/components/Input/demo.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 86 | 101 | -------------------------------------------------------------------------------- /src/components/Scroll-view/bar.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 80 | 108 | -------------------------------------------------------------------------------- /src/components/Message/message.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 58 | 59 | -------------------------------------------------------------------------------- /src/components/Option/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 107 | 108 | 127 | -------------------------------------------------------------------------------- /src/components/Date-picker/CONST.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": { 3 | "month": [{ 4 | "label": "1月", 5 | "value": 0 6 | }, 7 | { 8 | "label": "2月", 9 | "value": 1 10 | }, 11 | { 12 | "label": "3月", 13 | "value": 2 14 | }, 15 | { 16 | "label": "4月", 17 | "value": 3 18 | }, 19 | { 20 | "label": "5月", 21 | "value": 4 22 | }, 23 | { 24 | "label": "6月", 25 | "value": 5 26 | }, 27 | { 28 | "label": "7月", 29 | "value": 6 30 | }, 31 | { 32 | "label": "8月", 33 | "value": 7 34 | }, 35 | { 36 | "label": "9月", 37 | "value": 8 38 | }, 39 | { 40 | "label": "10月", 41 | "value": 9 42 | }, 43 | { 44 | "label": "11月", 45 | "value": 10 46 | }, 47 | { 48 | "label": "12月", 49 | "value": 11 50 | } 51 | ], 52 | "day": [{ 53 | "type": "week", 54 | "label": "日" 55 | }, 56 | { 57 | "type": "week", 58 | "label": "一" 59 | }, 60 | { 61 | "type": "week", 62 | "label": "二" 63 | }, 64 | { 65 | "type": "week", 66 | "label": "三" 67 | }, 68 | { 69 | "type": "week", 70 | "label": "四" 71 | }, 72 | { 73 | "type": "week", 74 | "label": "五" 75 | }, 76 | { 77 | "type": "week", 78 | "label": "六" 79 | } 80 | ] 81 | }, 82 | "EN": { 83 | "month": [{ 84 | "label": "Jan", 85 | "value": 0 86 | }, 87 | { 88 | "label": "Feb", 89 | "value": 1 90 | }, 91 | { 92 | "label": "Mar", 93 | "value": 2 94 | }, 95 | { 96 | "label": "Apr", 97 | "value": 3 98 | }, 99 | { 100 | "label": "May", 101 | "value": 4 102 | }, 103 | { 104 | "label": "Jun", 105 | "value": 5 106 | }, 107 | { 108 | "label": "Jul", 109 | "value": 6 110 | }, 111 | { 112 | "label": "Aug", 113 | "value": 7 114 | }, 115 | { 116 | "label": "Sep", 117 | "value": 8 118 | }, 119 | { 120 | "label": "Oct", 121 | "value": 9 122 | }, 123 | { 124 | "label": "Nov", 125 | "value": 10 126 | }, 127 | { 128 | "label": "Dec", 129 | "value": 11 130 | } 131 | ], 132 | "day": [{ 133 | "type": "week", 134 | "label": "Sun" 135 | }, 136 | { 137 | "type": "week", 138 | "label": "Mon" 139 | }, 140 | { 141 | "type": "week", 142 | "label": "Tues" 143 | }, 144 | { 145 | "type": "week", 146 | "label": "Wed" 147 | }, 148 | { 149 | "type": "week", 150 | "label": "Thur" 151 | }, 152 | { 153 | "type": "week", 154 | "label": "Fri" 155 | }, 156 | { 157 | "type": "week", 158 | "label": "Sat" 159 | } 160 | ] 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/components/Checkbox/index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 90 | 91 | 145 | -------------------------------------------------------------------------------- /src/components/Hover-tip/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | 26 | 144 | -------------------------------------------------------------------------------- /src/components/button/demo.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 93 | 95 | -------------------------------------------------------------------------------- /src/assets/styles/common.scss: -------------------------------------------------------------------------------- 1 | @import './var.scss'; 2 | 3 | @font-face { 4 | font-family: 'Material Icons'; 5 | font-style: normal; 6 | font-weight: 400; 7 | src: local('material-design-icons'), local('MaterialIcons-Regular'); 8 | } 9 | 10 | @font-face { 11 | font-family: 'MontBold'; 12 | src: url('/static/fonts/montserrat-semibold-webfont.woff2') format('woff2'), 13 | url('/static/fonts/montserrat-semibold-webfont.woff') format('woff'); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @font-face { 19 | font-family: 'Mont'; 20 | src: url('/static/fonts/montserrat-regular-webfont.woff2') format('woff2'), 21 | url('/static/fonts/montserrat-regular-webfont.woff') format('woff'); 22 | font-weight: normal; 23 | font-style: normal; 24 | } 25 | 26 | .material-icons { 27 | font-family: 'Material Icons'; 28 | font-weight: normal; 29 | font-style: normal; 30 | font-size: 24px; 31 | /* Preferred icon size */ 32 | display: inline-block; 33 | line-height: 1; 34 | text-transform: none; 35 | letter-spacing: normal; 36 | word-wrap: normal; 37 | white-space: nowrap; 38 | direction: ltr; 39 | /* Support for all WebKit browsers. */ 40 | -webkit-font-smoothing: antialiased; 41 | /* Support for Safari and Chrome. */ 42 | text-rendering: optimizeLegibility; 43 | /* Support for Firefox. */ 44 | -moz-osx-font-smoothing: grayscale; 45 | /* Support for IE. */ 46 | font-feature-settings: 'liga'; 47 | } 48 | 49 | .markdown-body { 50 | margin: 32px 0; 51 | text-align: left; 52 | 53 | pre { 54 | max-width: max-content; 55 | } 56 | } 57 | 58 | // ::-webkit-scrollbar { 59 | // width: 5px; 60 | // height: 5px; 61 | // background-color: #ddd; 62 | // } 63 | 64 | // ::-webkit-scrollbar-track { 65 | // background-color: #fff; 66 | // } 67 | 68 | // ::-webkit-scrollbar-thumb { 69 | // border-radius: 10px; 70 | // background-color: rgba(144, 147, 153, 0.3); 71 | // } 72 | 73 | /* font chart */ 74 | 75 | .c-size-s { 76 | font-size: $font-size-s; 77 | } 78 | 79 | .c-size-m { 80 | font-size: $font-size-m; 81 | } 82 | 83 | .c-size-l { 84 | font-size: $font-size-l; 85 | } 86 | 87 | .c-normal { 88 | font-family: Mont; 89 | } 90 | 91 | .c-bold { 92 | font-family: MontBold; 93 | font-weight: 800; 94 | } 95 | 96 | .c-color-normal { 97 | color: $font-color; 98 | } 99 | 100 | .c-color-success { 101 | color: $success-color; 102 | } 103 | 104 | /* text-type */ 105 | .t-none-decoration { 106 | text-decoration: none; 107 | } 108 | 109 | /* position-type */ 110 | .p-center { 111 | position: absolute; 112 | top: 0; 113 | bottom: 0; 114 | margin-top: auto; 115 | margin-bottom: auto; 116 | } 117 | 118 | /* transition effect */ 119 | @mixin transition-effect($val) { 120 | transition: opacity $val, transform $val, left $val, right $val, top $val, 121 | bottom $val; 122 | } 123 | 124 | .fade-enter-active, 125 | .fade-leave-active { 126 | @include transition-effect(0.3s); 127 | } 128 | 129 | .fade-enter, 130 | .fade-leave-to { 131 | opacity: 0; 132 | } 133 | 134 | .move-enter-active { 135 | transition: opacity .5s, transform .5s; 136 | } 137 | 138 | .move-leave-active { 139 | opacity: 0; 140 | } 141 | 142 | .move-enter { 143 | transform: translateX(20%); 144 | opacity: 0; 145 | } 146 | 147 | /* end */ 148 | 149 | input { 150 | 151 | /* input placeholder style */ 152 | &::-webkit-input-placeholder { 153 | /* WebKit, Blink, Edge */ 154 | color: #999; 155 | } 156 | 157 | &:-moz-placeholder { 158 | /* Mozilla Firefox 4 to 18 */ 159 | color: #999; 160 | } 161 | 162 | &::-moz-placeholder { 163 | /* Mozilla Firefox 19+ */ 164 | color: #999; 165 | } 166 | 167 | &:-ms-input-placeholder { 168 | /* Internet Explorer 10-11 */ 169 | color: #999; 170 | } 171 | } 172 | 173 | code { 174 | font-size: 1em; 175 | font-family: Menlo, Monaco, Consolas, Courier, monospace; 176 | } 177 | -------------------------------------------------------------------------------- /src/components/Message-box/demo.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 137 | 139 | -------------------------------------------------------------------------------- /src/components/Hover-tip/demo.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 116 | 132 | -------------------------------------------------------------------------------- /src/components/toast/demo.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 134 | 136 | -------------------------------------------------------------------------------- /src/components/Input/index.vue: -------------------------------------------------------------------------------- 1 |