├── docs
├── intro.md
├── uploader.md
├── icon.md
├── theme.md
├── sticky.md
├── spinner.md
├── switch.md
├── tag.md
├── use.md
├── utils.md
├── slide.md
├── toast.md
├── popup.md
├── actionsheet.md
├── table.md
├── tabs.md
├── radio.md
├── button.md
├── notice-bar.md
├── layout.md
├── tabbar.md
├── checkbox.md
├── modal.md
├── field.md
└── nav-bar.md
├── packages
├── theme
│ ├── src
│ │ ├── icon.scss
│ │ ├── slide-item.scss
│ │ ├── common
│ │ │ ├── _ellipsis.scss
│ │ │ ├── _1px.scss
│ │ │ ├── _var.scss
│ │ │ └── _transition.scss
│ │ ├── spinner.scss
│ │ ├── sticky.scss
│ │ ├── uploader.scss
│ │ ├── tab-pane.scss
│ │ ├── col.scss
│ │ ├── tabbar.scss
│ │ ├── table.scss
│ │ ├── cell-group.scss
│ │ ├── row.scss
│ │ ├── slide.scss
│ │ ├── base.scss
│ │ ├── index.scss
│ │ ├── field.scss
│ │ ├── checkbox.scss
│ │ ├── tabbar-item.scss
│ │ ├── actionsheet.scss
│ │ ├── popup.scss
│ │ ├── switch.scss
│ │ ├── toast.scss
│ │ ├── radio.scss
│ │ ├── tag.scss
│ │ ├── cell.scss
│ │ ├── modal.scss
│ │ ├── notice-bar.scss
│ │ ├── nav-bar.scss
│ │ ├── button.scss
│ │ └── tabs.scss
│ └── gulpfile.js
├── mixins
│ ├── index.js
│ ├── find-parent.js
│ └── popup.js
├── cell
│ ├── index.js
│ └── src
│ │ └── index.vue
├── col
│ ├── index.js
│ └── src
│ │ └── index.vue
├── icon
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── row
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── tabs
│ ├── index.js
│ ├── src
│ │ └── title.vue
│ └── demo
│ │ └── index.vue
├── tag
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── button
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── checkbox
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── field
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── nav-bar
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── popup
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── radio
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── slide
│ ├── index.js
│ └── demo
│ │ └── index.vue
├── spinner
│ ├── index.js
│ └── demo
│ │ └── index.vue
├── sticky
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── switch
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── tab-pane
│ ├── index.js
│ └── src
│ │ └── index.vue
├── tabbar
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── table
│ ├── index.js
│ ├── src
│ │ └── index.vue
│ └── demo
│ │ └── index.vue
├── uploader
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── actionsheet
│ ├── index.js
│ ├── demo
│ │ └── index.vue
│ └── src
│ │ └── index.vue
├── cell-group
│ ├── index.js
│ └── src
│ │ └── index.vue
├── checkbox-group
│ ├── index.js
│ └── src
│ │ └── index.vue
├── notice-bar
│ ├── index.js
│ └── demo
│ │ └── index.vue
├── radio-group
│ ├── index.js
│ └── src
│ │ └── index.vue
├── slide-item
│ ├── index.js
│ └── src
│ │ └── index.vue
├── tabbar-item
│ ├── index.js
│ └── src
│ │ └── index.vue
├── utils
│ ├── index.js
│ ├── event.js
│ └── shared.js
├── toast
│ ├── demo
│ │ └── index.vue
│ ├── index.js
│ └── src
│ │ └── index.vue
├── overlay
│ ├── overlay.vue
│ └── index.js
└── modal
│ ├── demo
│ └── index.vue
│ ├── index.js
│ └── src
│ └── index.vue
├── .eslintignore
├── .gitignore
├── postcss.config.js
├── examples
├── assets
│ ├── images
│ │ ├── logo1.png
│ │ ├── logo2.png
│ │ └── device-frame.png
│ └── styles
│ │ ├── global.scss
│ │ └── docs.scss
├── components
│ ├── doc-container.vue
│ ├── doc-main.vue
│ ├── demo-block.vue
│ ├── doc-simulator.vue
│ ├── demo-header.vue
│ ├── doc-nav.vue
│ ├── doc-header.vue
│ ├── demo-nav.vue
│ └── doc-brand.vue
├── utils
│ ├── index.js
│ └── iframe-router.js
├── index.html
├── router.js
├── pages
│ └── demo-home.vue
├── app_docs.vue
├── index_docs.js
├── index_mobile.js
└── app_mobile.vue
├── .editorconfig
├── .travis.yml
├── .babelrc
├── .eslintrc
├── LICENSE
├── README.md
├── src
└── index.js
└── package.json
/docs/intro.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/theme/src/icon.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/uploader.md:
--------------------------------------------------------------------------------
1 | ## Uploader 文件上传
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | lib
2 | examples
3 | node_modules
4 | packages/**/demo
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | examples/dist
3 | lib
4 | *.log*
5 | .DS_Store
6 | .idea
7 | .vscode
8 |
--------------------------------------------------------------------------------
/packages/theme/src/slide-item.scss:
--------------------------------------------------------------------------------
1 | .i-slide-item {
2 | float: left;
3 | height: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | cssnano: {}
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/assets/images/logo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaojundebug/unique-ui/HEAD/examples/assets/images/logo1.png
--------------------------------------------------------------------------------
/examples/assets/images/logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaojundebug/unique-ui/HEAD/examples/assets/images/logo2.png
--------------------------------------------------------------------------------
/examples/assets/images/device-frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaojundebug/unique-ui/HEAD/examples/assets/images/device-frame.png
--------------------------------------------------------------------------------
/packages/mixins/index.js:
--------------------------------------------------------------------------------
1 | import findParent from './find-parent'
2 | import popup from './popup'
3 |
4 | export { findParent, popup }
5 |
--------------------------------------------------------------------------------
/packages/theme/src/common/_ellipsis.scss:
--------------------------------------------------------------------------------
1 | .ellipsis {
2 | overflow: hidden;
3 | white-space: nowrap;
4 | text-overflow: ellipsis;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/cell/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/col/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/icon/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/row/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/tabs/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/tag/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/button/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/checkbox/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/field/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/nav-bar/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/popup/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/radio/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/slide/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/spinner/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/sticky/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/switch/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/tab-pane/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/tabbar/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/table/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/uploader/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/actionsheet/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/cell-group/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/checkbox-group/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/notice-bar/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/radio-group/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/slide-item/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/packages/tabbar-item/index.js:
--------------------------------------------------------------------------------
1 | import Component from './src'
2 |
3 | Component.install = function(Vue) {
4 | Vue.component(Component.name, Component)
5 | }
6 |
7 | export default Component
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = crlf
7 | charset = utf-8
8 | trim_trailing_whitespace = false
9 | insert_final_newline = false
10 |
--------------------------------------------------------------------------------
/packages/cell-group/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/theme/src/spinner.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-spinner {
4 | display: inline-block;
5 | svg {
6 | stroke: $primary-color;
7 | fill: $primary-color;
8 | vertical-align: middle;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/components/doc-container.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/theme/src/sticky.scss:
--------------------------------------------------------------------------------
1 | .i-sticky {
2 | &__inner {
3 | position: relative;
4 | width: 100%;
5 | }
6 | &--native {
7 | position: sticky;
8 | }
9 | &--simulate {
10 | .i-sticky__inner {
11 | position: fixed;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/theme/src/uploader.scss:
--------------------------------------------------------------------------------
1 | .i-uploader {
2 | position: relative;
3 | display: inline-block;
4 | &__input {
5 | position: absolute;
6 | top: 0;
7 | right: 0;
8 | bottom: 0;
9 | left: 0;
10 | opacity: 0;
11 | width: 100%;
12 | height: 100%;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/theme/src/tab-pane.scss:
--------------------------------------------------------------------------------
1 | .i-tab {
2 | &__panel {
3 | width: 100%;
4 | padding: 20px;
5 | box-sizing: border-box;
6 | }
7 | &--animated {
8 | .i-tab__content {
9 | display: flex;
10 | }
11 | .i-tab__panel {
12 | flex-shrink: 0;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 10
4 | install:
5 | - yarn
6 | script:
7 | - yarn build:doc
8 | cache: yarn
9 | deploy:
10 | provider: pages
11 | local_dir: examples/dist
12 | skip_cleanup: true
13 | keep_history: true
14 | github_token: $GITHUB_TOKEN
15 | on:
16 | branch: master
--------------------------------------------------------------------------------
/packages/theme/src/col.scss:
--------------------------------------------------------------------------------
1 | .i-col {
2 | flex-shrink: 0;
3 | width: 100%;
4 | box-sizing: border-box;
5 | }
6 |
7 | $i: 1;
8 |
9 | @while $i <= 24 {
10 | .i-col--#{$i} {
11 | width: $i * 100% / 24;
12 | }
13 | .i-col--offset-#{$i} {
14 | margin-left: $i * 100% / 24;
15 | }
16 |
17 | $i: $i + 1;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/radio-group/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/preset-env", {
4 | "loose": true,
5 | "modules": false
6 | }
7 | ],
8 | ["@vue/babel-preset-jsx", {
9 | "functional": false
10 | }
11 | ]
12 | ],
13 | "plugins": [
14 | "@babel/plugin-transform-runtime",
15 | "@babel/plugin-syntax-dynamic-import",
16 | "@babel/plugin-transform-object-assign"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/packages/theme/src/tabbar.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-tabbar {
4 | height: $tab-bar-height;
5 | &__inner {
6 | position: relative;
7 | display: flex;
8 | height: $tab-bar-height;
9 | background-color: #fff;
10 | }
11 | &--fixed {
12 | .i-tabbar__inner {
13 | position: fixed;
14 | left: 0;
15 | bottom: 0;
16 | width: 100%;
17 | z-index: 1;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": ["plugin:vue-libs/recommended", "plugin:vue/strongly-recommended"],
4 | "rules": {
5 | "space-before-function-paren": ["error", "never"],
6 | "vue/html-self-closing": 0,
7 | "vue/require-default-prop": 0,
8 | "vue/require-v-for-key": 0,
9 | "vue/max-attributes-per-line": [
10 | 2,
11 | {
12 | "singleline": 1
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/theme/src/table.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-table {
4 | overflow: auto;
5 | font-size: 0;
6 | background-color: #fff;
7 | &__tr {
8 | display: inline-flex;
9 | min-width: 100%;
10 | }
11 | &__th {
12 | font-weight: bold;
13 | }
14 | &__th,
15 | &__td {
16 | flex-grow: 1;
17 | display: inline-block;
18 | padding: 15px;
19 | box-sizing: border-box;
20 | font-size: 14px;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/components/doc-main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
23 |
--------------------------------------------------------------------------------
/packages/mixins/find-parent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * find parent component by name
3 | */
4 |
5 | export default {
6 | data() {
7 | return {
8 | parent: null
9 | }
10 | },
11 |
12 | methods: {
13 | findParent(name) {
14 | let parent = this.$parent
15 | while (parent) {
16 | if (parent.$options.name === name) {
17 | this.parent = parent
18 | break
19 | }
20 | parent = parent.$parent
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/checkbox-group/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
--------------------------------------------------------------------------------
/packages/theme/src/cell-group.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-cell-group {
4 | background-color: #fff;
5 | &:not(:last-child) {
6 | margin-bottom: 10px;
7 | }
8 | .i-cell {
9 | &:not(:first-child)::after {
10 | content: '';
11 | position: absolute;
12 | pointer-events: none;
13 | box-sizing: border-box;
14 | left: 0.3rem;
15 | right: 0;
16 | top: 0;
17 | transform: scaleY(0.5);
18 | transform-origin: 0 0;
19 | border-bottom: 1px solid $border-color;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/utils/index.js:
--------------------------------------------------------------------------------
1 | // 测试css兼容性
2 | function featureTest(property, value, noPrefixes) {
3 | var prop = property + ':'
4 |
5 | var el = document.createElement('test')
6 |
7 | var mStyle = el.style
8 |
9 | if (!noPrefixes) {
10 | mStyle.cssText =
11 | prop + ['-webkit-', '-moz-', '-ms-', '-o-', ''].join(value + ';' + prop) + value + ';'
12 | } else {
13 | mStyle.cssText = prop + value
14 | }
15 | return mStyle[property].indexOf(value) !== -1
16 | }
17 |
18 | export { featureTest }
19 | export * from './event'
20 | export * from './shared'
21 |
--------------------------------------------------------------------------------
/packages/theme/src/row.scss:
--------------------------------------------------------------------------------
1 | .i-row {
2 | display: flex;
3 | justify-content: flex-start;
4 | align-items: flex-start;
5 | flex-wrap: wrap;
6 | &--justify-center {
7 | justify-content: center;
8 | }
9 | &--justify-end {
10 | justify-content: flex-end;
11 | }
12 | &--justify-space-around {
13 | justify-content: space-around;
14 | }
15 | &--justify-space-between {
16 | justify-content: space-between;
17 | }
18 | &--align-center {
19 | align-items: center;
20 | }
21 | &--align-bottom {
22 | align-items: flex-end;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/row/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
--------------------------------------------------------------------------------
/packages/toast/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 常规样式
5 |
6 |
7 | loading
8 | success
9 | fail
10 |
11 |
12 |
13 |
14 |
22 |
--------------------------------------------------------------------------------
/packages/theme/src/slide.scss:
--------------------------------------------------------------------------------
1 | .i-slide {
2 | position: relative;
3 | overflow: hidden;
4 | &__track {
5 | height: 100%;
6 | user-select: none;
7 | }
8 | &__indicators {
9 | position: absolute;
10 | left: 50%;
11 | transform: translateX(-50%);
12 | bottom: 10px;
13 | display: flex;
14 | margin: 0;
15 | padding: 0;
16 | list-style: none;
17 | }
18 | &__indicator {
19 | height: 6px;
20 | width: 6px;
21 | border-radius: 50%;
22 | margin: 0 2px;
23 | background-color: rgba(0, 0, 0, 0.3);
24 | &.active {
25 | background-color: orange;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/theme/src/base.scss:
--------------------------------------------------------------------------------
1 | @import './common/normalize';
2 | @import './common/ellipsis';
3 | @import './common/transition';
4 | @import './common/var';
5 | @import './common/1px';
6 |
7 | body {
8 | font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
9 | 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
10 | margin: 0;
11 | font-size: 14px;
12 | color: $dark-color;
13 | -webkit-tap-highlight-color: transparent;
14 | }
15 |
16 | button,
17 | input,
18 | textarea {
19 | outline: none;
20 | }
21 |
22 | ul {
23 | list-style-type: none;
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
--------------------------------------------------------------------------------
/packages/icon/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
36 |
37 |
--------------------------------------------------------------------------------
/packages/utils/event.js:
--------------------------------------------------------------------------------
1 | // Test via a getter in the options object to see
2 | // if the passive property is accessed
3 | var supportsPassive = false
4 | try {
5 | var opts = Object.defineProperty({}, 'passive', {
6 | get: function() {
7 | supportsPassive = true
8 | }
9 | })
10 | window.addEventListener('test', null, opts)
11 | } catch (e) {}
12 |
13 | function on(elem, event, handler, passive = false) {
14 | elem.addEventListener(event, handler, supportsPassive ? { passive } : false)
15 | }
16 |
17 | function off(elem, event, handler) {
18 | elem.removeEventListener(event, handler)
19 | }
20 |
21 | export {
22 | on,
23 | off
24 | }
25 |
--------------------------------------------------------------------------------
/examples/utils/index.js:
--------------------------------------------------------------------------------
1 | function iframeReady(iframe, callback) {
2 | const doc = iframe.contentWindow.document
3 | const interval = () => {
4 | if (iframe.contentWindow.changePath) {
5 | callback()
6 | } else {
7 | setTimeout(() => {
8 | interval()
9 | }, 50)
10 | }
11 | }
12 |
13 | if (doc.readyState === 'complete') {
14 | interval()
15 | } else {
16 | iframe.onload = interval
17 | }
18 | }
19 |
20 | const ua = navigator.userAgent.toLowerCase()
21 | const isMobile = /ios|iphone|ipod|ipad|android/.test(ua)
22 | const randNum = (a = 0, b) => a + Math.round(Math.random() * (b - a))
23 |
24 | export { isMobile, iframeReady, randNum }
25 |
--------------------------------------------------------------------------------
/packages/icon/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/packages/theme/src/index.scss:
--------------------------------------------------------------------------------
1 | @import './base.scss';
2 |
3 | @import './actionsheet';
4 | @import './button';
5 | @import './cell-group';
6 | @import './cell';
7 | @import './checkbox';
8 | @import './col';
9 | @import './field';
10 | @import './modal';
11 | @import './nav-bar';
12 | @import './notice-bar';
13 | @import './popup';
14 | @import './radio';
15 | @import './row';
16 | @import './slide-item';
17 | @import './slide';
18 | @import './spinner';
19 | @import './sticky';
20 | @import './switch';
21 | @import './tab-pane';
22 | @import './tabbar-item';
23 | @import './tabbar';
24 | @import './table';
25 | @import './tabs';
26 | @import './tag';
27 | @import './toast';
28 | @import './uploader';
29 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | unique-ui
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages/theme/src/field.scss:
--------------------------------------------------------------------------------
1 | @import './cell.scss';
2 |
3 | .i-field {
4 | .i-cell__hd {
5 | width: 90px;
6 | }
7 | &__body {
8 | width: 100%;
9 | height: 100%;
10 | display: flex;
11 | align-items: center;
12 | }
13 | &__control {
14 | width: 100%;
15 | height: 100%;
16 | border: none;
17 | padding: 0;
18 | box-sizing: border-box;
19 | background-color: transparent;
20 | resize: none;
21 | &:disabled {
22 | opacity: 1;
23 | color: #999;
24 | -webkit-text-fill-color: #999;
25 | }
26 | &::placeholder {
27 | color: #bbb;
28 | }
29 | }
30 | &__clear {
31 | font-size: 20px;
32 | color: #aaa;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/examples/utils/iframe-router.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 同步父窗口和 iframe 的 vue-router 状态
3 | */
4 |
5 | import { iframeReady, isMobile } from './'
6 |
7 | window.syncPath = function() {
8 | const router = window.vueRouter
9 | const isInIframe = window !== window.top
10 | const currPath = router.history.current.path
11 |
12 | if (!isInIframe && !isMobile) {
13 | const iframe = document.querySelector('iframe')
14 | if (iframe) {
15 | iframeReady(iframe, () => {
16 | iframe.contentWindow.changePath(currPath)
17 | })
18 | }
19 | } else if (isInIframe) {
20 | window.top.changePath(currPath)
21 | }
22 | }
23 |
24 | window.changePath = function(path = '') {
25 | window.vueRouter.replace(path)
26 | }
27 |
--------------------------------------------------------------------------------
/packages/theme/src/common/_1px.scss:
--------------------------------------------------------------------------------
1 | @import './var';
2 |
3 | [class*='i-1px'] {
4 | position: relative;
5 |
6 | &::after {
7 | content: ' ';
8 | position: absolute;
9 | top: -50%;
10 | left: -50%;
11 | right: -50%;
12 | bottom: -50%;
13 | transform: scale(0.5);
14 | border: 0 solid $border-color;
15 | box-sizing: border-box;
16 | pointer-events: none;
17 | }
18 | }
19 |
20 | .i-1px {
21 | &::after {
22 | border-width: 1px;
23 | }
24 | &--t::after {
25 | border-top-width: 1px;
26 | }
27 | &--r::after {
28 | border-right-width: 1px;
29 | }
30 | &--b::after {
31 | border-bottom-width: 1px;
32 | }
33 | &--l::after {
34 | border-left-width: 1px;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/theme/gulpfile.js:
--------------------------------------------------------------------------------
1 | const { series, src, dest } = require('gulp')
2 | const sass = require('gulp-sass')
3 | const autoprefixer = require('gulp-autoprefixer')
4 | const cssmin = require('gulp-cssmin')
5 | const path = require('path')
6 |
7 | const inputPath = path.resolve(__dirname, './src')
8 | const outputPath = path.resolve(__dirname, '../../lib/theme')
9 |
10 | function compile() {
11 | return src(inputPath + '/*.scss')
12 | .pipe(sass.sync())
13 | .pipe(autoprefixer())
14 | .pipe(cssmin())
15 | .pipe(dest(outputPath))
16 | }
17 |
18 | function copyfont() {
19 | return src(inputPath + '/fonts/**')
20 | .pipe(cssmin())
21 | .pipe(dest(outputPath + '/fonts'))
22 | }
23 |
24 | exports.build = series(compile, copyfont)
25 |
--------------------------------------------------------------------------------
/packages/theme/src/checkbox.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-checkbox {
4 | display: inline-flex;
5 | align-items: center;
6 | user-select: none;
7 | margin-right: 10px;
8 | &__icon {
9 | border: 1px solid #ddd;
10 | border-radius: 50%;
11 | width: 17px;
12 | height: 17px;
13 | text-align: center;
14 | line-height: 18px;
15 | font-size: 14px;
16 | color: transparent;
17 | transition: 0.2s;
18 | }
19 | &__label {
20 | font-size: 14px;
21 | margin-left: 5px;
22 | }
23 | &--checked {
24 | .i-checkbox__icon {
25 | background-color: $primary-color;
26 | border-color: $primary-color;
27 | color: #fff;
28 | }
29 | }
30 | &--disabled {
31 | opacity: 0.5;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docs/icon.md:
--------------------------------------------------------------------------------
1 | ## Icon 图标
2 |
3 | > 图标资源来自于[Font Awesome 4.7.0](https://fontawesome.com/v4.7.0/),兼容官方写法,如果你只是想简单使用某个图标,可以使用这里提供的`Icon`组件,也许能省下一些你写类名的时间
4 |
5 | #### 简单用法
6 |
7 | ```html
8 |
9 | ```
10 |
11 | #### 自定义大小
12 |
13 | ```html
14 |
15 |
16 |
17 | ```
18 |
19 | #### 自定义颜色
20 |
21 | ```html
22 |
23 |
24 | ```
25 |
26 | #### Props
27 |
28 | | 参数 | 说明 | 类型 | 默认值 |
29 | |------|------|------|------|
30 | | name | 图标名称 | `String` | `''` |
31 | | size | 图标大小 | `String` | `'inherit'` |
32 | | color | 图标颜色 | `String` | `'inherit'` |
33 |
--------------------------------------------------------------------------------
/examples/components/demo-block.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ title }}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
21 |
22 |
38 |
--------------------------------------------------------------------------------
/packages/slide-item/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
39 |
40 |
--------------------------------------------------------------------------------
/packages/theme/src/tabbar-item.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-tabbar-item {
4 | flex: 1;
5 | display: flex;
6 | flex-direction: column;
7 | align-items: center;
8 | justify-content: center;
9 | color: #a9b1b9;
10 | &__icon {
11 | position: relative;
12 | margin-bottom: 5px;
13 | font-size: 16px;
14 | }
15 | &__icon--dot::after {
16 | content: '';
17 | position: absolute;
18 | width: 8px;
19 | height: 8px;
20 | border-radius: 50%;
21 | background-color: #f44;
22 | top: 0;
23 | right: 0;
24 | transform: translate(50%, -50%);
25 | }
26 | &__text {
27 | font-size: 12px;
28 | }
29 | &--active {
30 | color: $primary-color;
31 | }
32 | img {
33 | height: 20px;
34 | margin-bottom: 5px;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/examples/router.js:
--------------------------------------------------------------------------------
1 | import navConfig from './nav.config'
2 | import './utils/iframe-router'
3 |
4 | const registerRoutes = isDemo => {
5 | const routes = []
6 |
7 | if (isDemo) {
8 | routes.push({
9 | path: '/',
10 | component: () => import('./pages/demo-home'),
11 | meta: { hideNavBar: true }
12 | })
13 | } else {
14 | routes.push({
15 | path: '/',
16 | component: () => import('../README')
17 | })
18 | }
19 |
20 | navConfig.forEach(group => {
21 | group.list.forEach(nav => {
22 | routes.push({
23 | name: nav.name,
24 | path: nav.routePath,
25 | component: isDemo ? nav.demo : nav.doc,
26 | meta: { hideNavBar: nav.hideNavBar }
27 | })
28 | })
29 | })
30 |
31 | return routes
32 | }
33 |
34 | export default registerRoutes
35 |
--------------------------------------------------------------------------------
/packages/sticky/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | *
5 |
6 | top: 60px
7 |
8 | *
9 |
10 |
11 |
12 | *
13 |
14 | top: 300px
15 |
16 | *
17 |
18 | top: 350px
19 |
20 | *
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/packages/theme/src/actionsheet.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 | @import './popup.scss';
3 |
4 | .i-actionsheet {
5 | background-color: #f8f8f8;
6 | &__header,
7 | &__body,
8 | &__footer {
9 | background-color: #fff;
10 | }
11 | &__header {
12 | display: flex;
13 | align-items: center;
14 | justify-content: center;
15 | flex-direction: column;
16 | min-height: 50px;
17 | }
18 | &__action {
19 | &--disabled {
20 | opacity: 0.5;
21 | }
22 | }
23 | &__footer {
24 | margin-top: 10px;
25 | }
26 | &__action,
27 | &__footer {
28 | height: $action-height;
29 | line-height: $action-height;
30 | text-align: center;
31 | font-size: 16px;
32 | &:active:not(.i-actionsheet__action--disabled) {
33 | background-color: $border-color;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/docs/theme.md:
--------------------------------------------------------------------------------
1 | ## 更换主题
2 |
3 | 1、安装命令行主题构建工具
4 |
5 | ```bash
6 | npm i unique-theme-builder -g
7 | ```
8 |
9 | 2、修改主题变量 _只能修改,不要删除某个变量_
10 |
11 | 主题变量文件地址`node_modules/unique-ui/packages/theme/src/common/_var.scss`
12 |
13 | 3、构建主题
14 |
15 | ```bash
16 | # 必须在你工程根目录下输入
17 | utb # 等同于 utb -o .theme
18 | ```
19 |
20 | 你可以通过`-o`参数指定打包目录,默认 .theme
21 |
22 | 4、引入主题
23 |
24 | 如果是搭配 [babel-plugin-component](https://github.com/ElementUI/babel-plugin-component) 一起使用,只需要修改 .babelrc 的配置,指定 styleLibraryName 路径为自定义主题相对于 .babelrc 的路径,注意要加`~`
25 |
26 | ```javascript
27 | {
28 | // ...
29 | "plugins": [
30 | // ...
31 | [
32 | "component",
33 | {
34 | "libraryName": "unique-ui",
35 | "styleLibraryName": "~.theme"
36 | }
37 | ]
38 | ]
39 | }
40 | ```
41 |
42 | 如果没用这个插件,那么需要你手动引入构建后的主题文件,操作与以前一样,只是路径是你打包后的文件地址
43 |
--------------------------------------------------------------------------------
/packages/col/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
38 |
39 |
--------------------------------------------------------------------------------
/examples/assets/styles/global.scss:
--------------------------------------------------------------------------------
1 | ::-webkit-scrollbar-track {
2 | background-color: transparent;
3 | }
4 | ::-webkit-scrollbar {
5 | width: 6px;
6 | height: 6px;
7 | }
8 | ::-webkit-scrollbar-thumb {
9 | background-color: rgba(165, 181, 194, 0.5);
10 | border-radius: 3px;
11 | }
12 | ::-webkit-scrollbar-thumb:hover {
13 | background-color: rgba(165, 181, 194, 0.85);
14 | }
15 |
16 | html,
17 | body {
18 | height: 100%;
19 | }
20 | body {
21 | margin: 0;
22 | font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
23 | 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
24 | color: #34495e;
25 | font-size: 14px;
26 | }
27 | * {
28 | box-sizing: border-box;
29 | }
30 | a {
31 | text-decoration: none;
32 | }
33 | ul {
34 | list-style-type: none;
35 | margin: 0;
36 | padding: 0;
37 | }
38 |
--------------------------------------------------------------------------------
/packages/mixins/popup.js:
--------------------------------------------------------------------------------
1 | import Overlay from '../overlay'
2 |
3 | export default {
4 | props: {
5 | show: Boolean,
6 | position: {
7 | type: String,
8 | default: 'center'
9 | },
10 | overlay: {
11 | type: Boolean,
12 | default: true
13 | },
14 | overlayOpacity: {
15 | type: Number,
16 | default: 0.5
17 | },
18 | overlayColor: {
19 | type: String,
20 | default: '#000'
21 | },
22 | transitionName: String
23 | },
24 | mounted() {
25 | if (this.show && this.overlay) {
26 | Overlay.open(this)
27 | }
28 | },
29 | beforeDestroy() {
30 | Overlay.close(this)
31 | },
32 | watch: {
33 | show(val) {
34 | if (val && this.overlay) {
35 | Overlay.open(this)
36 | } else {
37 | Overlay.close(this)
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/tag/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
40 |
41 |
--------------------------------------------------------------------------------
/packages/tabbar/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
45 |
46 |
--------------------------------------------------------------------------------
/packages/theme/src/popup.scss:
--------------------------------------------------------------------------------
1 | .i-popup {
2 | backface-visibility: hidden;
3 | overflow-y: auto;
4 | -webkit-overflow-scrolling: touch;
5 | &--center {
6 | position: fixed;
7 | left: 50%;
8 | top: 50%;
9 | width: 85%;
10 | transform: translate3d(-50%, -50%, 0);
11 | }
12 | &--top {
13 | position: fixed;
14 | top: 0;
15 | left: 0;
16 | right: 0;
17 | max-height: 85%;
18 | transform: translate3d(0, 0, 0);
19 | }
20 | &--right {
21 | position: fixed;
22 | top: 0;
23 | bottom: 0;
24 | right: 0;
25 | transform: translate3d(0, 0, 0);
26 | }
27 | &--bottom {
28 | position: fixed;
29 | bottom: 0;
30 | left: 0;
31 | right: 0;
32 | max-height: 85%;
33 | transform: translate3d(0, 0, 0);
34 | }
35 | &--left {
36 | position: fixed;
37 | top: 0;
38 | bottom: 0;
39 | left: 0;
40 | transform: translate3d(0, 0, 0);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/docs/sticky.md:
--------------------------------------------------------------------------------
1 | ## Sticky 粘性定位
2 |
3 | 常用来实现吸顶效果,如果浏览器支持`sticky`定位,则使用原生的,否则会模拟实现,但可能与原生有些许差别
4 |
5 | ```html
6 | *
7 |
8 |
9 | top: 60px
10 |
11 |
12 | *
13 |
14 |
15 |
16 |
17 |
18 | *
19 |
20 |
21 | top: 300px
22 |
23 |
24 | *
25 |
26 |
27 | top: 350px
28 |
29 |
30 | *
31 | ```
32 |
33 |
34 | #### Props
35 |
36 | | 参数 | 说明 | 类型 | 默认值 |
37 | |------|------|------|------|
38 | | top | 距浏览器顶部的距离(单位为px) | `String | Number` | `0` |
39 | | z-index | 原生 z-index 属性 | `String | Number` | `1` |
40 |
--------------------------------------------------------------------------------
/examples/components/doc-simulator.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
16 |
17 |
38 |
--------------------------------------------------------------------------------
/examples/pages/demo-home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
一个 Vue2.x 移动端组件库
5 |
6 |
7 |
8 |
9 |
25 |
26 |
44 |
--------------------------------------------------------------------------------
/packages/popup/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
49 |
50 |
--------------------------------------------------------------------------------
/examples/components/demo-header.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
22 |
23 |
47 |
48 |
--------------------------------------------------------------------------------
/packages/uploader/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
25 |
26 |
50 |
51 |
--------------------------------------------------------------------------------
/packages/overlay/overlay.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
55 |
--------------------------------------------------------------------------------
/packages/switch/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 xiaojun1994
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/theme/src/switch.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 | @import './spinner.scss';
3 |
4 | $width: $switch-width - 2px;
5 | $height: $switch-height - 2px;
6 |
7 | .i-switch {
8 | position: relative;
9 | display: inline-block;
10 | width: $width;
11 | height: $height;
12 | border: 1px solid rgba(0, 0, 0, 0.1);
13 | border-radius: ($height + 2px) / 2;
14 | box-sizing: content-box;
15 | background-color: #fff;
16 | transition: background-color 0.3s;
17 | &__node {
18 | position: absolute;
19 | width: $height;
20 | height: $height;
21 | display: flex;
22 | align-items: center;
23 | justify-content: center;
24 | border-radius: 100%;
25 | top: 0;
26 | left: 0;
27 | box-shadow:
28 | 0 1px 1px 0 rgba(0, 0, 0, 0.05),
29 | 0 2px 2px 0 rgba(0, 0, 0, 0.1),
30 | 0 3px 3px 0 rgba(0, 0, 0, 0.05);
31 | background-color: #fff;
32 | transition: transform 0.3s;
33 | }
34 | &--on {
35 | background-color: $primary-color;
36 | .i-switch__node {
37 | transform: translateX($width - $height);
38 | }
39 | }
40 | &--disabled {
41 | opacity: 0.5;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/examples/app_docs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
41 |
42 |
49 |
--------------------------------------------------------------------------------
/packages/theme/src/common/_var.scss:
--------------------------------------------------------------------------------
1 | /* Color
2 | -------------------------- */
3 | $primary-color: #4a4d5a;
4 | $info-color: #409eff;
5 | $warning-color: #fdb470;
6 | $success-color: #36be52;
7 | $danger-color: #f86f74;
8 | $dark-color: #34495e;
9 | $light-color: #fff;
10 |
11 | /* Border
12 | -------------------------- */
13 | $border-radius: 2px;
14 | $border-color: #eee;
15 |
16 | /* NavBar
17 | -------------------------- */
18 | $nav-bar-height: 50px;
19 |
20 | /* TabBar
21 | -------------------------- */
22 | $tab-bar-height: 50px;
23 |
24 | /* Button
25 | -------------------------- */
26 | $button-height-mini: 25px;
27 | $button-height-small: 35px;
28 | $button-height-normal: 45px;
29 | $button-height-large: 50px;
30 |
31 | /* Tag
32 | -------------------------- */
33 | $tag-height: 24px;
34 |
35 | /* Switch
36 | -------------------------- */
37 | $switch-width: 50px;
38 | $switch-height: 30px;
39 |
40 | /* Tab
41 | -------------------------- */
42 | $tab-height_line: 44px;
43 | $tab-height_card: 30px;
44 |
45 | /* NoticeBar
46 | -------------------------- */
47 |
48 | /* Actionsheet
49 | -------------------------- */
50 | $action-height: 45px;
51 |
--------------------------------------------------------------------------------
/packages/theme/src/toast.scss:
--------------------------------------------------------------------------------
1 | @import './popup.scss';
2 |
3 | .i-popup.i-toast {
4 | background-color: rgba(50, 50, 51, 0.88);
5 | color: #fff;
6 | z-index: 9999;
7 | overflow: hidden;
8 | &__text {
9 | font-size: 14px;
10 | line-height: 2;
11 | }
12 | &__icon {
13 | i {
14 | font-size: 40px;
15 | }
16 | }
17 | &--normal {
18 | top: auto;
19 | bottom: 75px;
20 | width: fit-content;
21 | max-width: 80%;
22 | padding: 10px 30px;
23 | border-radius: 100px;
24 | }
25 | &--loading,
26 | &--success,
27 | &--fail {
28 | display: flex;
29 | flex-direction: column;
30 | align-items: center;
31 | justify-content: center;
32 | width: 100px;
33 | height: 100px;
34 | padding: 10px;
35 | border-radius: 5px;
36 | text-align: center;
37 | .toast__icon {
38 | width: 50px;
39 | height: 50px;
40 | display: flex;
41 | align-items: center;
42 | justify-content: center;
43 | i {
44 | font-size: 40px;
45 | }
46 | }
47 | .toast__text {
48 | width: 100%;
49 | margin-top: 5px;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/theme/src/radio.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | // transition-duration
4 | $duration: 0.3s;
5 |
6 | .i-radio {
7 | display: inline-flex;
8 | align-items: center;
9 | user-select: none;
10 | margin-right: 10px;
11 | &__icon {
12 | position: relative;
13 | height: 16px;
14 | width: 16px;
15 | border: 1px solid #ddd;
16 | border-radius: 50%;
17 | transition: border-color $duration;
18 | color: $primary-color;
19 | &::after {
20 | content: ' ';
21 | position: absolute;
22 | width: 10px;
23 | height: 10px;
24 | top: 3px;
25 | left: 3px;
26 | border-radius: 50%;
27 | background-color: currentColor;
28 | transform: scale(0.5);
29 | opacity: 0;
30 | transition: transform $duration, opacity $duration;
31 | }
32 | }
33 | &__label {
34 | font-size: 14px;
35 | margin-left: 5px;
36 | }
37 | &--checked {
38 | .i-radio__icon {
39 | border-color: currentColor;
40 | &::after {
41 | transform: scale(1);
42 | opacity: 1;
43 | }
44 | }
45 | }
46 | &--disabled {
47 | opacity: 0.5;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/docs/spinner.md:
--------------------------------------------------------------------------------
1 | ## Spinner 加载动画
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 |
8 |
9 |
10 |
11 | ```
12 |
13 | #### 设置大小
14 |
15 | ```html
16 |
17 |
18 |
19 |
20 |
21 | ```
22 |
23 | #### 自定义颜色
24 |
25 | ```html
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | #### Props
34 |
35 | | 参数 | 说明 | 类型 | 默认值 |
36 | |------|------|------|------|
37 | | type | 类型,可选值为`ios` `dots` `ripple` `lines` `crescent` | `String` | `ios` |
38 | | size | 大小 | `String` | `30px` |
39 | | color | 颜色 | `String` | 主题色 |
40 |
--------------------------------------------------------------------------------
/docs/switch.md:
--------------------------------------------------------------------------------
1 | ## Switch 开关
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 | ```
8 |
9 | #### 禁用状态
10 |
11 | ```html
12 |
13 | ```
14 |
15 | #### 加载状态
16 |
17 | 设置`loading`属性开启加载状态,此时不可点击
18 |
19 | ```html
20 |
21 | ```
22 |
23 | #### 自定义颜色
24 |
25 | ```html
26 |
27 | ```
28 |
29 | #### 搭配 Cell 使用
30 |
31 | ```html
32 |
33 |
34 |
35 |
36 |
37 | ```
38 |
39 | #### Props
40 |
41 | | 参数 | 说明 | 类型 | 默认值 |
42 | |------|------|------|------|
43 | | value | 为`true`代表打开,为`false`代表关闭 | `Boolean` | `false` |
44 | | disabled | 是否为禁用状态 | `Boolean` | `false` |
45 | | loading | 是否为加载状态 | `Boolean` | `false` |
46 | | active-color | 打开时的背景色 | `String` | 主题色 |
47 | | inactive-color | 关闭时的背景色 | `String` | `#fff` |
48 |
49 | #### Events
50 |
51 | | 事件名 | 说明 | 参数 |
52 | |------|------|------|
53 | | change | 切换时触发 | 状态 |
--------------------------------------------------------------------------------
/packages/theme/src/tag.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-tag {
4 | display: inline-flex;
5 | align-items: center;
6 | justify-content: center;
7 | height: $tag-height;
8 | padding: 0 10px;
9 | border-radius: $border-radius;
10 | background-color: $primary-color;
11 | color: $light-color;
12 | font-size: 12px;
13 | &::after {
14 | border-radius: $border-radius * 2;
15 | border-color: currentColor;
16 | }
17 | &--info {
18 | background-color: $info-color;
19 | }
20 | &--warning {
21 | background-color: $warning-color;
22 | }
23 | &--success {
24 | background-color: $success-color;
25 | }
26 | &--danger {
27 | background-color: $danger-color;
28 | }
29 | &--round {
30 | border-radius: $tag-height / 2;
31 | }
32 | &--plain {
33 | background-color: transparent;
34 | color: $primary-color;
35 | &.i-tag--info {
36 | color: $info-color;
37 | }
38 | &.i-tag--warning {
39 | color: $warning-color;
40 | }
41 | &.i-tag--success {
42 | color: $success-color;
43 | }
44 | &.i-tag--danger {
45 | color: $danger-color;
46 | }
47 | &.i-tag--round::after {
48 | border-radius: $tag-height;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/examples/index_docs.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './app_docs'
3 | import VueRouter from 'vue-router'
4 | import routes from './router'
5 | import 'highlight.js/styles/solarized-light.css'
6 | import './assets/styles/global.scss'
7 | import './assets/styles/docs.scss'
8 | import { isMobile } from './utils'
9 | import VueProgressBar from 'vue-progressbar'
10 |
11 | Vue.use(VueRouter)
12 | Vue.use(VueProgressBar, {
13 | color: "#ff7e4a",
14 | transition: {
15 | speed: '0.2s',
16 | opacity: '0.6s',
17 | termination: 300
18 | }
19 | })
20 |
21 | const router = new VueRouter({
22 | mode: 'hash',
23 | routes: routes(false)
24 | })
25 |
26 | router.beforeEach((to, from, next) => {
27 | Vue.prototype.$Progress.start()
28 | if (isMobile) {
29 | location.replace('mobile.html' + location.hash)
30 | }
31 | next()
32 | })
33 |
34 | router.afterEach((to, from) => {
35 | Vue.prototype.$Progress.finish()
36 | window.document.querySelector('.doc-container').scrollTo(0, 0)
37 | Vue.nextTick(window.syncPath)
38 | })
39 |
40 | window.vueRouter = router
41 |
42 | Vue.config.productionTip = false
43 |
44 | new Vue({
45 | el: '#app',
46 | router,
47 | components: { App },
48 | template: ''
49 | })
50 |
--------------------------------------------------------------------------------
/packages/tab-pane/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
58 |
59 |
--------------------------------------------------------------------------------
/packages/theme/src/cell.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-cell {
4 | position: relative;
5 | display: flex;
6 | min-height: 30px;
7 | padding: 10px 15px;
8 | background-color: #fff;
9 | &__icon {
10 | margin-right: 5px;
11 | .fa {
12 | font-size: 16px;
13 | }
14 | img {
15 | max-height: 32px;
16 | }
17 | }
18 |
19 | &__hd {
20 | display: flex;
21 | flex-direction: column;
22 | justify-content: center;
23 | margin-right: 8px;
24 | }
25 |
26 | &__bd {
27 | flex: 1;
28 | display: flex;
29 | align-items: center;
30 | justify-content: flex-end;
31 | }
32 |
33 | &__ft {
34 | margin-left: 8px;
35 | img {
36 | max-height: 32px;
37 | }
38 | }
39 |
40 | &__icon,
41 | &__ft {
42 | display: flex;
43 | align-items: center;
44 | justify-content: center;
45 | }
46 |
47 | &__title {
48 | line-height: 28px;
49 | }
50 | &__desc {
51 | font-size: 12px;
52 | }
53 |
54 | &__desc,
55 | &__value,
56 | &__arrow {
57 | color: #838993;
58 | }
59 |
60 | &__arrow.fa {
61 | font-size: 20px;
62 | }
63 |
64 | &--clickable {
65 | &:active {
66 | background-color: $border-color;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/packages/theme/src/modal.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 | @import './popup.scss';
3 |
4 | .i-modal {
5 | background-color: #fff;
6 | border-radius: 5px;
7 | &__title {
8 | padding-top: 30px;
9 | text-align: center;
10 | color: #1d273c;
11 | font-size: 15px;
12 | font-weight: bold;
13 | }
14 | &__body {
15 | padding: 20px 25px 25px 25px;
16 | color: #535d72;
17 | font-size: 16px;
18 | text-align: center;
19 | }
20 | &__footer {
21 | }
22 | &__btn-group {
23 | display: flex;
24 | align-items: center;
25 | justify-content: center;
26 | .button:not(:first-child) {
27 | margin-left: 12px;
28 | }
29 | }
30 | &__confirm-btn,
31 | &__cancel-btn {
32 | width: 100%;
33 | height: 50px;
34 | line-height: 50px;
35 | text-align: center;
36 | font-size: 15px;
37 | &:active {
38 | background-color: rgba(0, 0, 0, 0.05);
39 | }
40 | }
41 | &__confirm-btn {
42 | color: $info-color;
43 | }
44 | &__alert-btn {
45 | width: 100%;
46 | height: 50px;
47 | line-height: 50px;
48 | text-align: center;
49 | font-size: 15px;
50 | color: $primary-color;
51 | &:active {
52 | background-color: rgba(0, 0, 0, 0.05);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/spinner/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/packages/switch/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
58 |
59 |
--------------------------------------------------------------------------------
/packages/tabs/src/title.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
51 |
52 |
55 |
--------------------------------------------------------------------------------
/packages/theme/src/notice-bar.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-notice-bar {
4 | &__inner {
5 | position: relative;
6 | display: flex;
7 | align-items: center;
8 | padding: 10px 15px;
9 | font-size: 14px;
10 | background: #ffebc4;
11 | color: #df9952;
12 | }
13 |
14 | &__left {
15 | display: flex;
16 | align-items: center;
17 | margin-right: 2px;
18 | }
19 |
20 | &__main {
21 | flex: 1;
22 | position: relative;
23 | display: flex;
24 | align-items: center;
25 | overflow: hidden;
26 | }
27 | &__content {
28 | line-height: 20px;
29 | white-space: nowrap;
30 | &.ellipsis {
31 | max-width: 100%;
32 | }
33 | }
34 |
35 | &__right {
36 | display: flex;
37 | align-items: center;
38 | margin-left: 2px;
39 | }
40 | &__right-icon {
41 | font-size: 20px;
42 | }
43 |
44 | &--play {
45 | animation: notice-bar-slideInRight linear both;
46 | }
47 |
48 | &--loop {
49 | animation: notice-bar-slideInRight--loop linear infinite both;
50 | }
51 | }
52 |
53 | @keyframes notice-bar-slideInRight {
54 | to {
55 | transform: translate3d(-100%, 0, 0);
56 | }
57 | }
58 |
59 | @keyframes notice-bar-slideInRight--loop {
60 | to {
61 | transform: translate3d(-100%, 0, 0);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/docs/tag.md:
--------------------------------------------------------------------------------
1 | ## Tag 标记
2 |
3 | #### 简单用法
4 |
5 | ```html
6 | 标签
7 | 标签
8 | 标签
9 | 标签
10 | 标签
11 | ```
12 |
13 | #### 圆角样式
14 |
15 | ```html
16 | 标签
17 | 标签
18 | 标签
19 | 标签
20 | 标签
21 | ```
22 |
23 | #### 空心样式
24 |
25 | ```html
26 | 标签
27 | 标签
28 | 标签
29 | 标签
30 | 标签
31 | ```
32 |
33 | #### 自定义颜色
34 |
35 | ```html
36 | 标签
37 | 标签
38 | 标签
39 | 标签
40 | ```
41 |
42 | #### Props
43 |
44 | | 参数 | 说明 | 类型 | 默认值 |
45 | |------|------|------|------|
46 | | type | 类型,可选值为`primary` `info` `warning` `success` `danger` | `String` | `primary` |
47 | | color | 自定义标签颜色 | `String` | `''` |
48 | | plain | 是否为空心样式 | `Boolean` | `false` |
49 | | round | 是否为圆角样式 | `Boolean` | `false` |
50 |
--------------------------------------------------------------------------------
/docs/use.md:
--------------------------------------------------------------------------------
1 | ## 快速上手
2 |
3 | 字体图标文件未集成到`unique-ui`中,请在`index.html`中引入以下样式
4 |
5 | ```html
6 |
7 |
8 | ```
9 |
10 | #### 完整引入
11 |
12 | ```javascript
13 | import 'unique-ui/lib/theme/index.css' // 引入所有样式
14 | import uniqueUI from 'unique-ui'
15 | Vue.use(uniqueUI)
16 | ```
17 |
18 | #### 手动引入
19 |
20 | ```javascript
21 | import 'unique-ui/lib/theme/base.css' // 引入基本样式
22 | import 'unique-ui/lib/theme/button.css' // 引入组件样式
23 | import { Button } from 'unique-ui'
24 | Vue.use(Button)
25 | ```
26 |
27 | #### 按需引入(推荐)
28 |
29 | _可以帮你自动引入这个组件的样式_
30 |
31 | 首先安装 [babel-plugin-component](https://github.com/ElementUI/babel-plugin-component) 库
32 |
33 | ```bash
34 | npm install babel-plugin-component -D
35 | ```
36 |
37 | 然后修改`.babelrc`文件
38 |
39 | ```javascript
40 | {
41 | // ...
42 | "plugins": [
43 | // ...
44 | [
45 | "component",
46 | {
47 | "libraryName": "unique-ui",
48 | "styleLibraryName": "theme"
49 | }
50 | ]
51 | ]
52 | }
53 | ```
54 |
55 | 接下来,如果你只希望引入部分组件,比如`Button`和`Modal`,那么需要在`main.js`中写入以下内容:
56 |
57 | ```javascript
58 | import { Button, Modal } from 'unique-ui'
59 | Vue.use(Button)
60 | .use(Modal)
61 | ```
62 |
--------------------------------------------------------------------------------
/packages/tag/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 标签
5 | 标签
6 | 标签
7 | 标签
8 | 标签
9 |
10 |
11 | 标签
12 | 标签
13 | 标签
14 | 标签
15 | 标签
16 |
17 |
18 | 标签
19 | 标签
20 | 标签
21 | 标签
22 | 标签
23 |
24 |
25 | 标签
26 | 标签
27 | 标签
28 | 标签
29 |
30 |
31 |
32 |
33 |
40 |
--------------------------------------------------------------------------------
/packages/slide/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 1
6 | 2
7 | 3
8 | 4
9 |
10 |
11 |
12 |
13 | 1
14 | 2
15 | 3
16 | 4
17 |
18 | {{ props.active + 1 }} / 4
19 |
20 |
21 |
22 |
23 |
24 |
25 |
44 |
--------------------------------------------------------------------------------
/packages/table/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
10 | {{ item.title }}
11 |
12 |
13 |
27 |
28 |
29 |
30 |
60 |
--------------------------------------------------------------------------------
/packages/theme/src/nav-bar.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-nav-bar {
4 | height: $nav-bar-height;
5 | &__inner {
6 | position: relative;
7 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
8 | height: $nav-bar-height;
9 | background-color: #fff;
10 | color: $primary-color;
11 | }
12 | &__left {
13 | height: 100%;
14 | position: absolute;
15 | top: 0;
16 | left: 10px;
17 | display: flex;
18 | align-items: center;
19 | justify-content: center;
20 | &:active {
21 | opacity: 0.5;
22 | }
23 | .i-nav-bar__arrow {
24 | font-size: 25px;
25 | margin-top: -1px;
26 | }
27 | .i-nav-bar__text {
28 | font-size: 14px;
29 | margin-left: -6px;
30 | }
31 | }
32 | &__title {
33 | max-width: 50%;
34 | height: $nav-bar-height;
35 | line-height: $nav-bar-height;
36 | text-align: center;
37 | margin: 0 auto;
38 | font-size: 16px;
39 | color: $dark-color;
40 | }
41 | &__right {
42 | height: 100%;
43 | position: absolute;
44 | top: 0;
45 | right: 10px;
46 | display: flex;
47 | align-items: center;
48 | justify-content: center;
49 | &:active {
50 | opacity: 0.5;
51 | }
52 | }
53 | &--fixed {
54 | .i-nav-bar__inner {
55 | position: fixed;
56 | z-index: 99;
57 | top: 0;
58 | left: 0;
59 | width: 100%;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/packages/tabbar-item/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
13 | {{ label }}
14 |
15 |
16 |
17 |
65 |
66 |
--------------------------------------------------------------------------------
/packages/nav-bar/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 | {{ leftText }}
17 |
18 |
19 |
20 |
21 | {{ title }}
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
63 |
64 |
--------------------------------------------------------------------------------
/packages/utils/shared.js:
--------------------------------------------------------------------------------
1 | // 日期格式化
2 | export function dateFormat(date, fmt = 'yyyy-MM-dd hh:mm:ss') {
3 | var o = {
4 | 'M+': date.getMonth() + 1, // 月份
5 | 'd+': date.getDate(), // 日
6 | 'h+': date.getHours(), // 时
7 | 'm+': date.getMinutes(), // 分
8 | 's+': date.getSeconds(), // 秒
9 | 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
10 | S: date.getMilliseconds() // 毫秒
11 | }
12 | if (/(y+)/.test(fmt)) {
13 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
14 | }
15 | for (var k in o) {
16 | if (new RegExp('(' + k + ')').test(fmt)) {
17 | fmt = fmt.replace(
18 | RegExp.$1,
19 | RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
20 | )
21 | }
22 | }
23 | return fmt
24 | }
25 | // 数字前补 0
26 | export function prefixInteger(num, n = 2) {
27 | return (Array(n).join(0) + num).slice(-n)
28 | }
29 |
30 | // 防抖
31 | export function debounce(fn, delay) {
32 | let timer = null
33 | return function(...args) {
34 | clearTimeout(timer)
35 | timer = setTimeout(() => {
36 | fn.call(this, ...args)
37 | }, delay)
38 | }
39 | }
40 |
41 | // 节流
42 | export function throttle(fn, delay, cb) {
43 | let time = null
44 | return function(...args) {
45 | const curTime = new Date()
46 | if (time && curTime - time < delay) {
47 | return typeof cb === 'function' && cb.call(this)
48 | }
49 | time = curTime
50 | fn.call(this, ...args)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A mobile component library for Vue2.x
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | > :warning: 由于我工作中很久未再使用 vue 技术栈,且 vue3 也已发布,该仓库没有动力继续维护。
16 |
17 | _这个 UI 库是我练手所用,质量可想而知,所以不要用在正式环境哦~_
18 |
19 | _其中大量代码参考(抄袭)了 [vant](https://github.com/youzan/vant) ,少量代码参考了 [element-ui](https://github.com/ElemeFE/element)、[vux](https://github.com/airyland/vux) 等其它库_
20 |
21 | ### 👀 预览
22 |
23 | https://xiaojundebug.github.io/unique-ui/
24 |
25 | ### 🌵 安装
26 |
27 | ```bash
28 | npm i unique-ui
29 | ```
30 |
31 | ### 🚀 快速开始
32 |
33 | ```javascript
34 | import Vue from 'vue'
35 | import Unique from 'unique-ui'
36 |
37 | Vue.use(Unique)
38 | ```
39 |
40 | ### 💩 多年后对该项目的一些感想与反思
41 |
42 | - commit message 不规范,有些 message 看起来很呆
43 | - 主题功能薄弱,需要依靠手动构建文件
44 | - icon 用的 `Font Awesom`,使用方式比较简陋
45 | - 不该暴露一些公共方法,这对于一个 ui 库来说“管的太宽了”,况且写的还不咋样
46 | - 没有单元测试
47 | - 😀 还有。。。。现在感觉这个组件库的名字比较一般
48 |
49 | ...
50 |
--------------------------------------------------------------------------------
/packages/table/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
64 |
--------------------------------------------------------------------------------
/packages/actionsheet/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 简单用法
5 |
6 |
7 | 显示取消按钮
8 |
9 |
10 | 自定义样式
11 |
12 |
13 |
14 |
15 |
16 | 确定吗?
17 | 删除之后就无法取消了哦
18 |
19 |
20 |
21 |
22 |
23 |
42 |
43 |
50 |
--------------------------------------------------------------------------------
/examples/components/doc-nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
27 |
28 |
67 |
68 |
--------------------------------------------------------------------------------
/packages/radio/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
73 |
74 |
--------------------------------------------------------------------------------
/packages/toast/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Component from './src'
3 |
4 | const Toast = Vue.extend(Component)
5 | let vm = null
6 | let timer = null
7 |
8 | function clear() {
9 | try {
10 | document.body.removeChild(vm.$el)
11 | vm.$destroy()
12 | vm = null
13 | } catch (error) {}
14 | }
15 |
16 | function handler(msg, opts = {}) {
17 | if (vm) clear()
18 | if (timer) window.clearTimeout(timer)
19 |
20 | vm = new Toast()
21 | document.body.appendChild(vm.$mount().$el)
22 |
23 | const { type, duration = 2500, overlay } = opts
24 |
25 | vm.text = msg + '' // 设置弹窗内容
26 | vm.type = type // 设置弹窗类型
27 | vm.overlay = overlay
28 |
29 | vm.show = true
30 |
31 | vm.$on('toggle', function(val) {
32 | this.show = val
33 | })
34 |
35 | if (duration) {
36 | timer = setTimeout(() => {
37 | vm.show = false
38 | }, duration)
39 | }
40 | }
41 |
42 | Component.toast = (msg, opts = {}) => handler(msg, { type: 'normal', ...opts, overlay: false })
43 | Component.loading = (msg, opts = {}) => handler(msg, { duration: 0, ...opts, type: 'loading' })
44 | Component.success = (msg, opts = {}) => handler(msg, { ...opts, type: 'success' })
45 | Component.fail = (msg, opts = {}) => handler(msg, { ...opts, type: 'fail' })
46 |
47 | Component.install = function(Vue) {
48 | Vue.prototype.$toast = this.toast
49 | Vue.prototype.$toast.loading = this.loading
50 | Vue.prototype.$toast.success = this.success
51 | Vue.prototype.$toast.fail = this.fail
52 |
53 | Vue.prototype.$toast.close = clear
54 |
55 | Vue.component(Component.name, Component)
56 | }
57 |
58 | export default Component
59 |
--------------------------------------------------------------------------------
/docs/utils.md:
--------------------------------------------------------------------------------
1 | ## 实用代码
2 |
3 | `unique-ui`中集成了一些常用工具代码
4 |
5 | #### 1px 方案
6 |
7 | 基于伪类 + transform 实现,提供了以下几个内置类名
8 |
9 | - 上边`i-1px--t`
10 | - 右边`i-1px--r`
11 | - 下边`i-1px--b`
12 | - 左边`i-1px--l`
13 | - 全部`i-1px`
14 |
15 | #### 单行省略
16 |
17 | 提供了内置类名`ellipsis`
18 |
19 | #### 日期格式化
20 |
21 | > dateFormat(date[, fmt = 'yyyy-MM-dd hh:mm:ss'])
22 | >
23 | > - date\: Date 实例
24 | > - fmt\: 格式,默认为 'yyyy-MM-dd hh:mm:ss'
25 |
26 | ```javascript
27 | import { utils: { dateFormat } } from 'unique'
28 | // 常规用法
29 | dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss')
30 | // 只保留年月日部分
31 | dateFormat(new Date(), 'yyyy-MM-dd')
32 | // 只保留时间部分
33 | dateFormat(new Date(), 'hh:mm:ss')
34 | // 随意组合
35 | dateFormat(new Date(), 'yyyy-MM-dd 00:00:00')
36 | ```
37 |
38 | #### 数字前补 0
39 |
40 | > prefixInteger(num[, n = 2])
41 | >
42 | > - num\: 被修饰数字
43 | > - n\: 修饰成多少位,默认 2 位
44 |
45 | ```javascript
46 | import { utils: { prefixInteger } } from 'unique'
47 | prefixInteger(9, 2) // 09
48 | prefixInteger(15, 3) // 015
49 | ```
50 |
51 | #### 防抖
52 |
53 | > debounce(fn, delay)
54 | >
55 | > - fn\: 被装饰方法
56 | > - delay\: 间隔多少毫秒
57 |
58 | ```javascript
59 | import { utils: { debounce } } from 'unique'
60 | const search = debounce(function() {
61 | // ...
62 | }, 300)
63 | ```
64 |
65 | #### 节流
66 |
67 | > throttle(fn, delay[, cb])
68 | >
69 | > - fn\: 被装饰方法
70 | > - delay\: 间隔多少毫秒
71 | > - cb\: 节流发挥作用时触发
72 |
73 | ```javascript
74 | import { utils: { throttle } } from 'unique'
75 | const query = throttle(
76 | function() {
77 | // ...
78 | },
79 | 1000,
80 | function() {
81 | console.log('请求次数过于频繁')
82 | }
83 | )
84 | ```
85 |
--------------------------------------------------------------------------------
/packages/modal/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | alert
5 | confirm
6 |
7 |
8 | 异步关闭
9 |
10 |
11 | 组件调用
12 |
13 |
20 |
25 |
26 |
27 |
28 |
29 |
47 |
48 |
64 |
--------------------------------------------------------------------------------
/docs/slide.md:
--------------------------------------------------------------------------------
1 | ## Slide 轮播图
2 |
3 | ```scss
4 | // 示例样式
5 | .i-slide-item {
6 | display: flex;
7 | align-items: center;
8 | justify-content: center;
9 | font-size: 38px;
10 | color: #fff;
11 | &:nth-child(odd) {
12 | background-color: #787e8f;
13 | }
14 | &:nth-child(even) {
15 | background-color: #9398a6;
16 | }
17 | }
18 | ```
19 |
20 | #### 简单用法
21 |
22 | ```html
23 |
24 | 1
25 | 2
26 | 3
27 | 4
28 |
29 | ```
30 |
31 | #### 自定义指示器
32 |
33 | ```html
34 |
35 | 1
36 | 2
37 | 3
38 | 4
39 |
40 | {{ props.active + 1 }} / 4
41 |
42 |
43 | ```
44 |
45 | #### Slide Props
46 |
47 | | 参数 | 说明 | 类型 | 默认值 |
48 | |------|------|------|------|
49 | | loop | 是否可以无缝循环轮播 | `Boolean` | `true` |
50 | | autoplay | 自动轮播毫秒数,`0`代表不自动轮播 | `Number` | `3000` |
51 | | duration | 动画时长,单位毫秒 | `Number` | `500` |
52 | | initial-slide | 初始位置索引值 | `Number` | `0` |
53 |
54 | #### Slide Slots
55 |
56 | | 名称 | 说明 | slot-scope |
57 | |------|------|------|
58 | | indicator | 自定义指示器 | active: 当前索引 |
59 |
60 | #### Slide Methods
61 |
62 | | 方法名 | 参数 | 返回值 | 介绍 |
63 | |------|------|------|------|
64 | | slideTo | 索引 | - | 切换到指定位置 |
65 |
66 | #### Slide Events
67 |
68 | | 事件名 | 说明 | 参数 |
69 | |------|------|------|
70 | | change | 滑动完成后触发 | 当前索引 |
71 |
--------------------------------------------------------------------------------
/packages/theme/src/common/_transition.scss:
--------------------------------------------------------------------------------
1 | /* 淡入
2 | -------------------------- */
3 | .fadeIn-enter-active,
4 | .fadeIn-leave-active {
5 | transition: opacity 0.3s !important;
6 | }
7 | .fadeIn-enter,
8 | .fadeIn-leave-to {
9 | opacity: 0 !important;
10 | }
11 |
12 | /* 从上面滑动到下面
13 | -------------------------- */
14 | .slideInDown-enter-active,
15 | .slideInDown-leave-active {
16 | transition: transform 0.35s !important;
17 | }
18 | .slideInDown-enter,
19 | .slideInDown-leave-to {
20 | transform: translate3d(0, -100%, 0) !important;
21 | }
22 |
23 | /* 从右面滑动到左面
24 | -------------------------- */
25 | .slideInRight-enter-active,
26 | .slideInRight-leave-active {
27 | transition: transform 0.35s !important;
28 | }
29 | .slideInRight-enter,
30 | .slideInRight-leave-to {
31 | transform: translate3d(100%, 0, 0) !important;
32 | }
33 |
34 | /* 从左面滑动到右面
35 | -------------------------- */
36 | .slideInLeft-enter-active,
37 | .slideInLeft-leave-active {
38 | transition: transform 0.35s !important;
39 | }
40 | .slideInLeft-enter,
41 | .slideInLeft-leave-to {
42 | transform: translate3d(-100%, 0, 0) !important;
43 | }
44 |
45 | /* 从下面滑动到上面
46 | -------------------------- */
47 | .slideInUp-enter-active,
48 | .slideInUp-leave-active {
49 | transition: transform 0.35s !important;
50 | }
51 | .slideInUp-enter,
52 | .slideInUp-leave-to {
53 | transform: translate3d(0, 100%, 0) !important;
54 | }
55 |
56 | /* 从中间淡入放大
57 | -------------------------- */
58 | .zoomIn-enter-active,
59 | .zoomIn-leave-active {
60 | transition: opacity 0.3s, transform 0.3s !important;
61 | }
62 | .zoomIn-enter {
63 | opacity: 0;
64 | transform: translate3d(-50%, -50%, 0) scale(0.7) !important;
65 | }
66 | .zoomIn-leave-to {
67 | opacity: 0;
68 | transform: translate3d(-50%, -50%, 0) scale(0.9) !important;
69 | }
70 |
--------------------------------------------------------------------------------
/docs/toast.md:
--------------------------------------------------------------------------------
1 | ## Toast 消息提示
2 |
3 | #### 简单使用
4 |
5 | _第一个参数代表消息内容,第二个参数传入一个 options 配置对象,仅支持单例模式_
6 |
7 | ```javascript
8 | import { Toast } from 'unique-ui'
9 |
10 | /* 普通提示 */
11 | Toast.toast('hello~')
12 |
13 | /* 加载提示 */
14 | Toast.toast('Loading...', { type: 'loading', duration: 3000 })
15 | Toast.loading('Loading...', { duration: 3000 })
16 |
17 | /* 成功提示 */
18 | Toast.toast('成功', { type: 'success' })
19 | Toast.success('成功')
20 |
21 | /* 失败提示 */
22 | Toast.toast('失败', { type: 'fail' })
23 | Toast.fail('失败')
24 | ```
25 |
26 | #### 全局使用
27 |
28 | > 推荐用`Vue.use`方式来使用本组件,以后便可以在每个Vue实例上直接通过`this.$toast`方式使用
29 |
30 | ```javascript
31 | import { Toast } from 'unique-ui'
32 | Vue.use(Toast)
33 |
34 | /* 普通提示 */
35 | this.$toast('hello~')
36 |
37 | /* 加载提示 */
38 | this.$toast('Loading...', { type: 'loading', duration: 3000 })
39 | this.$toast.loading('Loading...', { duration: 3000 })
40 |
41 | /* 成功提示 */
42 | this.$toast('成功', { type: 'success' })
43 | this.$toast.success('成功')
44 |
45 | /* 失败提示 */
46 | this.$toast('失败', { type: 'fail' })
47 | this.$toast.fail('失败')
48 | ```
49 |
50 | #### Options(第二个参数)
51 |
52 | | 参数 | 说明 | 类型 | 默认值 |
53 | |------|------|------|------|
54 | | type | 类型,可选值为`normal` `loading` `success` `fail` | `String` | `'normal'` |
55 | | duration | 多久自动消失,`0`代表不消失,单位毫秒 | `Number` | 当`type`为`loading`时默认是`0`,其它为`2500` |
56 | | overlay | 是否显示一个透明度为`0`的蒙版,防止用户点击其它地方,只在`type`不为`normal`时生效 | `Boolean` | `true` |
57 |
58 | #### Props
59 |
60 | | 参数 | 说明 | 类型 | 默认值 |
61 | |------|------|------|------|
62 | | show | 是否显示 | `Boolean` | `false` |
63 | | type | 同 Options 中一致 | `String` | `normal` |
64 | | text | 文字内容 | `String` | `''` |
65 | | overlay | 是否显示一个透明度为`0`的蒙版,不同于 Options 中,这里所有`type`下都会生效 | `Boolean` | `true` |
66 |
67 |
68 | #### Slots
69 |
70 | | 参数 | 说明 |
71 | |------|------|
72 | | icon | 图标 |
73 | | text | 文字 |
74 |
--------------------------------------------------------------------------------
/packages/modal/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Component from './src'
3 |
4 | const Modal = Vue.extend(Component)
5 | let vm = null
6 |
7 | function clear() {
8 | try {
9 | document.body.removeChild(vm.$el)
10 | vm.$destroy()
11 | vm = null
12 | } catch (error) {}
13 | }
14 |
15 | function handler(msg, opts = {}) {
16 | return new Promise((resolve, reject) => {
17 | if (vm) clear()
18 |
19 | vm = new Modal()
20 | document.body.appendChild(vm.$mount().$el)
21 |
22 | const {
23 | type,
24 | title,
25 | confirmText,
26 | cancelText,
27 | closeOnClickOverlay,
28 | autoClose = true,
29 | transitionName
30 | } = opts
31 |
32 | title && (vm.title = title)
33 | vm.text = msg
34 | vm.type = type
35 | vm.closeOnClickOverlay = closeOnClickOverlay
36 | vm.transitionName = transitionName
37 |
38 | confirmText && (vm.confirmText = confirmText)
39 | cancelText && (vm.cancelText = cancelText)
40 |
41 | vm.show = true
42 |
43 | if (autoClose) {
44 | vm.$on('toggle', function(val) {
45 | this.show = val
46 | })
47 | }
48 | vm.$on('cancel', _ => reject('cancel'))
49 | vm.$on('confirm', _ =>
50 | resolve(() => {
51 | vm.show = false
52 | })
53 | )
54 | })
55 | }
56 |
57 | Component.modal = (msg, opts = {}) => handler(msg, { type: 'alert', ...opts })
58 | Component.alert = (msg, opts = {}) => handler(msg, { ...opts, type: 'alert' })
59 | Component.confirm = (msg, opts = {}) => handler(msg, { ...opts, type: 'confirm' })
60 |
61 | Component.install = function(Vue) {
62 | Vue.prototype.$modal = this.modal
63 | Vue.prototype.$modal.alert = this.alert
64 | Vue.prototype.$modal.confirm = this.confirm
65 |
66 | Vue.component(Component.name, Component)
67 | }
68 |
69 | export default Component
70 |
--------------------------------------------------------------------------------
/packages/tabs/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | { this.$toast('Current: ' + index) }">
5 | Vue
6 | React
7 | Angular
8 |
9 |
10 |
11 |
12 | Vue
13 | React
14 | Angular
15 |
16 |
17 |
18 |
19 | 洗护
20 | 生鲜
21 | 男装
22 | 女装
23 | 手机
24 | 零食
25 | 果饮
26 |
27 |
28 |
29 |
30 |
31 | label1
32 | label1
33 |
34 |
35 | label2
36 | label2
37 |
38 |
39 |
40 |
41 |
42 |
43 |
55 |
--------------------------------------------------------------------------------
/examples/components/doc-header.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
24 |
25 |
50 |
--------------------------------------------------------------------------------
/packages/toast/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
19 |
23 |
27 |
28 |
29 |
33 |
34 | {{ text }}
35 |
36 |
37 |
38 |
39 |
40 |
86 |
87 |
--------------------------------------------------------------------------------
/docs/popup.md:
--------------------------------------------------------------------------------
1 | ## Popup 弹出层
2 |
3 | > `Popup` 组件在整个组件库中是一个十分重要的基本组件,很多弹出类组件都依赖于它
4 |
5 | #### 位置
6 |
7 | 通过`position`属性来设置弹层出现位置
8 |
9 | ```html
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```
26 |
27 | #### 自定义样式
28 |
29 | ```html
30 |
31 |
32 |
33 | ```
34 |
35 | ```css
36 | .fade-enter-active,
37 | .fade-leave-active {
38 | transition: opacity 0.3s, transform 0.3s;
39 | }
40 | .fade-enter,
41 | .fade-leave-to {
42 | opacity: 0;
43 | transform: translate3d(-50%, -50%, 0);
44 | }
45 | ```
46 |
47 | #### Props
48 |
49 | | 参数 | 说明 | 类型 | 默认值 |
50 | |------|------|------|------|
51 | | show | 是否显示 | `Boolean` | `false` |
52 | | position | 位置,可选值为`center` `top` `right` `bottom` `left` | `String` | `center` |
53 | | overlay | 是否显示蒙版 | `Boolean` | `true` |
54 | | overlay-opacity | 蒙版透明度 | `Number` | `0.5` |
55 | | overlay-color | 蒙版颜色 | `String` | `#000` |
56 | | transition-name | 同 vue 中`transition`的`name`属性 | `String` | 取决于`position` |
57 |
58 | #### Events
59 |
60 | | 事件名 | 说明 | 参数 |
61 | |------|------|------|
62 | | click-overlay | 点击蒙版时触发 | - |
63 |
--------------------------------------------------------------------------------
/packages/cell/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
11 |
12 |
13 |
14 |
18 |
19 | {{ title }}
20 | {{ desc }}
24 |
25 |
26 |
27 |
28 |
29 | {{ value }}
30 |
31 |
32 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
83 |
84 |
--------------------------------------------------------------------------------
/docs/actionsheet.md:
--------------------------------------------------------------------------------
1 | ## Actionsheet 上拉菜单
2 |
3 | #### 简单用法
4 |
5 | 需要传入一个`actions`数组,数组的每一项是一个对象,对象属性见文档下方表格。
6 |
7 | ```html
8 |
9 | ```
10 |
11 | ```javascript
12 | export default {
13 | data() {
14 | return {
15 | show: false,
16 | actions: [{ name: '唱' }, { name: '跳' }, { name: 'rap' }, { name: '篮球', disabled: true }],
17 | }
18 | },
19 | methods: {
20 | onSelect(data) {
21 | this.$toast(data.name)
22 | }
23 | }
24 | }
25 | ```
26 |
27 | #### 显示取消按钮
28 |
29 | 传入`cancel-text`以显示底部按钮
30 |
31 |
32 | ```html
33 |
34 | ```
35 |
36 | #### 自定义样式
37 |
38 | ```html
39 |
40 |
41 | 确定吗?
42 | 删除之后就无法取消了哦
43 |
44 |
45 | ```
46 |
47 | ```javascript
48 | export default {
49 | data() {
50 | return {
51 | show: false,
52 | actions: [{ name: '删除', className: 'danger' }],
53 | }
54 | }
55 | }
56 | ```
57 |
58 | ```scss
59 | .danger {
60 | color: #f86f74;
61 | }
62 | ```
63 |
64 | #### Props
65 |
66 | | 参数 | 说明 | 类型 | 默认值 |
67 | |------|------|------|------|
68 | | show | 是否显示 | `Boolean` | `false` |
69 | | actions | 选项,请参考下方详情 | `Array` | `[]` |
70 | | cancel-text | 取消按钮文字 | `String` | `''` |
71 | | close-on-click-overlay | 点击蒙版时是否自动关闭 | `Boolean` | `false` |
72 |
73 | #### Actions
74 |
75 | | 参数 | 说明 |
76 | |------|------|
77 | | name | 选项内容 |
78 | | disabled | 禁用该项 |
79 | | className | 设置额外class |
80 |
81 | #### Slots
82 |
83 | | 名称 | 说明 |
84 | |------|------|
85 | | header | 头部区域 |
86 | | footer | 尾部区域 |
87 |
88 | #### Events
89 |
90 | | 事件名 | 说明 | 参数 |
91 | |------|------|------|
92 | | select | 选中时触发 | 该项对应数据 |
93 | | cancel | 取消时触发 | - |
--------------------------------------------------------------------------------
/packages/overlay/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Component from './overlay' // 引入 overlay 组件
3 | const O = Vue.extend(Component)
4 | let overlayVM = null
5 |
6 | let zIndex = 1000
7 | const getZIndex = function() {
8 | return zIndex++
9 | }
10 |
11 | const Overlay = {
12 | instances: [],
13 | // 打开遮罩层
14 | open(instance) {
15 | if (!instance || this.instances.indexOf(instance) !== -1) return
16 | if (!overlayVM) {
17 | // 当没有遮盖层时,新建遮盖层
18 | this.createOverlay()
19 | }
20 | // 禁止页面滚动
21 | this.bodyOverflow = document.body.style.overflow
22 | document.body.style.overflow = 'hidden'
23 | // 设置内容的z-index
24 | instance.$el.style.zIndex = getZIndex()
25 | overlayVM.color = instance.overlayColor
26 | overlayVM.opacity = instance.overlayOpacity
27 | overlayVM.show = true
28 |
29 | this.instances.push(instance)
30 | },
31 | // 关闭遮罩层
32 | close(instance) {
33 | const index = this.instances.indexOf(instance)
34 | if (index === -1) return
35 |
36 | Vue.nextTick(() => {
37 | this.instances.splice(index, 1)
38 |
39 | // 当页面上没有弹出层了就关闭遮盖层
40 | if (this.instances.length === 0) {
41 | this.closeOverlay()
42 | }
43 | })
44 | },
45 | createOverlay() {
46 | overlayVM = new O()
47 | overlayVM.onClick = this.handleOverlayClick.bind(this)
48 | document.body.appendChild(overlayVM.$mount().$el)
49 | // 设置遮罩层z-index
50 | overlayVM.$el.style.zIndex = getZIndex()
51 | },
52 | // 关闭遮罩层
53 | closeOverlay() {
54 | if (!overlayVM) return
55 | document.body.style.overflow = this.bodyOverflow
56 | overlayVM.show = false
57 | },
58 | // 处理遮罩层点击事件
59 | handleOverlayClick() {
60 | if (this.instances.length === 0) return
61 | const instance = this.instances[this.instances.length - 1]
62 | const { handleOverlayClick } = instance
63 | if (handleOverlayClick && typeof handleOverlayClick === 'function') {
64 | handleOverlayClick()
65 | }
66 | }
67 | }
68 |
69 | export default Overlay
70 |
--------------------------------------------------------------------------------
/packages/actionsheet/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
14 |
15 | -
21 | {{ item.name }}
22 |
23 |
24 |
33 |
34 |
35 |
36 |
85 |
86 |
--------------------------------------------------------------------------------
/docs/table.md:
--------------------------------------------------------------------------------
1 | ## Table 表格
2 |
3 | 一个简单的表格组件,使用`ul`模拟而成
4 |
5 | ```html
6 |
7 | ```
8 |
9 | #### 用法
10 |
11 | ```javascript
12 | export default {
13 | data() {
14 | return {
15 | tableColumns: [
16 | {
17 | title: 'Name',
18 | key: 'name',
19 | width: 120,
20 | },
21 | {
22 | title: 'Age',
23 | key: 'age',
24 | align: 'right',
25 | width: 70,
26 | render(val) {
27 | if (val >= 18) {
28 | return "" + val + ''
29 | } else {
30 | return "" + val + ''
31 | }
32 | }
33 | },
34 | {
35 | title: 'Address',
36 | key: 'address'
37 | }
38 | ],
39 | tableData: [
40 | {
41 | name: 'John Brown',
42 | age: 14,
43 | address: 'New York No. 1 Lake Park'
44 | },
45 | {
46 | name: 'Jim Green',
47 | age: 24,
48 | address: 'London No. 1 Lake Park'
49 | },
50 | {
51 | name: 'Joe Black',
52 | age: 30,
53 | address: 'Sydney No. 1 Lake Park'
54 | },
55 | {
56 | name: 'Jon Snow',
57 | age: 17,
58 | address: 'Ottawa No. 2 Lake Park'
59 | }
60 | ]
61 | }
62 | }
63 | }
64 | ```
65 |
66 | #### Props
67 |
68 | | 参数 | 说明 | 类型 | 默认值 |
69 | |------|------|------|------|
70 | | columns | 列配置,详情见下个表格 | `Array` | `[]` |
71 | | data | 数据 | `Array` | `[]` |
72 |
73 | #### columns
74 |
75 | | 参数 | 说明 | 类型 | 默认值 |
76 | |------|------|------|------|
77 | | title | 列名 | `String` | `''` |
78 | | key | 字段名 | `String` | `''` |
79 | | width | 列宽度,单位 px | `Number` | `100` |
80 | | align | 内容对齐方式,同 css 中 text-align | `String` | `left` |
81 | | render | 自定义渲染,参数为原始值 | `Function` | `''` |
82 |
83 | #### Events
84 |
85 | | 事件名 | 说明 | 参数 |
86 | |------|------|------|
87 | | click-row | 点击某行时触发 | 当前行原始数据 |
--------------------------------------------------------------------------------
/packages/theme/src/button.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 | @import './spinner.scss';
3 |
4 | .i-button {
5 | position: relative;
6 | display: inline-flex;
7 | align-items: center;
8 | justify-content: center;
9 | border: 1px solid currentColor;
10 | border-radius: $border-radius;
11 | background-color: currentColor;
12 | vertical-align: middle;
13 |
14 | &::before {
15 | content: ' ';
16 | position: absolute;
17 | top: 50%;
18 | left: 50%;
19 | opacity: 0;
20 | width: 100%;
21 | height: 100%;
22 | border: inherit;
23 | border-color: #000;
24 | background-color: #000;
25 | border-radius: inherit;
26 | transform: translate(-50%, -50%);
27 | }
28 |
29 | &:active::before {
30 | opacity: 0.05;
31 | }
32 |
33 | &:disabled, &--loading { opacity: 0.5; &:active::before { opacity: 0; } }
34 |
35 | &__text { color: $light-color; }
36 |
37 | .i-spinner { margin-right: 3px; }
38 |
39 | &--plain, &--dashed { background-color: #fff; .i-button__text { color: currentColor; } }
40 |
41 | &--dashed { border-style: dashed; }
42 |
43 | &--round { border-radius: 10em; }
44 |
45 | &--circle {
46 | border-radius: 50%;
47 | overflow: hidden;
48 | &.i-button--normal { width: $button-height-normal; }
49 | &.i-button--large { width: $button-height-large; }
50 | &.i-button--small { width: $button-height-small; }
51 | &.i-button--mini { width: $button-height-mini; }
52 | }
53 |
54 | &--default { color: $border-color; .i-button__text { color: $dark-color; } }
55 |
56 | &--normal { height: $button-height-normal; padding: 0 17px; font-size: 14px; }
57 |
58 | &--primary { color: $success-color; }
59 |
60 | &--info { color: $info-color; }
61 |
62 | &--danger { color: $danger-color; }
63 |
64 | &--warning { color: $warning-color; }
65 |
66 | &--large { width: 100%; height: $button-height-large; padding: 0 15px; font-size: 15px; }
67 |
68 | &--small { height: $button-height-small; padding: 0 px; font-size: 13px; }
69 |
70 | &--mini { height: $button-height-mini; padding: 0 10px; font-size: 12px; }
71 | }
72 |
--------------------------------------------------------------------------------
/packages/button/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 默认按钮
5 | 主要按钮
6 | 信息按钮
7 | 危险按钮
8 | 警告按钮
9 |
10 |
11 | 空心按钮
12 | 空心按钮
13 |
14 |
15 | 虚线按钮
16 | 虚线按钮
17 |
18 |
19 |
20 |
21 |
22 |
23 | 圆角按钮
24 | 圆角按钮
25 |
26 |
27 | 禁用状态
28 | 加载状态
29 |
30 |
31 | 自定义颜色
32 | 自定义颜色
33 |
34 |
35 |
36 |
39 | 正常按钮
40 | 小型按钮
41 | 迷你按钮
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
56 |
57 |
--------------------------------------------------------------------------------
/packages/checkbox/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ value1 }}
5 |
6 |
7 | {{ value2 }}
8 |
9 |
10 | value: {{ value3 }}
11 |
12 |
13 | disabled
14 |
15 |
16 |
17 |
18 |
19 | {{ props.value }}
20 |
21 |
22 |
23 |
24 |
25 | a
26 | b
27 | c
28 | d
29 |
30 | 当前选择:{{ value7 }}
31 |
32 |
33 |
34 | $refs.a.toggle()">
35 |
36 |
37 | $refs.b.toggle()">
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
61 |
--------------------------------------------------------------------------------
/packages/uploader/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
83 |
--------------------------------------------------------------------------------
/examples/index_mobile.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './app_mobile'
3 | import VueRouter from 'vue-router'
4 | import routes from './router'
5 | import 'packages/theme/src/index.scss'
6 | import uniqueUI from 'src'
7 | import DemoBlock from './components/demo-block.vue'
8 | import VueProgressBar from 'vue-progressbar'
9 | import { isMobile } from './utils'
10 |
11 | Vue.component(DemoBlock.name, DemoBlock)
12 |
13 | Vue.use(VueRouter)
14 | Vue.use(uniqueUI)
15 | Vue.use(VueProgressBar, {
16 | color: '#8d8f91',
17 | transition: {
18 | speed: '0.2s',
19 | opacity: '0.6s',
20 | termination: 300
21 | }
22 | })
23 |
24 | const router = new VueRouter({
25 | mode: 'hash',
26 | routes: routes(true)
27 | })
28 |
29 | router.beforeEach((to, from, next) => {
30 | Vue.prototype.$Progress.start()
31 | next()
32 | })
33 |
34 | router.afterEach((to, from) => {
35 | Vue.prototype.$Progress.finish()
36 | if (!router.currentRoute.redirectedFrom) {
37 | window.scrollTo(0, 0)
38 | Vue.nextTick(window.syncPath)
39 | }
40 | })
41 |
42 | window.vueRouter = router
43 |
44 | Vue.config.productionTip = false
45 |
46 | new Vue({
47 | el: '#app',
48 | router,
49 | components: { App },
50 | template: ''
51 | })
52 |
53 | if (!isMobile) {
54 | import('./utils/touch-simulator')
55 |
56 | // const touchPointEl = document.querySelector('.touch-point')
57 | // const { style } = touchPointEl
58 |
59 | // function correctPosition(ev) {
60 | // const { clientX, clientY } = ev
61 | // style.top = clientY - touchPointEl.offsetWidth / 2 + 'px'
62 | // style.left = clientX - touchPointEl.offsetWidth / 2 + 'px'
63 | // }
64 |
65 | // function onMousedown(ev) {
66 | // style.opacity = '0.3'
67 | // correctPosition(ev)
68 | // window.addEventListener('mousemove', onMousemove, true)
69 | // }
70 |
71 | // function onMousemove(ev) {
72 | // style.opacity = '0.3'
73 | // correctPosition(ev)
74 | // }
75 |
76 | // function onMouseup(ev) {
77 | // style.opacity = '0'
78 | // window.removeEventListener('mousemove', onMousemove, true)
79 | // }
80 |
81 | // window.addEventListener('mousedown', onMousedown, true)
82 | // window.addEventListener('mouseup', onMouseup, true)
83 | }
84 |
--------------------------------------------------------------------------------
/packages/button/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
98 |
99 |
--------------------------------------------------------------------------------
/packages/sticky/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
93 |
94 |
--------------------------------------------------------------------------------
/packages/notice-bar/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
29 |
30 |
37 |
38 |
--------------------------------------------------------------------------------
/packages/theme/src/tabs.scss:
--------------------------------------------------------------------------------
1 | @import './common/var';
2 |
3 | .i-tab {
4 | position: relative;
5 | overflow: hidden;
6 | &--line {
7 | padding-top: $tab-height-line;
8 | background-color: #fff;
9 | .i-tab__wrap {
10 | height: $tab-height_line;
11 | }
12 | .i-tab__nav {
13 | box-sizing: content-box;
14 | height: 100%;
15 | padding-bottom: 15px;
16 | }
17 | .i-tab__title {
18 | height: 100%;
19 | color: #999;
20 | & > span {
21 | line-height: $tab-height_line;
22 | }
23 | &--active {
24 | color: #333;
25 | }
26 | }
27 | }
28 | &--card {
29 | padding-top: $tab-height-card;
30 | .i-tab__wrap {
31 | height: $tab-height_card;
32 | overflow: hidden;
33 | }
34 | .i-tab__nav {
35 | box-sizing: border-box;
36 | height: 100%;
37 | margin: 0 15px;
38 | border: 1px solid $info-color;
39 | border-radius: 2px;
40 | background-color: #fff;
41 | }
42 | .i-tab__title {
43 | height: 100%;
44 | color: $info-color;
45 | & > span {
46 | line-height: $tab-height_card - 2px;
47 | }
48 | &--active {
49 | background-color: $info-color;
50 | color: #fff;
51 | }
52 | &:not(:last-child) {
53 | border-right: 1px solid $info-color;
54 | }
55 | }
56 | }
57 |
58 | &__wrap {
59 | position: absolute;
60 | top: 0;
61 | right: 0;
62 | left: 0;
63 | z-index: 1;
64 | overflow: hidden;
65 | }
66 | &__nav {
67 | position: relative;
68 | display: flex;
69 | user-select: none;
70 | }
71 | &__title {
72 | flex: 1;
73 | position: relative;
74 | box-sizing: border-box;
75 | padding: 0 5px;
76 | font-size: 14px;
77 | text-align: center;
78 | overflow: hidden;
79 | & > span {
80 | display: block;
81 | }
82 | }
83 | &__track {
84 | position: absolute;
85 | bottom: 15px;
86 | left: 0;
87 | z-index: 1;
88 | height: 3px;
89 | background-color: $info-color;
90 | }
91 | &--scrollable {
92 | .i-tab__nav {
93 | overflow-x: auto;
94 | -webkit-overflow-scrolling: touch;
95 | }
96 | .i-tab__title {
97 | flex: 0 0 22%;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/docs/tabs.md:
--------------------------------------------------------------------------------
1 | ## Tabs 标签页
2 |
3 | > 此 demo 通过手机浏览最佳
4 |
5 | #### 简单用法
6 |
7 | ```html
8 | { this.$toast('Current: ' + index) }">
9 | Vue
10 | React
11 | Angular
12 |
13 | ```
14 |
15 | #### 样式风格
16 |
17 | ```html
18 |
19 | Vue
20 | React
21 | Angular
22 |
23 | ```
24 |
25 | #### 横向滚动
26 |
27 | 超过 4 个后会开启横向滚动
28 |
29 | ```html
30 |
31 | 洗护
32 | 生鲜
33 | 男装
34 | 女装
35 | 手机
36 | 零食
37 | 果饮
38 |
39 | ```
40 |
41 | #### 自定义标签
42 |
43 | ```html
44 |
45 |
46 | label1
47 | label1
48 |
49 |
50 | label2
51 | label2
52 |
53 |
54 | ```
55 |
56 | #### Tabs Props
57 |
58 | | 参数 | 说明 | 类型 | 默认值 |
59 | |------|------|------|------|
60 | | value | 当前选中项索引 | `Number` | `0` |
61 | | type | 整体样式风格,可选值为`line` `card`| `String` | `line` |
62 | | color | 当`type`为`line`时是指示条的颜色,
当`type`为`card`时是背景色和未激活文字颜色 | `String` | `''` |
63 | | active-color | 激活文字颜色 | `String` | `''` |
64 | | inactive-color | 未激活文字颜色 | `String` | `''` |
65 | | animated | 是否开启内容区切换动画 | `Boolean` | `false` |
66 | | duration | 设置该组件全局动画时长,单位秒 | `Number | String` | `0.3` |
67 | | lazy | 是否切换到当前 tab 以后才渲染 | `Boolean` | `true` |
68 |
69 | #### TabPane Props
70 |
71 | | 参数 | 说明 | 类型 | 默认值 |
72 | |------|------|------|------|
73 | | label | tab 标题 | `String` | `''` |
74 |
75 | #### TabPane Slots
76 |
77 | | 名称 | 说明 |
78 | |------|------|
79 | | label | 标题区域内容 |
80 |
81 | #### Tabs Events
82 |
83 | | 事件名 | 说明 | 参数 |
84 | |------|------|------|
85 | | change | 选中项改变时触发 | 索引 |
--------------------------------------------------------------------------------
/examples/assets/styles/docs.scss:
--------------------------------------------------------------------------------
1 | .doc-container h1,
2 | .doc-container h2,
3 | .doc-container h3,
4 | .doc-container h4,
5 | .doc-container h5,
6 | .doc-container h6 {
7 | line-height: 1.5;
8 | font-weight: 400;
9 | color: #333;
10 | }
11 |
12 | .doc-container h1 {
13 | font-size: 40px;
14 | }
15 |
16 | .doc-container h2 {
17 | font-size: 30px;
18 | }
19 |
20 | .doc-container h3 {
21 | font-size: 22px;
22 | }
23 |
24 | .doc-container h4 {
25 | font-size: 18px;
26 | }
27 |
28 | .doc-container p {
29 | margin: 15px 0;
30 | font-size: 14px;
31 | line-height: 26px;
32 | color: #34495e;
33 | }
34 |
35 | .doc-container li > code,
36 | .doc-container p > code,
37 | .doc-container table code {
38 | display: inline;
39 | margin: 2px;
40 | padding: 2px 7px;
41 | border-radius: 2px;
42 | color: #e96900;
43 | background-color: #f1f4f8;
44 | }
45 |
46 | .doc-container pre.hljs {
47 | background: #f6f8fa;
48 | padding: 1.3em;
49 | line-height: 1.5em;
50 | }
51 |
52 | .doc-container pre.hljs .hljs-comment {
53 | font-style: italic;
54 | font-size: 13px;
55 | }
56 |
57 | .doc-container code {
58 | font-family: Menlo, Monaco, Consolas, 'Courier New', 'PingFang SC';
59 | }
60 |
61 | .doc-container table {
62 | width: 100%;
63 | font-size: 13px;
64 | line-height: 1.5;
65 | margin-bottom: 45px;
66 | background-color: #fff;
67 | border-collapse: collapse;
68 | color: #34495e;
69 | }
70 |
71 | .doc-container table th {
72 | padding: 10px;
73 | text-align: left;
74 | font-weight: 400;
75 | background-color: #f1f4f8;
76 | }
77 | .doc-container table td {
78 | padding: 10px;
79 | border-bottom: 1px solid #f1f4f8;
80 | line-height: 1.8;
81 | }
82 |
83 | .doc-container a {
84 | color: #008df6;
85 | &:hover {
86 | text-decoration: underline;
87 | }
88 | }
89 |
90 | .doc-container blockquote {
91 | border-left: 4px solid #dcdcdc;
92 | margin: 20px 0;
93 | padding: 0 15px;
94 | p {
95 | margin: 0;
96 | }
97 | }
98 |
99 | .doc-container ul {
100 | display: block;
101 | list-style-type: disc;
102 | margin-block-start: 1em;
103 | margin-block-end: 1em;
104 | margin-inline-start: 0px;
105 | margin-inline-end: 0px;
106 | padding-inline-start: 40px;
107 | }
108 |
109 | .doc-container ul > li {
110 | list-style: circle;
111 | line-height: 32px;
112 | }
113 |
--------------------------------------------------------------------------------
/docs/radio.md:
--------------------------------------------------------------------------------
1 | ## Radio 单选框
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 | a
8 | b
9 | c
10 |
11 | ```
12 |
13 | #### 自定义颜色
14 |
15 | ```html
16 |
17 | a
18 | b
19 | c
20 |
21 | ```
22 |
23 | #### 禁用
24 |
25 | ```html
26 |
27 | a
28 | b
29 | c
30 |
31 | ```
32 |
33 | #### 自定义图标
34 |
35 | ```html
36 |
37 |
38 | a
39 |
40 |
41 | b
42 |
43 |
44 | c
45 |
46 |
47 | ```
48 |
49 | #### 搭配 Cell 使用
50 |
51 | ```html
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | ```
63 |
64 | #### RadioGroup Props
65 |
66 | | 参数 | 说明 | 类型 | 默认值 |
67 | |------|------|------|------|
68 | | value | 被选中项的`value`值 | `Boolean | Number | String` | - |
69 | | disabled | 是否禁用所有单选框 | `Boolean` | `false` |
70 |
71 | #### Radio Props
72 |
73 | | 参数 | 说明 | 类型 | 默认值 |
74 | |------|------|------|------|
75 | | value | 该单选框被选中后的值,可以认为是一个唯一标识 | `Boolean | Number | String` | - |
76 | | disabled | 是否禁用该单选框 | `Boolean` | `false` |
77 | | color | 选中状态图标背景色 | `String` | 主题色 |
78 |
79 | #### Radio Slots
80 |
81 | | 名称 | 说明 | slot-scope |
82 | |------|------|------|
83 | | icon | 自定义图标 | checked: 该单选框是否被选中 |
84 |
85 | #### RadioGroup Events
86 |
87 | | 事件名 | 说明 | 参数 |
88 | |------|------|------|
89 | | change | 选中项改变时触发 | 被选中项的`value`值 |
90 |
--------------------------------------------------------------------------------
/packages/tabbar/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
{{ item }}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/packages/popup/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 中
5 | 上
6 | 右
7 | 下
8 | 左
9 |
10 |
11 | 自定义样式
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
36 |
37 |
38 |
39 |
40 |
41 |
55 |
56 |
79 |
--------------------------------------------------------------------------------
/docs/button.md:
--------------------------------------------------------------------------------
1 | ## Button 按钮
2 |
3 | #### 按钮类型
4 |
5 | 支持`default` `primary` `info` `danger` `warning`五种类型,默认为`default`
6 |
7 | ```html
8 | 默认按钮
9 | 主要按钮
10 | 信息按钮
11 | 危险按钮
12 | 警告按钮
13 | ```
14 |
15 | #### 空心按钮
16 |
17 | ```html
18 | 空心按钮
19 | 空心按钮
20 | ```
21 |
22 | #### 虚线按钮
23 |
24 | ```html
25 | 虚线按钮
26 | 虚线按钮
27 | ```
28 |
29 | #### 圆形按钮
30 |
31 | ```html
32 |
33 |
34 | ```
35 |
36 | #### 圆角按钮
37 |
38 | ```html
39 | 圆角按钮
40 | 圆角按钮
41 | ```
42 |
43 | #### 按钮状态
44 |
45 | ```html
46 | 禁用状态
47 | 加载状态
48 | ```
49 |
50 | #### 自定义颜色
51 |
52 | ```html
53 | 自定义颜色
54 | 自定义颜色
55 |
56 | ```
57 |
58 | #### 按钮尺寸
59 |
60 | ```html
61 | 大号按钮
62 | 正常按钮
63 | 小型按钮
64 | 迷你按钮
65 | ```
66 |
67 | #### Props
68 |
69 | | 参数 | 说明 | 类型 | 默认值 |
70 | |------|------|------|------|
71 | | type | 类型,可选值为 `default` `primary`
`info` `danger` `warning` | `String` | `default` |
72 | | plain | 是否为空心按钮 | `Boolean` | `false` |
73 | | dashed | 是否为虚线按钮 | `Boolean` | `false` |
74 | | circle | 是否为圆形按钮 | `Boolean` | `false` |
75 | | round | 是否为圆角按钮 | `Boolean` | `false` |
76 | | disabled | 是否禁用 | `Boolean` | `false` |
77 | | loading | 是否为 loading 状态 | `Boolean` | `false` |
78 | | size | 尺寸,可选值为 `normal` `large`
`small` `mini` | `String` | `normal` |
79 | | color | 按钮颜色 | `String` | `''` |
80 | | text-color | 按钮字体颜色 | `String` | 1、未设置`color`情况下为`''`
2、否则为`color`或`#fff`
_取决于`plain` `dashed`_ |
81 |
82 | #### Events
83 |
84 | | 事件名 | 说明 | 参数 |
85 | |------|------|------|
86 | | click | 点击按钮且按钮状态不为加载或禁用时触发 | 原生事件对象 |
87 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Actionsheet from 'packages/actionsheet'
2 | import Button from 'packages/button'
3 | import Cell from 'packages/cell'
4 | import CellGroup from 'packages/cell-group'
5 | import Checkbox from 'packages/checkbox'
6 | import CheckboxGroup from 'packages/checkbox-group'
7 | import Col from 'packages/col'
8 | import Field from 'packages/field'
9 | import Icon from 'packages/icon'
10 | import Modal from 'packages/modal'
11 | import NavBar from 'packages/nav-bar'
12 | import NoticeBar from 'packages/notice-bar'
13 | import Popup from 'packages/popup'
14 | import Radio from 'packages/radio'
15 | import RadioGroup from 'packages/radio-group'
16 | import Row from 'packages/row'
17 | import Slide from 'packages/slide'
18 | import SlideItem from 'packages/slide-item'
19 | import Spinner from 'packages/spinner'
20 | import Sticky from 'packages/sticky'
21 | import Switch from 'packages/switch'
22 | import Tabbar from 'packages/tabbar'
23 | import TabbarItem from 'packages/tabbar-item'
24 | import Table from 'packages/table'
25 | import TabPane from 'packages/tab-pane'
26 | import Tabs from 'packages/tabs'
27 | import Tag from 'packages/tag'
28 | import Toast from 'packages/toast'
29 | import Uploader from 'packages/uploader'
30 |
31 | const components = [
32 | Actionsheet,
33 | Button,
34 | Cell,
35 | CellGroup,
36 | Checkbox,
37 | CheckboxGroup,
38 | Col,
39 | Field,
40 | Icon,
41 | Modal,
42 | NavBar,
43 | NoticeBar,
44 | Popup,
45 | Radio,
46 | RadioGroup,
47 | Row,
48 | Slide,
49 | SlideItem,
50 | Spinner,
51 | Sticky,
52 | Switch,
53 | Tabbar,
54 | TabbarItem,
55 | Table,
56 | TabPane,
57 | Tabs,
58 | Tag,
59 | Toast,
60 | Uploader
61 | ]
62 |
63 | export {
64 | Actionsheet,
65 | Button,
66 | Cell,
67 | CellGroup,
68 | Checkbox,
69 | CheckboxGroup,
70 | Col,
71 | Field,
72 | Icon,
73 | Modal,
74 | NavBar,
75 | NoticeBar,
76 | Popup,
77 | Radio,
78 | RadioGroup,
79 | Row,
80 | Slide,
81 | SlideItem,
82 | Spinner,
83 | Sticky,
84 | Switch,
85 | Tabbar,
86 | TabbarItem,
87 | Table,
88 | TabPane,
89 | Tabs,
90 | Tag,
91 | Toast,
92 | Uploader
93 | }
94 |
95 | const install = function(Vue) {
96 | components.forEach(component => {
97 | Vue.use(component)
98 | })
99 | }
100 |
101 | if (typeof window !== 'undefined' && window.Vue) {
102 | install(window.Vue)
103 | }
104 |
105 | export default {
106 | install
107 | }
108 |
--------------------------------------------------------------------------------
/packages/checkbox/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
14 |
15 |
19 |
20 |
21 |
22 |
101 |
102 |
--------------------------------------------------------------------------------
/packages/radio/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | a
6 | b
7 | c
8 |
9 |
10 |
11 |
12 | a
13 | b
14 | c
15 |
16 |
17 |
18 |
19 | a
20 | b
21 | c
22 |
23 |
24 |
25 |
26 |
27 | a
34 |
35 |
36 | b
43 |
44 |
45 | c
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
83 |
84 |
--------------------------------------------------------------------------------
/examples/components/demo-nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ data.groupName }}
5 |
6 |
7 |
8 |
9 | {{ nav.name }}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
43 |
44 |
102 |
--------------------------------------------------------------------------------
/examples/components/doc-brand.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
23 |
24 |
95 |
96 |
--------------------------------------------------------------------------------
/docs/notice-bar.md:
--------------------------------------------------------------------------------
1 | ## NoticeBar 通告栏
2 |
3 | ```javascript
4 | export default {
5 | data() {
6 | return {
7 | msg1: '您订阅的双11抽奖活动已开始,共3次抽奖机会,仅限今日。',
8 | msg2: '网络不给力,请检查网络设置。'
9 | }
10 | }
11 | }
12 | ```
13 |
14 | #### 多种模式
15 |
16 | ```html
17 |
18 |
19 |
20 | ```
21 |
22 | #### 禁止滚动
23 |
24 | 通过`scrollable`属性设置消息过长是否自动滚动,默认`true`,允许滚动
25 |
26 | ```html
27 |
28 | ```
29 |
30 | #### 高级用法
31 |
32 | ```html
33 |
34 |
35 |
36 | ```
37 |
38 | #### Props
39 |
40 | | 参数 | 说明 | 类型 | 默认值 |
41 | |------|------|------|------|
42 | | text | 文本消息| `String` | `''` |
43 | | mode | 模式 | `String`,可另选为`closeable` `link` | `''` |
44 | | scrollable | 超出一行自动滚动 | `Boolean` | `true` |
45 | | speed | 滚动速率 (px/s) | `Number` | `50` |
46 | | delay | 动画延迟时间 (s) | `Number` | `1` |
47 | | background-color | 背景色 | `String` | `#ffebc4` |
48 | | color | 文字颜色 | `String` | `#df9952` |
49 |
50 | #### Slots
51 |
52 | | 名称 | 说明 |
53 | |------|------|
54 | | left | 自定义左侧区域内容 |
55 | | right | 自定义右侧区域内容 |
56 |
57 | #### Events
58 |
59 | | 事件名 | 说明 | 参数 |
60 | |------|------|------|
61 | | click | 点击时触发 | - |
62 |
--------------------------------------------------------------------------------
/examples/app_mobile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
65 |
66 |
112 |
--------------------------------------------------------------------------------
/packages/row/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | span: 8
6 | span: 8
7 | span: 8
8 |
9 |
10 | span: 5
11 | span: 15, offset: 4
12 |
13 |
14 |
15 |
16 | span: 8
17 | span: 8
18 | span: 8
19 |
20 |
21 |
22 |
23 | span: 6
24 | span: 6
25 | span: 6
26 |
27 |
28 | span: 6
29 | span: 6
30 | span: 6
31 |
32 |
33 | span: 6
34 | span: 6
35 | span: 6
36 |
37 |
38 | span: 6
39 | span: 6
40 | span: 6
41 |
42 |
43 | span: 6
44 | span: 6
45 | span: 6
46 |
47 |
48 |
49 |
50 | span: 6
51 | span: 6
52 | span:
6
53 |
54 |
55 | span:
6
56 | span: 6
57 | span: 6
58 |
59 |
60 | span:
6
61 | span: 6
62 | span
:
6
63 |
64 |
65 |
66 |
67 |
68 |
87 |
--------------------------------------------------------------------------------
/packages/modal/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 | {{ title }}
16 |
17 |
18 |
19 |
20 |
21 | {{ text }}
22 |
23 |
24 |
25 |
26 |
53 |
54 |
55 |
56 |
57 |
116 |
--------------------------------------------------------------------------------
/docs/layout.md:
--------------------------------------------------------------------------------
1 | ## Layout 布局
2 |
3 | 基于`flex`实现,提供`i-row`和`i-col`两个组件进行布局
4 |
5 | #### 简单用法
6 |
7 | 提供了`24`列栅格,可以在`col`上添加`span`属性设置该列所占格数,还可以通过`offset`属性设置偏移格数
8 |
9 | ```html
10 |
11 | span: 8
12 | span: 8
13 | span: 8
14 |
15 |
16 | span: 5
17 | span: 15, offset: 4
18 |
19 | ```
20 |
21 | #### 在列元素之间增加间距
22 |
23 | 通过`gutter`设置列间距,默认为`0`
24 |
25 | ```html
26 |
27 | span: 8
28 | span: 8
29 | span: 8
30 |
31 | ```
32 |
33 | #### 主轴对齐方式
34 |
35 | ```html
36 |
37 |
38 | span: 6
39 | span: 6
40 | span: 6
41 |
42 |
43 |
44 | span: 6
45 | span: 6
46 | span: 6
47 |
48 |
49 |
50 | span: 6
51 | span: 6
52 | span: 6
53 |
54 |
55 |
56 | span: 6
57 | span: 6
58 | span: 6
59 |
60 |
61 |
62 | span: 6
63 | span: 6
64 | span: 6
65 |
66 | ```
67 |
68 | #### 交叉轴对齐方式
69 |
70 | ```html
71 |
72 |
73 | span: 6
74 | span: 6
75 | span:
6
76 |
77 |
78 |
79 | span:
6
80 | span: 6
81 | span: 6
82 |
83 |
84 |
85 | span:
6
86 | span: 6
87 | span
:
6
88 |
89 | ```
90 |
91 | #### Row Props
92 |
93 | | 参数 | 说明 | 类型 | 默认值 |
94 | |------|------|------|------|
95 | | gutter | 列元素之间的间距(单位为px) | `String | Number` | - |
96 | | justify | 主轴对齐方式,可选值为`start` `center` `end`
`space-around` `space-between` | `String` | `start` |
97 | | align | 交叉轴对齐方式,可选值为 `top` `center` `bottom` | `String` | `top` |
98 |
99 | #### Col Props
100 |
101 | | 参数 | 说明 | 类型 | 默认值 |
102 | |------|------|------|------|
103 | | span | 列元素所占格数 | `String | Number` | `24` |
104 | | offset | 列元素偏移格数 | `String | Number` | - |
105 |
--------------------------------------------------------------------------------
/docs/tabbar.md:
--------------------------------------------------------------------------------
1 | ## Tabbar 标签栏
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 |
8 |
9 |
10 |
11 | ```
12 |
13 | ```javascript
14 | export default {
15 | data() {
16 | return {
17 | active: '/shopping-cart'
18 | }
19 | }
20 | }
21 | ```
22 |
23 | #### 自定义颜色
24 |
25 | ```html
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | ```javascript
34 | export default {
35 | data() {
36 | return {
37 | active: '/star'
38 | }
39 | }
40 | }
41 | ```
42 |
43 | #### 高级用法
44 |
45 | 通过插槽定制内容
46 |
47 | ```html
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | ```javascript
62 | export default {
63 | data() {
64 | return {
65 | active: '/share'
66 | }
67 | }
68 | }
69 | ```
70 |
71 | #### Tabbar Props
72 |
73 | | 参数 | 说明 | 类型 | 默认值 |
74 | |------|------|------|------|
75 | | value | 选中某项,传入值为该项`value` | `String` | `''` |
76 | | inactive-color | 未激活文字的颜色 | `String` | `#a9b1b9` |
77 | | active-color | 已激活文字的颜色 | `String` | 主题色 |
78 | | fixed | 是否固定在底部 | `Boolean` | `true` |
79 |
80 | #### TabbarItem Props
81 |
82 | | 参数 | 说明 | 类型 | 默认值 |
83 | |------|------|------|------|
84 | | label | 标签文字 | `String` | `''` |
85 | | value | 唯一标识 | `String` | `''` |
86 | | icon | 图标 | `String` | `''` |
87 | | dot | 是否显示图标右上角小红点 | `Boolean` | `''` |
88 |
89 | #### TabbarItem Slots
90 |
91 | | 名称 | 说明 | slot-scope |
92 | |------|------|------|
93 | | icon | 自定义图标 | active: 是否为选中标签 |
94 |
95 | #### Tabbar Events
96 |
97 | | 事件名 | 说明 | 参数 |
98 | |------|------|------|
99 | | change | 切换标签时触发 | 当前选中标签的value |
--------------------------------------------------------------------------------
/docs/checkbox.md:
--------------------------------------------------------------------------------
1 | ## Checkbox 复选框
2 |
3 | #### 简单用法
4 |
5 | ```html
6 | {{ value }}
7 | ```
8 |
9 | #### 自定义颜色
10 |
11 | ```html
12 | {{ value }}
13 | ```
14 |
15 | #### 自定义状态值
16 |
17 | ```html
18 | value: {{ value }}
19 | ```
20 |
21 | #### 禁用
22 |
23 | ```html
24 | disabled
25 | ```
26 |
27 | #### 自定义图标
28 |
29 | ```html
30 |
31 |
32 |
33 | {{ props.value }}
34 |
35 |
36 | ```
37 |
38 | #### Checkbox 组
39 |
40 | 需要与`CheckboxGroup`搭配使用,选中值是一个数组,数组中的项是`Checkbox`上`name`属性设置的值,可以通过设置`max`属性来限制最大选中数量
41 |
42 | ```html
43 |
44 | a
45 | b
46 | c
47 | d
48 |
49 | ```
50 |
51 | #### 搭配 Cell 使用
52 |
53 | `Checkbox`提供了一个`toggle`方法用来切换选中状态,你可以搭配`Cell`组件一起使用
54 |
55 | ```html
56 |
57 | $refs.a.toggle()">
58 |
59 |
60 | $refs.b.toggle()">
61 |
62 |
63 |
64 | ```
65 |
66 | #### CheckboxGroup Props
67 |
68 | | 参数 | 说明 | 类型 | 默认值 |
69 | |------|------|------|------|
70 | | value | 所有选中项`name`值集合 | `Array` | `[]` |
71 | | disabled | 是否禁用所有复选框 | `Boolean` | `false` |
72 | | max | 限制最大选中数量,`0`代表不限制 | `Number` | `0` |
73 |
74 | #### Checkbox Props
75 |
76 | | 参数 | 说明 | 类型 | 默认值 |
77 | |------|------|------|------|
78 | | name | 标识符,与`CheckboxGroup`组件搭配使用 | `String | Number` | `''` |
79 | | value | 状态值 | `Boolean | Number | String` | - |
80 | | true-value | 设置选中状态的值 | `Boolean | Number | String` | `true` |
81 | | false-value | 设置未选中状态的值 | `Boolean | Number | String` | `false` |
82 | | disabled | 是否禁用该复选框 | `Boolean` | `false` |
83 | | color | 选中状态图标背景色 | `String` | 主题色 |
84 |
85 | #### Checkbox Slots
86 |
87 | | 名称 | 说明 | slot-scope |
88 | |------|------|------|
89 | | icon | 自定义图标 | value: 状态值 |
90 |
91 | #### Checkbox Methods
92 |
93 | | 方法名 | 参数 | 返回值 | 介绍 |
94 | |------|------|------|------|
95 | | toggle | - | - | 切换选中状态 |
96 |
97 | #### CheckboxGroup Events
98 |
99 | | 事件名 | 说明 | 参数 |
100 | |------|------|------|
101 | | change | 选中项改变时触发 | 所有选中项`name`值集合 |
102 |
103 | #### Checkbox Events
104 |
105 | | 事件名 | 说明 | 参数 |
106 | |------|------|------|
107 | | change | 切换时触发 | 状态值 |
--------------------------------------------------------------------------------
/docs/modal.md:
--------------------------------------------------------------------------------
1 | ## Modal 弹窗
2 |
3 | #### 使用方法
4 |
5 | _第一个参数代表消息内容,第二个参数传入一个 options 配置对象,仅支持单例模式_
6 |
7 | ```javascript
8 | import { Modal } from 'unique-ui'
9 |
10 | /* Alert */
11 | Modal.modal('Are you ok?', { type: 'alert', title: '👽' })
12 | Modal.alert('Are you ok?', { title: '👽' })
13 |
14 | /* Confirm */
15 | Modal.modal('大郎,起来喝药了', { type: 'confirm', title: '提示' })
16 | Modal.confirm('大郎,起来喝药了', { title: '提示' })
17 | ```
18 |
19 | #### 异步关闭
20 |
21 | ```javascript
22 | // 要想使用异步关闭,autoClose一定要传false
23 | Modal.alert('异步关闭', { title: '提示', autoClose: false }).then(close => {
24 | setTimeout(() => {
25 | close()
26 | }, 1000)
27 | })
28 | ```
29 |
30 | ### 全局使用
31 |
32 | > 推荐用`Vue.use`方式来使用本组件,以后便可以在每个Vue实例上直接通过`this.$modal`方式使用
33 |
34 | ```javascript
35 | import { Modal } from 'unique-ui'
36 | Vue.use(Modal)
37 |
38 | /* Alert */
39 | this.$modal('Are you ok?', { type: 'alert', title: '👽' })
40 | this.$modal.alert('Are you ok?', { title: '👽' })
41 |
42 | /* Confirm */
43 | this.$modal('大郎,起来喝药了', { type: 'confirm', title: '提示' })
44 | this.$modal.confirm('大郎,起来喝药了', { title: '提示' })
45 | ```
46 |
47 | #### 组件调用
48 |
49 | 通过组件使用以深度定制样式
50 |
51 | ```html
52 |
53 |
54 |
55 | ```
56 |
57 | ```scss
58 | .modal-enter-active,
59 | .modal-leave-active {
60 | transition: opacity 0.45s, transform 0.45s;
61 | }
62 | .modal-enter {
63 | opacity: 0;
64 | transform: translate3d(-50%, -50%, 0) scale(2);
65 | }
66 | .modal-leave-to {
67 | opacity: 0;
68 | transform: translate3d(-50%, -50%, 0) scale(1.5);
69 | }
70 | ```
71 |
72 | #### Options(第二个参数)
73 |
74 | | 参数 | 说明 | 类型 | 默认值 |
75 | |------|------|------|------|
76 | | show | 是否显示 | `Boolean` | `false` |
77 | | type | 类型,可选值为`alert` `confirm` | `String` | `'alert'` |
78 | | title | 标题 | `String` | `''` |
79 | | confirmText | 确定按钮文字 | `String` | `确认` |
80 | | cancelText | 取消按钮文字 | `String` | `取消` |
81 | | closeOnClickOverlay | 点击蒙版时是否关闭弹窗 | `Boolean` | `false` |
82 | | autoClose | 点击按钮时自动关闭,要想实现异步关闭功能,请设为`false` | `Boolean` | `true` |
83 | | transitionName | 同`Popup组件`中一致 | `String` | `''` |
84 |
85 | #### Props
86 |
87 | | 参数 | 说明 | 类型 | 默认值 |
88 | |------|------|------|------|
89 | | type | 同 Options 中一致 | `String` | `normal` |
90 | | title | 同 Options 中一致 | `String` | `''` |
91 | | text | 文字内容 | `String` | `''` |
92 | | overlay | 是否显示蒙版 | `Boolean` | `true` |
93 | | confirm-text | 同 Options 中一致 | `String` | `确认` |
94 | | cancel-text | 同 Options 中一致 | `String` | `取消` |
95 | | close-on-click-overlay | 同 Options 中一致 | `Boolean` | `false` |
96 | | transition-name | 同`Popup组件`中一致 | `String` | `''` |
97 |
98 |
99 | #### Slots
100 |
101 | | 参数 | 说明 |
102 | |------|------|
103 | | default | 弹窗主内容区域 |
104 | | title | 标题区域 |
105 | | footer | 底部区域 |
106 |
107 | #### Events
108 |
109 | | 事件名 | 说明 | 参数 |
110 | |------|------|------|
111 | | confirm | 点击确认按钮时触发 | - |
112 | | cancel | 取消时触发 | - |
113 |
114 |
--------------------------------------------------------------------------------
/packages/field/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
13 |
14 |
24 |
35 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
130 |
131 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unique-ui",
3 | "version": "0.10.1",
4 | "description": "A mobile component library for Vue2.x",
5 | "main": "lib/index.js",
6 | "license": "MIT",
7 | "homepage": "https://imzxj.github.io/unique-ui/",
8 | "repository": "git@github.com:imzxj/unique-ui.git",
9 | "author": "imzxj <362896731@qq.com>",
10 | "scripts": {
11 | "dev": "webpack-dev-server --hot --inline --progress --config build/webpack.dev.conf.js",
12 | "build:entry": "node build/build-entry.js",
13 | "build:components": "webpack --color --progress --config build/webpack.prod.conf.js",
14 | "build:theme": "gulp build --gulpfile packages/theme/gulpfile.js",
15 | "build:lib": "rm -rf lib && npm run build:entry && npm run build:components && npm run build:theme",
16 | "build:doc": "webpack --color --progress --config build/webpack.doc.conf.js",
17 | "release": "sh build/release.sh",
18 | "lint": "eslint --ext .js,.vue src packages",
19 | "lint:fix": "eslint --fix --ext .js,.vue src packages"
20 | },
21 | "files": [
22 | "lib",
23 | "packages",
24 | "src"
25 | ],
26 | "dependencies": {
27 | "@babel/runtime": "^7.4.5",
28 | "font-awesome": "^4.7.0",
29 | "normalize.css": "^8.0.1",
30 | "qrcode": "^1.3.3",
31 | "raf": "^3.4.1"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.4.5",
35 | "@babel/plugin-syntax-dynamic-import": "^7.2.0",
36 | "@babel/plugin-transform-object-assign": "^7.2.0",
37 | "@babel/plugin-transform-runtime": "^7.4.4",
38 | "@babel/polyfill": "^7.4.4",
39 | "@babel/preset-env": "^7.4.5",
40 | "@vue/babel-preset-jsx": "^1.0.0",
41 | "autoprefixer": "^9.3.1",
42 | "babel-loader": "^8.0.6",
43 | "clean-webpack-plugin": "^1.0.0",
44 | "cross-env": "^5.2.0",
45 | "css-loader": "^2.1.1",
46 | "cssnano": "^4.1.10",
47 | "cz-conventional-changelog": "^2.1.0",
48 | "eslint": "^5.16.0",
49 | "eslint-loader": "^2.1.2",
50 | "eslint-plugin-vue": "^5.2.2",
51 | "eslint-plugin-vue-libs": "^3.0.0",
52 | "friendly-errors-webpack-plugin": "^1.7.0",
53 | "fs-extra": "^8.1.0",
54 | "gulp": "^4.0.2",
55 | "gulp-autoprefixer": "^6.1.0",
56 | "gulp-cssmin": "^0.2.0",
57 | "gulp-sass": "4.x",
58 | "highlight.js": "^9.13.1",
59 | "html-webpack-plugin": "^3.2.0",
60 | "markdown-to-vue-loader": "^1.0.1",
61 | "node-sass": "^4.11.0",
62 | "postcss": "^7.0.16",
63 | "postcss-loader": "^3.0.0",
64 | "progress-bar-webpack-plugin": "^1.12.1",
65 | "sass-loader": "^7.1.0",
66 | "style-loader": "^0.23.1",
67 | "url-loader": "^1.1.2",
68 | "vue": "^2.6.10",
69 | "vue-loader": "^15.7.0",
70 | "vue-progressbar": "^0.7.5",
71 | "vue-router": "^3.0.6",
72 | "vue-template-compiler": "^2.6.10",
73 | "webpack": "^4.32.2",
74 | "webpack-cli": "^3.3.2",
75 | "webpack-dev-server": "^3.4.1",
76 | "webpack-node-externals": "^1.7.2"
77 | },
78 | "peerDependencies": {
79 | "vue": ">= 2.5.0"
80 | },
81 | "browserslist": [
82 | "Android >= 4.0",
83 | "iOS >= 7"
84 | ],
85 | "config": {
86 | "commitizen": {
87 | "path": "./node_modules/cz-conventional-changelog"
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/packages/nav-bar/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 标题
10 |
11 |
12 |
13 |
14 |
15 |
16 |
18 |
--------------------------------------------------------------------------------
/docs/field.md:
--------------------------------------------------------------------------------
1 | ## Field 输入框
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 |
8 |
9 | ```
10 |
11 | #### 原生属性
12 |
13 | 本组件支持所有原生属性
14 |
15 | ```html
16 |
17 |
18 |
19 |
20 | ```
21 |
22 | #### 多行输入
23 |
24 | 将`type`设置为`textarea`可以将默认的`input`组件更改为`textarea`组件,支持`rows`等原生属性,
25 |
26 | ```html
27 |
28 |
35 |
36 | ```
37 |
38 | #### 自定义内容
39 |
40 | ```html
41 |
42 |
43 |
44 | 发送验证码
45 |
46 |
47 | ```
48 |
49 | #### Props
50 |
51 | | 参数 | 说明 | 类型 | 默认值 |
52 | |------|------|------|------|
53 | | value | 输入框内容 | `String` | `''` |
54 | | type | 输入框类型 | `String` | `'input'` |
55 | | icon | 左侧图标 | `String` | `''` |
56 | | label | 左侧标签文字 | `String` | `''` |
57 | | clearable | 是否显示清空按钮 | `Boolean` | `false` |
58 | | readonly | 是否只读 | `Boolean` | `false` |
59 |
60 | #### Slots
61 |
62 | | 参数 | 说明 |
63 | |------|------|
64 | | icon | 左侧图标 |
65 | | right-icon | 右侧图标 |
66 |
67 | #### Events
68 |
69 | 本组件支持所有原生事件
--------------------------------------------------------------------------------
/packages/field/demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 |
28 |
34 | 发送验证码
35 |
36 |
37 |
38 |
39 |
40 |
41 |
54 |
55 |
59 |
--------------------------------------------------------------------------------
/docs/nav-bar.md:
--------------------------------------------------------------------------------
1 | ## NavBar 导航栏
2 |
3 | #### 简单用法
4 |
5 | ```html
6 |
7 | ```
8 |
9 | #### 高级用法
10 |
11 | 通过插槽定制内容
12 |
13 | ```html
14 |
15 |
16 | 标题
17 |
18 |
19 | ```
20 |
21 | #### Props
22 |
23 | | 参数 | 说明 | 类型 | 默认值 |
24 | |------|------|------|------|
25 | | title | 标题 | `String` | `''` |
26 | | left-arrow | 是否显示左侧箭头 | `Boolean` | `false` |
27 | | left-text | 左侧文案 | `String` | `''` |
28 | | fixed | 是否固定在顶部 | `Boolean` | `false` |
29 |
30 | #### Slots
31 |
32 | | 名称 | 说明 |
33 | |------|------|
34 | | title | 标题区域内容 |
35 | | left | 左侧区域内容 |
36 | | right | 右侧区域内容 |
37 |
38 | #### Events
39 |
40 | | 事件名 | 说明 | 参数 |
41 | |------|------|------|
42 | | click-left | 点击左侧按钮时触发 | 原生事件对象 |
43 | | click-right | 点击右侧按钮时触发 | 原生事件对象 |
--------------------------------------------------------------------------------