├── src
├── schema
│ ├── cache.js
│ ├── messages.js
│ ├── format.js
│ └── store.js
├── icon
│ ├── iconfont.eot
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ ├── iconfont.woff2
│ ├── iconfont.css
│ └── index.html
├── collapse-transition.css
├── locales
│ ├── index.js
│ ├── en.js
│ └── zh.js
├── basic
│ ├── dropdown-divider.vue
│ ├── nav-menu.vue
│ ├── panel.vue
│ ├── dropdown-item.vue
│ ├── vbox.vue
│ ├── progress-bar.vue
│ ├── sticky.vue
│ ├── dialog.vue
│ ├── button-group.vue
│ ├── nav-menu-item.vue
│ ├── alert.vue
│ └── dropdown.vue
├── nav
│ ├── breadcrumb.vue
│ ├── accordion.vue
│ ├── breadcrumb-item.vue
│ └── tab.vue
├── form
│ ├── radio.vue
│ ├── select.vue
│ ├── checkbox.vue
│ ├── form.vue
│ ├── index.js
│ ├── radio-group.vue
│ ├── select-option.vue
│ ├── draggable.js
│ └── fields
│ │ ├── label.vue
│ │ ├── check.vue
│ │ ├── radio.vue
│ │ ├── check-group.vue
│ │ ├── field.vue
│ │ └── text.vue
├── service
│ ├── dropdown.js
│ ├── loading-mask.js
│ ├── tooltip.js
│ ├── notification.js
│ ├── loading-mask.vue
│ ├── msgbox.js
│ ├── notification.vue
│ ├── msgbox.vue
│ └── tooltip.vue
├── collapse-transition.js
├── data
│ └── tree.vue
├── popover.js
├── index.js
├── common.css
└── util.js
├── .gitignore
├── docs
├── schema
│ ├── first-form.png
│ └── README.MD
├── sticky.md
├── progress-bar.md
├── tabs.md
├── form.md
├── tooltip.md
├── slider.md
├── breadcrumb.md
├── alert.md
├── panel.md
├── dialog.md
├── notification.md
├── accordion.md
├── navmenu.md
├── pagination.md
├── loading-mask.md
├── dropdown.md
├── popup-mixin.md
├── button.md
├── msgbox.md
├── form-field.md
├── grid.md
└── tree.md
├── examples
├── json
│ ├── mapping.json
│ └── mapping2.json
├── empty.vue
├── form
│ ├── upload.vue
│ ├── tags.vue
│ ├── schema.js
│ ├── editor.vue
│ ├── field.vue
│ ├── validation.vue
│ └── mapping.vue
├── markdown.js
├── index.html
├── nav
│ ├── breadcrumb.vue
│ ├── accordion.vue
│ └── tabs.vue
├── basic
│ ├── slider.vue
│ ├── alert.vue
│ ├── progress-bar.vue
│ ├── sticky.vue
│ ├── dropdown.vue
│ ├── dialog.vue
│ ├── nav-menu.vue
│ └── button.vue
├── service
│ ├── tooltip.vue
│ ├── loading-mask.vue
│ ├── msgbox.vue
│ └── notification.vue
├── data
│ ├── pagination.vue
│ ├── custom-grid.vue
│ ├── custom-grid-test.vue
│ └── tree.vue
├── util.js
├── markdown.css
├── index.js
└── app.vue
├── .babelrc
├── .npmignore
├── test
├── index.js
├── index.html
└── validator.js
├── Makefile
├── icons
├── arrow-down.svg
├── arrow-right.svg
├── info.svg
├── config.json
├── warning.svg
├── arrow-left.svg
├── confirm-circle.svg
├── first.svg
├── last.svg
├── error.svg
├── arrow-up.svg
├── close.svg
├── success.svg
├── date-trigger.svg
└── close-circle.svg
├── README.md
├── webpack.config.js
└── package.json
/src/schema/cache.js:
--------------------------------------------------------------------------------
1 | export default {};
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | coverage
5 | .idea
6 | .jshintrc
7 | /lib/
--------------------------------------------------------------------------------
/src/icon/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ElemeFE/vue-desktop/HEAD/src/icon/iconfont.eot
--------------------------------------------------------------------------------
/src/icon/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ElemeFE/vue-desktop/HEAD/src/icon/iconfont.ttf
--------------------------------------------------------------------------------
/src/icon/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ElemeFE/vue-desktop/HEAD/src/icon/iconfont.woff
--------------------------------------------------------------------------------
/src/icon/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ElemeFE/vue-desktop/HEAD/src/icon/iconfont.woff2
--------------------------------------------------------------------------------
/docs/schema/first-form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ElemeFE/vue-desktop/HEAD/docs/schema/first-form.png
--------------------------------------------------------------------------------
/examples/json/mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "Test1": 1,
3 | "Test2": 2,
4 | "Test3": 3,
5 | "Test4": 4
6 | }
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-1"],
3 | "plugins": ["transform-runtime"],
4 | "comments": false
5 | }
--------------------------------------------------------------------------------
/examples/empty.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | coverage
5 | .idea
6 | .jshintrc
7 | /src/
8 | /examples/
9 | /docs/
10 | /icons/
11 | /test/
--------------------------------------------------------------------------------
/src/collapse-transition.css:
--------------------------------------------------------------------------------
1 | .collapse-transition {
2 | transition: 0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out;
3 | }
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var chai = require('chai');
2 | chai.should();
3 | chai.use(require('sinon-chai'));
4 |
5 | require('./schema');
6 | require('./validator');
7 |
--------------------------------------------------------------------------------
/src/locales/index.js:
--------------------------------------------------------------------------------
1 | import { default as en } from './en';
2 | import { default as zh } from './zh';
3 |
4 | export default {
5 | en: en,
6 | zh: zh
7 | };
8 |
--------------------------------------------------------------------------------
/examples/form/upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/examples/markdown.js:
--------------------------------------------------------------------------------
1 | var Vue = require('vue');
2 |
3 | var marked = require('marked');
4 |
5 | Vue.elementDirective('markdown', {
6 | bind() {
7 | this.el.className = 'markdown';
8 | this.el.innerHTML = marked(this.el.innerHTML);
9 | }
10 | });
11 |
12 | export default {};
13 |
--------------------------------------------------------------------------------
/docs/sticky.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Sticky 用于创建顶部固定组件。
4 |
5 | # Usage
6 |
7 | 使用 d-sticky 标签即可创建 Sticky 组件:
8 |
9 | ```HTML
10 | 固定在顶部
11 | ```
12 |
13 | # Properties
14 |
15 | Sticky 目前可以使用的属性如下:
16 |
17 | | Property | Description |
18 | | ---- | ---- |
19 | | top | 组件固定时与视口顶部的距离, 单位为px, 默认值为0。 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Vue Webpack Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/basic/dropdown-divider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/json/mapping2.json:
--------------------------------------------------------------------------------
1 | {
2 | "1": {
3 | "11": 11,
4 | "12": 12,
5 | "13": 13
6 | },
7 | "2": {
8 | "21": 21,
9 | "22": 22,
10 | "23": 23
11 | },
12 | "3": {
13 | "31": 31,
14 | "32": 32,
15 | "33": 33
16 | },
17 | "4": {
18 | "41": 41,
19 | "42": 42,
20 | "43": 43
21 | }
22 | }
--------------------------------------------------------------------------------
/src/nav/breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | install:
2 | @if [ ! -f "$$(which istanbul)" ]; then npm install --registry=https://registry.npm.taobao.org -g browserify watchify mocha istanbul; fi
3 | @npm install --registry=https://registry.npm.taobao.org
4 |
5 | dev: install
6 | @npm run dev
7 |
8 | test: install
9 | @npm run test
10 |
11 | coverage: install
12 | @npm run coverage
13 |
--------------------------------------------------------------------------------
/src/nav/accordion.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/nav/breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 首页
4 | Tabs
5 | Accordion
6 | Breadcrumb
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/basic/slider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/schema/messages.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'default': '字段{label}校验失败',
3 | required: '{label}为必填项',
4 | pattern: '{label}的格式不正确',
5 | whitespace: '{label}不能为空',
6 | 'enum': '{label}必须为以下值中的一个: {list}',
7 | length: {
8 | 'min': '{label}至少有{min}个字符',
9 | 'max': '{label}最多有{max}个字符',
10 | 'range': '{label}的长度应该大于等于{min}并且小于等于{max}'
11 | },
12 | range: {
13 | 'min': '{label}应该大于{min}',
14 | 'max': '{label}应该小于{max}',
15 | 'range': '{label}应该介于{min}和{max}之间'
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/examples/service/tooltip.vue:
--------------------------------------------------------------------------------
1 |
2 | Right Tooltip
3 | Top Tooltip
4 | Bottom Tooltip
5 | Left Tooltip
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/progress-bar.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Progress-bar 组件用于创建进度条。
4 |
5 | # Usage
6 |
7 | 使用 d-progress-bar 标签即可创建 Progress-bar 组件:
8 |
9 | ```HTML
10 |
11 | ```
12 |
13 | # Properties
14 |
15 | Slider 目前可以使用的属性如下:
16 |
17 | | Property | Description |
18 | | ---- | ---- |
19 | | percent | 进度条的百分值, 默认值为0。 |
20 | | type | 进度条的颜色主题, 可设置为"success", "info", "warning", "error", 默认值为 "info"。 |
21 | | showPercent | 是否在进度条的右侧显示百分值, Boolean 类型,默认值为 true。 |
22 | | barHeight | 进度条的高度, 单位为px, 默认值为15。 |
--------------------------------------------------------------------------------
/docs/tabs.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 |
3 | tabs 是一个常见的标签页组件,使用方式如下:
4 |
5 | ```Vue
6 |
7 |
8 |
9 | ```
10 |
11 | ## Tabs
12 |
13 | 通过 d-tabs 在 .vue 中定义一个 Tabs 组件,Tabs 目前没有提供属性支持,后续会陆续添加。
14 |
15 | ## Tab
16 |
17 | 通过 d-tab 在 Tabs 中添加一个 Tab 组件,Tab 目前可以使用的属性如下:
18 |
19 | | Property | Description |
20 | | ---- | ---- |
21 | | title | Tab 上显示的标题。 |
22 | | icon | Tab 上显示的 icon 使用的 className。 |
23 | | disabled | Tab 是否处于 disabled 状态,Boolean 类型,默认值为 false。 |
24 | | closable | Tab 是否可以关闭,Boolean 类型,默认值为 false。|
--------------------------------------------------------------------------------
/examples/nav/accordion.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 这是标题一的内容
5 |
6 |
7 |
8 | 这是标题二的内容 这是标题二的内容
9 |
10 |
11 |
12 | 这是标题三的内容 这是标题三的内容 这是标题三的内容
13 |
14 |
15 |
16 | 这是标题四的内容
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/form.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Form 可以定义列数,并为 FormField 定义一些公用属性。
4 |
5 | # Usage
6 |
7 | 使用 d-form 即可创建一个 Form,例子如下:
8 |
9 | ```HTML
10 |
11 | ...
12 |
13 | ```
14 |
15 | # Properties
16 |
17 | Form 可以使用的属性如下
18 |
19 | | Property | Description |
20 | | ---- | ---- |
21 | | cols | Form 显示的列数,数值类型,默认值为1。 |
22 | | schema | Form 中的 FormField 使用的 Schema。 |
23 | | model | Form 中的 FormField 使用的 model。 |
24 | | labelWidth | Form 中的 FormField 的 labelWidth 的默认值。|
25 | | labelSuffix | Form 中的 FormField 的 labelSuffix 的默认值。|
26 | | editorWidth | Form 中的 FormField 的 editorWidth 的默认值。|
--------------------------------------------------------------------------------
/examples/basic/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 成功提示的示例
4 |
5 |
6 |
7 | 警告提示的示例
8 |
9 |
10 |
11 | 消息提示的示例
12 |
13 |
14 |
15 | 错误提示的示例
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/examples/basic/progress-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/icons/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/examples/basic/sticky.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 固定在顶部
5 |
6 |
7 |
8 | 固定在距顶部70px的位置
9 |
10 |
11 |
12 |
13 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/form/tags.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/tooltip.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Tooltip 是 vue-desktop 提供的一个directive,并不是一个组件 不能单独实例化。
4 |
5 |
6 | # Usage
7 | 在需要显示 tooltip 的组件上添加 v-tooltip 这个属性,即可激活这个功能。在 v-tooltip 之外,你还可以定义 tooltip-placement、tooltip-content、tooltip-delay、tooltip-trigger 等属性。
8 |
9 | ```HTML
10 | Right Tooltip
11 | ```
12 |
13 | # Properties
14 | 请在使用的时候为属性添加上 tooltip- 前缀。
15 |
16 | | Property | Description |
17 | | ---- | ---- |
18 | | placement | Tooltip 显示的位置,默认值为 bottom。 |
19 | | content | Tooltip 中显示的内容。 |
20 | | delay | Tooltip 打开的延时,默认无延时。 |
21 | | trigger | Tooltip 触发的方式,默认为 mouseenter,可选值 mouseenter、click、focus。 |
22 |
--------------------------------------------------------------------------------
/examples/data/pagination.vue:
--------------------------------------------------------------------------------
1 |
2 | Change ItemTotal
3 |
4 | save
5 | cancel
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/slider.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Slider 组件用于创建滑动条。
4 |
5 | # Usage
6 |
7 | 使用 d-slider 标签即可创建 Slider 组件:
8 |
9 | ```HTML
10 |
11 | ```
12 |
13 | # Properties
14 |
15 | Slider 目前可以使用的属性如下:
16 |
17 | | Property | Description |
18 | | ---- | ---- |
19 | | min | 滑动条的最小值, 默认值为0。 |
20 | | max | 滑动条的最大值, 默认值为100。 |
21 | | step | 滑动条的步长, 默认值为1。 |
22 | | defaultValue | 滑动条的初始值, 默认等于 min 属性的值。 |
23 | | showInput | 是否在滑动条右侧显示一个输入框, Boolean 类型,默认值为 false。设置为 true 时, 可通过该输入框控制滑动条的值。 |
24 |
25 | 当滑动条的值发生变化时, 会触发 @change 事件, 调用相应的回调函数, 该回调函数的参数为滑动条的值。绑定事件的方法如下:
26 |
27 | ```HTML
28 |
29 | ```
--------------------------------------------------------------------------------
/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/form/radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/service/dropdown.js:
--------------------------------------------------------------------------------
1 | var dropdowns = [];
2 |
3 | document.addEventListener('click', function(event) {
4 | dropdowns.forEach(function(dropdown) {
5 | var target = event.target;
6 | if (!dropdown || !dropdown.$el) return;
7 | if (target === dropdown.$el || dropdown.$el.contains(target)) {
8 | return;
9 | }
10 | dropdown.onDocumentClick && dropdown.onDocumentClick(event);
11 | });
12 | });
13 |
14 | export default {
15 | open(instance) {
16 | if (instance) {
17 | dropdowns.push(instance);
18 | }
19 | },
20 |
21 | close(instance) {
22 | var index = dropdowns.indexOf(instance);
23 | if (index !== -1) {
24 | dropdowns.splice(instance, 1);
25 | }
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/icons/info.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/docs/breadcrumb.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Breadcrumb 组件用于创建面包屑导航。
4 |
5 | # Usage
6 |
7 | 使用 d-breadcrumb 和 d-breadcrumb-item 标签即可创建 Breadcrumb 组件:
8 |
9 | ```HTML
10 |
11 | 首页
12 | Tabs
13 | Accordion
14 | Breadcrumb
15 |
16 | ```
17 |
18 | # Properties
19 |
20 | d-breadcrumb-item 目前可以使用的属性如下:
21 |
22 | | Property | Description |
23 | | ---- | ---- |
24 | | link | 链接地址, 若不赋值则该项不可点击。 |
25 |
26 | Breadcrumb 组件会自动判断当前页面的 URL 是否与某个 d-breadcrumb-item 的 link 属性相同, 若相同则会为该 d-breadcrumb-item 添加一些样式, 用来提示用户当前所在的位置。
--------------------------------------------------------------------------------
/examples/service/loading-mask.vue:
--------------------------------------------------------------------------------
1 |
2 | Show Loading Mask By API
3 | Show Loading Mask By Directive
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/basic/nav-menu.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/alert.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Alert 用于向用户显示警告信息。
4 |
5 | # Usage
6 |
7 | 使用 d-alert 标签即可创建一个 Alert 组件:
8 |
9 | ```HTML
10 |
11 | 消息提示的示例
12 |
13 | ```
14 |
15 | # Properties
16 |
17 | Alert 目前可以使用的属性如下:
18 |
19 | | Property | Description |
20 | | ---- | ---- |
21 | | title | Alert 上显示的标题, 默认值为"提示"。 |
22 | | type | Alert 的类型, 共有"success", "info", "warning", "error"四种, 默认值为"info"。 |
23 | | closable | Alert 是否可以关闭,Boolean 类型,默认值为 false。 |
24 | | closeText | Alert 关闭按钮的文本(若 Alert 可关闭),不为该属性赋值则显示×。 |
25 |
26 | Alert 组件在关闭后会触发 close 事件, 绑定事件的方法如下:
27 |
28 | ```HTML
29 |
30 | 绑定事件的示例
31 |
32 | ```
--------------------------------------------------------------------------------
/src/schema/format.js:
--------------------------------------------------------------------------------
1 | var RE_ARGS = /\{([0-9a-zA-Z]+)\}/g;
2 |
3 | export default function(string, ...args) {
4 | if (!string) return null;
5 | if (arguments.length === 2 && typeof arguments[1] === 'object') {
6 | args = arguments[1];
7 | }
8 |
9 | if (!args || !args.hasOwnProperty) {
10 | args = {};
11 | }
12 |
13 | return string.replace(RE_ARGS, function replaceArg(match, i, index) {
14 | var result;
15 |
16 | if (string[index - 1] === '{' && string[index + match.length] === '}') {
17 | return i;
18 | } else {
19 | result = args.hasOwnProperty(i) ? args[i] : null;
20 | if (result === null || result === undefined) {
21 | return '';
22 | }
23 |
24 | return result;
25 | }
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/docs/panel.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Panel 是一个面板组件,可以显示内容区的标题,折叠展开,并可以在标题栏添加其他组件。
4 |
5 | # Usage
6 |
7 | 使用 d-panel 即可以创建一个 Panel 组件:
8 |
9 | ```HTML
10 |
11 | ...
12 |
13 | ```
14 |
15 | 如果要在标题右侧添加一些按钮,则可以使用 Vue 的 slot 功能:
16 | ```HTML
17 |
18 |
19 |
20 | 测试
21 | 测试
22 | 测试
23 |
24 |
25 | 测试
26 |
27 | ...
28 |
29 | ```
30 |
31 | # Properties
32 |
33 | Panel 目前只有 title 一个属性,其他属性会陆续添加。
34 |
35 | | Property | Description |
36 | | ---- | ---- |
37 | | title | Panel 显示的标题。 |
38 | | expaned | Panel 是否展开,Boolean 类型,默认值为 true。 |
--------------------------------------------------------------------------------
/examples/service/msgbox.vue:
--------------------------------------------------------------------------------
1 |
2 | Alert
3 | Confirm
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/dialog.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Dialog 是一个对话框组件,在 .vue 文件通过 d-dialog 标签来定义。
4 |
5 | ```HTML
6 |
7 | ……
8 |
9 | ```
10 |
11 | # Usage
12 |
13 | Dialog 目前拥有的属性如下:
14 |
15 | | Property | Description |
16 | | ---- | ---- |
17 | | title | Dialog 显示的标题。 |
18 | | width | Dialog 的宽度,数值类型。 |
19 | | visible | Dialog 是否可见,Boolean 类型,默认值为 false。一般情况下,请使用 :visible.sync 来和 vm 中的某一个属性做双向绑定。 |
20 |
21 | ## dialog footer
22 |
23 | 如果要在 dialog 的底部定义 Button,请这么定义:
24 |
25 | ```HTML
26 |
27 | ……
28 |
29 | OK
30 | Cancel
31 |
32 |
33 | ```
--------------------------------------------------------------------------------
/docs/notification.md:
--------------------------------------------------------------------------------
1 | # 简介
2 | Notification 用来弹出通知消息。
3 |
4 | # 用法
5 |
6 | ## 引用
7 |
8 | ```JavaScript
9 | import { Notification } from 'vue-desktop'
10 | ```
11 |
12 | ## 用法
13 |
14 | 使用方法如下:
15 |
16 | Notification({
17 | title: '通知',
18 | message: '通知信息',
19 | type: 'error',
20 | duration: 3,
21 | callback: function(instance) {
22 | console.log(instance.id + ' is closed.');
23 | }
24 | });
25 |
26 | # 参数列表
27 | 目前 Notification 支持如下参数:
28 |
29 | - title: Notification 显示的标题。
30 | - message: Notification 显示的内容。
31 | - type: Notification 显示的图标的类型,可选值:success、info、warning、error,默认值为 info。
32 | - duration: Notification 显示的时长,单位为秒,默认值为 5。设置为 0 则会一直显示,直到用户手动关闭。
33 | - callback: Notification 关闭后的回调函数,参数 instance 为对应于该 Notification 的 Vue 实例对象,它具有上述四个属性,instance.id 为唯一性标识。
--------------------------------------------------------------------------------
/icons/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "categories": {
3 | "default": [
4 | "arrow-down.svg",
5 | "arrow-left.svg",
6 | "arrow-right.svg",
7 | "arrow-up.svg",
8 | "error.svg",
9 | "info.svg",
10 | "success.svg",
11 | "warning.svg",
12 | "close-circle.svg",
13 | "close.svg",
14 | "confirm-circle.svg",
15 | "date-trigger.svg",
16 | "last.svg",
17 | "first.svg"
18 | ],
19 | "exclude": [],
20 | "new": []
21 | },
22 | "useless": [
23 | "arrow-down.svg",
24 | "arrow-left.svg",
25 | "arrow-right.svg",
26 | "arrow-up.svg",
27 | "close-circle.svg",
28 | "close.svg",
29 | "confirm-circle.svg",
30 | "date-trigger.svg",
31 | "error.svg",
32 | "info.svg",
33 | "success.svg",
34 | "warning.svg"
35 | ]
36 | }
--------------------------------------------------------------------------------
/icons/warning.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/form/select.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{item.label}}
5 |
6 |
7 |
8 |
16 |
17 |
--------------------------------------------------------------------------------
/src/locales/en.js:
--------------------------------------------------------------------------------
1 | export default {
2 | validator: {
3 | required: 'Field {label} is required.',
4 | pattern: 'Field {label}\'s format is not correct.',
5 | length: 'Field {label}\'s length is not correct.'
6 | },
7 | datepicker: {
8 | today: 'Today',
9 | clear: 'Clear',
10 | confirm: 'OK',
11 | weeks: {
12 | sun: 'Sun',
13 | mon: 'Mon',
14 | tue: 'Tue',
15 | wed: 'Wed',
16 | thu: 'Thu',
17 | fri: 'Fri',
18 | sat: 'Sat'
19 | },
20 | months: {
21 | jan: 'January',
22 | feb: 'February',
23 | mar: 'March',
24 | apr: 'April',
25 | may: 'May',
26 | jun: 'June',
27 | jul: 'July',
28 | aug: 'August',
29 | sep: 'September',
30 | oct: 'October',
31 | nov: 'November',
32 | dec: 'December'
33 | }
34 | },
35 | alert: {
36 | title: 'Tip'
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/examples/basic/dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 第一个菜单项
5 | 第二个菜单项
6 | 第三个菜单项(不可用)
7 |
8 | 第四个菜单项
9 |
10 |
11 |
12 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/examples/form/schema.js:
--------------------------------------------------------------------------------
1 | import { Schema } from '../../src/index.js';
2 |
3 | export default new Schema({
4 | nickname: {
5 | label: 'NickName',
6 | required: true
7 | },
8 |
9 | password: {
10 | label: 'Password',
11 | required: true
12 | },
13 |
14 | birthday: {
15 | label: 'Birthday',
16 | type: 'date',
17 | default() {
18 | return new Date();
19 | }
20 | },
21 |
22 | sex: {
23 | label: 'Sex',
24 | default: 'female',
25 | trueValue: 'male',
26 | falseValue: 'female'
27 | },
28 |
29 | comment: {
30 | label: 'Comment'
31 | },
32 |
33 | count: {
34 | label: 'Number',
35 | type: 'integer'
36 | },
37 |
38 | simpleMapping: {
39 | label: 'Mapping',
40 | mapping: {
41 | 'Simple-0': 0,
42 | 'Simple-1': 1,
43 | 'Simple-2': 2,
44 | 'Simple-3': 3,
45 | 'Simple-4': 4,
46 | 'Simple-5': 5
47 | }
48 | }
49 | });
50 |
--------------------------------------------------------------------------------
/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/icons/confirm-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/icons/first.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shape
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/icons/last.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shape
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/service/loading-mask.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | var LoadingMask = Vue.extend(require('./loading-mask.vue'));
3 |
4 | var instance;
5 | var service = {
6 | open(text) {
7 | if (!instance) {
8 | instance = new LoadingMask({
9 | el: document.createElement('div')
10 | });
11 | }
12 | instance.text = text;
13 | Vue.nextTick(() => {
14 | instance.open();
15 | });
16 | },
17 |
18 | close() {
19 | if (instance) {
20 | Vue.nextTick(() => {
21 | instance.close();
22 | });
23 | }
24 | }
25 | };
26 |
27 | Vue.directive('action', {
28 | bind() {
29 | var el = this.el;
30 | el.addEventListener('click', () => {
31 | var result = this.vm.$get(this.expression);
32 | if (result && result.then) {
33 | service.open();
34 | result.catch(() => void 0).then(() => {
35 | service.close();
36 | });
37 | }
38 | }, false);
39 | }
40 | });
41 |
42 | export default service;
43 |
--------------------------------------------------------------------------------
/icons/error.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples/util.js:
--------------------------------------------------------------------------------
1 | const matchHtmlRegExp = /["'&<>]/;
2 | const ESCAPE_CHAR_MAP = {
3 | 34: '"',
4 | 38: '&',
5 | 39: ''',
6 | 60: '<',
7 | 62: '>'
8 | };
9 |
10 | var escapeHTML = function (string) {
11 | string = '' + string;
12 | var match = matchHtmlRegExp.exec(string);
13 |
14 | if (!match) {
15 | return string;
16 | }
17 |
18 | var html = '';
19 | var lastIndex = 0;
20 | var escape, index;
21 |
22 | for (index = match.index; index < string.length; index++) {
23 | var charCode = string.charCodeAt(index);
24 | if (ESCAPE_CHAR_MAP[charCode]) {
25 | escape = ESCAPE_CHAR_MAP[charCode];
26 | } else {
27 | continue;
28 | }
29 |
30 | if (lastIndex !== index) {
31 | html += string.substring(lastIndex, index);
32 | }
33 |
34 | lastIndex = index + 1;
35 | html += escape;
36 | }
37 |
38 | return lastIndex !== index ? html + string.substring(lastIndex, index) : html;
39 | };
40 |
41 | export default {
42 | escapeHTML: escapeHTML
43 | };
--------------------------------------------------------------------------------
/icons/arrow-up.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/schema/store.js:
--------------------------------------------------------------------------------
1 | import { default as cache } from './cache';
2 | import { default as Schema } from './index';
3 | import { default as validators } from './validators';
4 |
5 | export default {
6 | getSchema(name) {
7 | return cache[name];
8 | },
9 |
10 | defineSchema(name, config) {
11 | if (typeof name !== 'string') {
12 | throw new Error('name is required when define a schema.');
13 | }
14 |
15 | if (typeof config !== 'object') {
16 | throw new Error('config should be an object.');
17 | }
18 |
19 | var result = new Schema(config);
20 |
21 | cache[name] = result;
22 |
23 | return result;
24 | },
25 |
26 | removeSchema(name) {
27 | cache[name] = null;
28 | delete cache[name];
29 | },
30 |
31 | defineValidator(name, fn) {
32 | if (typeof name !== 'string' || typeof fn !== 'function') return;
33 |
34 | validators[name] = fn;
35 | },
36 |
37 | getValidator(name) {
38 | if (typeof name !== 'string') return null;
39 |
40 | return validators[name];
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/docs/accordion.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Accordion 组件用于创建手风琴导航。
4 |
5 | # Usage
6 |
7 | 使用 d-accordion 和 d-accordion-panel 标签即可创建 Accordion 组件:
8 |
9 | ```HTML
10 |
11 |
12 | 这是标题一的内容
13 |
14 |
15 | 这是标题二的内容 这是标题二的内容
16 |
17 |
18 | 这是标题三的内容 这是标题三的内容 这是标题三的内容
19 |
20 |
21 | 这是标题四的内容
22 |
23 |
24 | ```
25 |
26 | # Properties
27 |
28 | d-accordion 目前可以使用的属性如下:
29 |
30 | | Property | Description |
31 | | ---- | ---- |
32 | | type | 手风琴的颜色主题, 可设置为"default" 或 "transparent", 默认值为 "default"。当设置为 "transparent" 时, 组件背景色为透明, 用户可为其添加自定义的样式。 |
33 |
34 | d-accordion-panel 目前可以使用的属性如下:
35 |
36 | | Property | Description |
37 | | ---- | ---- |
38 | | title | 面板的标题文本 |
39 | | active | 添加 active 属性可让面板处于激活状态。 |
40 | | disabled | 添加 disabled 属性可让面板处于不可用状态。 |
41 |
--------------------------------------------------------------------------------
/src/form/checkbox.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ label }}
3 |
4 |
5 |
18 |
19 |
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Vue Desktop
2 |
3 | A UI library for building admin panel website.
4 |
5 | ## Install
6 |
7 | ```Bash
8 | npm install vue vue-i18n vue-desktop
9 | ```
10 |
11 | ## Usage
12 |
13 | ### All components
14 |
15 | Import all components provided by vue-desktop:
16 |
17 | ```JavaScript
18 | require('vue-desktop')
19 | ```
20 |
21 | Or
22 |
23 | ```JavaScript
24 | import components from 'vue-desktop'
25 | ```
26 |
27 | ### Import one component
28 |
29 | Replace src to lib in source code.
30 |
31 | ```JavaScript
32 | export default {
33 | components: {
34 | GridColumn: require('vue-desktop/lib/data/grid-column.vue'),
35 | Grid: require('vue-desktop/lib/data/grid.vue')
36 | }
37 | };
38 | ```
39 |
40 | ```HTML
41 |
42 |
43 |
44 |
45 |
46 | ```
47 |
48 | ## Dev
49 |
50 | ```Bash
51 | make dev
52 | ```
53 |
54 | ## Examples
55 |
56 | After npm run dev, visit http://localhost:8088/examples.
57 |
58 | ## License
59 | MIT.
--------------------------------------------------------------------------------
/src/form/form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/basic/dialog.vue:
--------------------------------------------------------------------------------
1 |
2 | Show Dialog
3 |
4 |
5 |
6 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
7 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
8 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
9 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
10 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
11 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
12 |
13 |
14 | OK
15 | Cancel
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/locales/zh.js:
--------------------------------------------------------------------------------
1 | export default {
2 | validator: {
3 | default: '字段{label}校验失败',
4 | required: '{label}为必填项',
5 | pattern: '{label}的格式不正确',
6 | whitespace: '{label}不能为空',
7 | enum: '{label}必须为以下值中的一个: {list}',
8 | length: {
9 | min: '{label}至少有{min}个字符',
10 | max: '{label}最多有{max}个字符',
11 | range: '{label}的长度应该大于等于{min}并且小鱼等于{max}'
12 | },
13 | range: {
14 | min: '{label}应该大于{min}',
15 | max: '{label}应该小于{max}',
16 | range: '{label}应该介于{min}和{max}之间'
17 | }
18 | },
19 | datepicker: {
20 | today: '今天',
21 | clear: '清空',
22 | confirm: '确定',
23 | weeks: {
24 | sun: '日',
25 | mon: '一',
26 | tue: '二',
27 | wed: '三',
28 | thu: '四',
29 | fri: '五',
30 | sat: '六'
31 | },
32 | months: {
33 | jan: '一月',
34 | feb: '二月',
35 | mar: '三月',
36 | apr: '四月',
37 | may: '五月',
38 | jun: '六月',
39 | jul: '七月',
40 | aug: '八月',
41 | sep: '九月',
42 | oct: '十月',
43 | nov: '十一月',
44 | dec: '十二月'
45 | }
46 | },
47 | alert: {
48 | title: '提示'
49 | }
50 | };
51 |
--------------------------------------------------------------------------------
/src/service/tooltip.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | var Tooltip = Vue.extend(require('./tooltip.vue'));
3 |
4 | Vue.directive('tooltip', {
5 | params: ['tooltip-content', 'tooltip-placement', 'tooltip-trigger', 'tooltip-delay'],
6 | paramWatchers: {
7 | tooltipContent(val) {
8 | if (this.instance) {
9 | this.instance.content = val;
10 | }
11 | }
12 | },
13 | bind() {
14 | var el = this.el;
15 | var placement = this.params.tooltipPlacement;
16 | var content = this.params.tooltipContent;
17 | var trigger = this.params.tooltipTrigger || 'mouseenter';
18 | var delay = parseInt(this.params.tooltipDelay, 10);
19 |
20 | if (trigger === 'mouseenter' && isNaN(delay)) {
21 | delay = 300;
22 | }
23 |
24 | if (!placement) placement = 'bottom';
25 |
26 | this.instance = new Tooltip({
27 | el: document.createElement('div')
28 | });
29 |
30 | this.instance.placement = placement;
31 | this.instance.content = content;
32 | this.instance.trigger = trigger;
33 | this.instance.target = el;
34 | this.instance.openDelay = delay;
35 | this.instance.bindTarget();
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/docs/navmenu.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | NavMenu 是一个导航菜单,可以支持多级菜单。
4 |
5 | # Usage
6 |
7 | 使用 d-nav-menu 即可创建一个 NavMenu 组件,在 NavMenu 里面使用 d-nav-menu-item 即可定义菜单项。
8 |
9 | ```HTML
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ```
23 |
24 | # Properties
25 |
26 | NavMenu 的属性如下:
27 | | Property | Description |
28 | | ---- | ---- |
29 | | exclusive | 是否排他展开,Boolean 类型,默认值为 true。 这个属性只对第一级的 NavMenuItem 起作用,如果是二级、三级,则需要指定子 NavMenu 的 exclusive 的属性。 |
30 |
31 |
32 | NavMenuItem 的属性如下:
33 |
34 | | Property | Description |
35 | | ---- | ---- |
36 | | text | 显示的文本。 |
37 | | path | Item 对应的路径,类似使用 v-link 中的 path。 |
38 | | exact | 是否路径完全匹配的时候才高亮 NavMenuItem,Boolean 类型,默认值为 false。 |
39 | | expanded | 是否展开,Boolean 类型,默认值为 false。 |
40 | | exclusive | 是否排他展开,Boolean 类型,默认值为 false。 |
41 |
42 |
--------------------------------------------------------------------------------
/icons/close.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/form/index.js:
--------------------------------------------------------------------------------
1 | import Form from './form.vue';
2 | import Radio from './radio.vue';
3 | import TextEditor from './text-editor.vue';
4 | import Checkbox from './checkbox.vue';
5 | import Tags from './tags.vue';
6 |
7 | import RadioGroup from './radio-group.vue';
8 | import DatePicker from './date-picker.vue';
9 | import TimePicker from './time-picker.vue';
10 | import Select from './select.vue';
11 | import Option from './select-option.vue';
12 |
13 | import Field from './fields/field.vue';
14 | import TextField from './fields/text.vue';
15 | import LabelField from './fields/label.vue';
16 | import CheckboxField from './fields/check.vue';
17 | import SelectField from './fields/select.vue';
18 | import RadiogroupField from './fields/radio.vue';
19 | import CheckgroupField from './fields/check-group.vue';
20 |
21 | import Upload from './upload.vue';
22 |
23 | export default {
24 | Form,
25 |
26 | DatePicker,
27 | TimePicker,
28 |
29 | Select,
30 | Option,
31 | Tags,
32 | TextEditor,
33 | Checkbox,
34 | Radio,
35 | RadioGroup,
36 |
37 | Field,
38 | TextField,
39 | LabelField,
40 | CheckboxField,
41 | SelectField,
42 | RadiogroupField,
43 | CheckgroupField,
44 |
45 | Upload
46 | };
47 |
--------------------------------------------------------------------------------
/icons/success.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/docs/pagination.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Pagination 是一个分页组件,可以实现常见的分页功能。
4 |
5 | # Usage
6 |
7 | 使用 d-pagination 标签即可创建一个 Pagination 组件:
8 |
9 | ```HTML
10 |
11 | ```
12 |
13 | # Properties
14 |
15 | Pagination 目前可用的属性如下:
16 |
17 | | Property | Description |
18 | | ---- | ---- |
19 | | pageSize | 每一页数据的长度,默认值为10。 |
20 | | itemCount | 数据的总数目,默认值为0。 |
21 | | currentPage | 当前是第几页,没有默认值。|
22 | | layout | 分页组件中内容的排列,默认值为: first, prev, manual, next, last, slot, ->, info。详细设置见下面的表格。 |
23 | | pageSizeList | 在显示 List 的情况下,所有可切换的 pageSize 的大小。数组类型,默认值为 [ 10, 20, 30, 40, 50, 100 ]。|
24 |
25 | layout 的所有可选项:
26 |
27 | | Property | Description |
28 | | ---- | ---- |
29 | | first, last | 第一个和最后一个的按钮。|
30 | | prev, next | 上一页和最后一页的按钮。|
31 | | manual | 显示 第 a 页, 共 b 页的信息,用户可以修改 a 的值。|
32 | | list | 显示 pageSizeList,就是用户可以修改的 pageSize 的列表。|
33 | | slot | Vue 中的 slot 的位置。|
34 | | -> | 左右分割的标识,-> 左侧的内容会显示在左侧,-> 右侧的内容会显示在右侧。|
35 | | info | 显示共有多少数据,现在显示的数据的范围。|
36 | | pager | 互联网风格的分页显示。|
37 |
38 | Pagination 在用户点击页码切换 currentPage 的时候,会触发 current-change 事件,可以这么绑定该事件:
39 |
40 | ```HTML
41 |
42 | ```
43 |
--------------------------------------------------------------------------------
/src/basic/panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
35 |
36 |
--------------------------------------------------------------------------------
/docs/loading-mask.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | LoadingMask 是 vue-desktop 提供的一个 Service,用来在用户提交数据的时候,页面上显示一个半透明的层,阻止用户的进一步操作。
4 |
5 | # Usage
6 |
7 | LoadingMask 有两种使用方式:
8 | 1. 使用 API 手动调用。
9 | 2. 使用 Directive。
10 |
11 | ## 手动调用
12 |
13 | LoadingMask 只提供了两个方法:open、close。open 用来打开 LoadingMask,close 用来关闭 LoadingMask。
14 |
15 | ```JavaScript
16 | import { LoadingMask } from 'vue-desktop'
17 | LoadingMask.open();
18 | setTimeout(function() {
19 | LoadingMask.close();
20 | }, 1000);
21 | ```
22 |
23 | ## 使用 Directive
24 |
25 | 使用 Directive 需要用户在自己的方法中返回一个 Promise:
26 | 1. 在 Promise 返回之后,打开 LoadingMask。
27 | 1. 在 Promise resolve 或者 reject 之后,关闭 LoadingMask。
28 |
29 | 假设目前有这么一个 Button,需要在 doAction 的时候显示一个 LoadingMask,在 doAction 中的行为执行结束的时候,隐藏 LoadingMask。HTML 中是这么定义的:
30 |
31 | ```HTML
32 | Do Something need stop user action
33 | ```
34 |
35 | 那么如果要想系统智能的显示隐藏 LoadingMask,修改这段 HTML 为如下内容:
36 | ```HTML
37 | Show Loading Mask By Directive
38 | ```
39 |
40 | doAction 的代码如下:
41 | ```JavaScript
42 | var doAction = function() {
43 | return new Promise(function(resolve) {
44 | setTimeout(function() {
45 | resolve(1);
46 | }, 1000);
47 | });
48 | }
49 | ```
50 |
51 | ## 修改显示文案
52 | LoadingMask.text = '加载中';
53 |
--------------------------------------------------------------------------------
/examples/service/notification.vue:
--------------------------------------------------------------------------------
1 |
2 | Notification 1
3 | Notification 2
4 | Notification 3
5 | Notification 4
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/form/radio-group.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/dropdown.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Dropdown 组件用于创建下拉菜单。
4 |
5 | # Usage
6 |
7 | 使用 d-dropdown-button, d-dropdown-item, d-dropdown-divider 标签即可创建 Dropdown 组件, d-dropdown-button 创建下拉按钮, d-dropdown-item 创建菜单项, d-dropdown-divider 创建菜单项之间的分割线:
8 |
9 | ```HTML
10 |
11 | 第一个菜单项
12 | 第二个菜单项
13 | 第三个菜单项(不可用)
14 |
15 | 第四个菜单项
16 |
17 | ```
18 |
19 | # Properties
20 |
21 | d-dropdown-button 目前可以使用的属性如下:
22 |
23 | | Property | Description |
24 | | ---- | ---- |
25 | | title | 显示在下拉按钮上的文字。 |
26 | | trigger | 下拉菜单的触发方式, 设置为 "click" 时通过点击触发, 设置为 "mouseenter" 时通过鼠标移入触发。触发默认值为 "click"。 |
27 | | position | 下拉菜单相对于下拉按钮的的位置, 可设置为 "top", "bottom", "left" 或 "right", 默认值为 "bottom"。 |
28 |
29 | d-dropdown-item 目前可以使用的属性如下:
30 |
31 | | Property | Description |
32 | | ---- | ---- |
33 | | disabled | 添加 disabled 属性即可让菜单项处于不可选状态。 |
34 | | name | 用户选择某个菜单项时, 传向回调函数的值。 |
35 |
36 | 当用户选择某个菜单项时, 会触发 @select 事件, 调用相应的回调函数, 该回调函数的参数即为被选中菜单项的 name 值。绑定事件的方法如下:
37 |
38 | ```HTML
39 |
40 | 第一个菜单项
41 | 第二个菜单项
42 |
43 | ```
--------------------------------------------------------------------------------
/src/nav/breadcrumb-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /
5 |
6 |
7 |
8 |
45 |
46 |
--------------------------------------------------------------------------------
/src/basic/dropdown-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
40 |
41 |
--------------------------------------------------------------------------------
/src/icon/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'eleme';
3 | src: url('iconfont.eot');
4 | src: url('iconfont.eot#iefix') format('embedded-opentype'),
5 | url('iconfont.woff') format('woff'),
6 | url('iconfont.ttf') format('truetype'),
7 | url('iconfont.svg') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 | [class^="d-icon-"]:before, [class*=" d-icon-"]:before {
12 | font-family: "eleme";
13 | font-style: normal;
14 | font-weight: normal;
15 | speak: none;
16 | display: inline-block;
17 | font-variant: normal;
18 | text-transform: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 | .d-icon-arrow-down:before { content: '\E901'; } /* '' */
23 | .d-icon-arrow-left:before { content: '\E902'; } /* '' */
24 | .d-icon-arrow-right:before { content: '\E903'; } /* '' */
25 | .d-icon-arrow-up:before { content: '\E904'; } /* '' */
26 | .d-icon-error:before { content: '\E905'; } /* '' */
27 | .d-icon-info:before { content: '\E906'; } /* '' */
28 | .d-icon-success:before { content: '\E907'; } /* '' */
29 | .d-icon-warning:before { content: '\E908'; } /* '' */
30 | .d-icon-close-circle:before { content: '\E909'; } /* '' */
31 | .d-icon-close:before { content: '\E90A'; } /* '' */
32 | .d-icon-confirm-circle:before { content: '\E90B'; } /* '' */
33 | .d-icon-date-trigger:before { content: '\E90C'; } /* '' */
34 | .d-icon-last:before { content: '\E90D'; } /* '' */
35 | .d-icon-first:before { content: '\E90E'; } /* '' */
--------------------------------------------------------------------------------
/src/nav/tab.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
50 |
51 |
79 |
--------------------------------------------------------------------------------
/src/form/select-option.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
24 |
--------------------------------------------------------------------------------
/src/service/notification.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | var NotificationConstructor = Vue.extend(require('./notification.vue'));
3 |
4 | var instance;
5 | var instances = [];
6 | var seed = 1;
7 |
8 | var Notification = function(options) {
9 | options = options || {};
10 | var userOnClose = options.callback;
11 | var id = 'notification_' + seed++;
12 |
13 | options.callback = function() {
14 | Notification.close(id, userOnClose);
15 | };
16 |
17 | instance = new NotificationConstructor({
18 | data: options
19 | });
20 | instance.id = id;
21 | instance.vm = instance.$mount();
22 | instance.vm.$appendTo('body');
23 | instance.dom = instance.vm.$el;
24 |
25 | var topDist = 0;
26 | for (var i = 0, len = instances.length; i < len; i++) {
27 | topDist += instances[i].$el.offsetHeight + 10;
28 | }
29 | topDist += 10;
30 | instance.top = topDist;
31 | instances.push(instance);
32 | };
33 |
34 | Notification.close = function(id, userOnClose) {
35 | for (var i = 0, len = instances.length; i < len; i++) {
36 | if (id === instances[i].id) {
37 | if (typeof userOnClose === 'function') {
38 | userOnClose(instances[i]);
39 | }
40 | var index = i;
41 | var removedHeight = instances[i].dom.offsetHeight;
42 | instances.splice(i, 1);
43 | break;
44 | }
45 | }
46 |
47 | if (len > 1) {
48 | for (i = index; i < len - 1 ; i++) {
49 | instances[i].dom.style.top = parseInt(instances[i].dom.style.top, 10) - removedHeight - 10 + 'px';
50 | }
51 | }
52 | };
53 |
54 | export default Notification;
55 |
--------------------------------------------------------------------------------
/icons/date-trigger.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/form/draggable.js:
--------------------------------------------------------------------------------
1 | import { on, off } from 'wind-dom';
2 |
3 | var isDragging = false;
4 |
5 | var isIE8 = Number(document.documentMode) < 9;
6 |
7 | var fixEvent = function(event) {
8 | var scrollTop = Math.max(window.scrollY || 0, document.documentElement.scrollTop || 0);
9 | var scrollLeft = Math.max(window.scrollX || 0, document.documentElement.scrollLeft || 0);
10 |
11 | event.target = event.srcElement;
12 | event.pageX = scrollLeft + event.clientX;
13 | event.pageY = scrollTop + event.clientY;
14 | };
15 |
16 | export default function(element, options) {
17 | var moveFn = function(event) {
18 | if (isIE8) {
19 | fixEvent(event);
20 | }
21 | if (options.drag) {
22 | options.drag(event);
23 | }
24 | };
25 | var upFn = function(event) {
26 | if (isIE8) {
27 | fixEvent(event);
28 | }
29 | off(document, 'mousemove', moveFn);
30 | off(document, 'mouseup', upFn);
31 | document.onselectstart = null;
32 | document.ondragstart = null;
33 |
34 | isDragging = false;
35 |
36 | if (options.end) {
37 | options.end(event);
38 | }
39 | };
40 | on(element, 'mousedown', function(event) {
41 | if (isIE8) {
42 | fixEvent(event);
43 | }
44 | if (isDragging) return;
45 | document.onselectstart = function() { return false; };
46 | document.ondragstart = function() { return false; };
47 |
48 | on(document, 'mousemove', moveFn);
49 | on(document, 'mouseup', upFn);
50 | isDragging = true;
51 |
52 | if (options.start) {
53 | options.start(event);
54 | }
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/examples/form/editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | test
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/popup-mixin.md:
--------------------------------------------------------------------------------
1 | # Overview
2 | Popup是一个Mixin, 为任何对象添加两个方法: open 和 close.
3 |
4 | # Usage
5 |
6 | Popup可以在open的时候指定自己显示的一些参数, 也可以通过实现popupOptions属性来返回参数的默认值。
7 |
8 | ```JavaScript
9 | import { Popup } from 'vue-desktop'
10 |
11 | export default {
12 | mixins: [ Popup ],
13 |
14 | computed: {
15 | popupOptions() {
16 | return {
17 | target: 'center',
18 | animation: false,
19 | modal: true,
20 | modalClass: 'loading-mask-modal',
21 | closeDelay: 300,
22 | updatePositionOnResize: true
23 | };
24 | }
25 | },
26 |
27 | props: {
28 | text: {}
29 | }
30 | }
31 | ```
32 |
33 | 通过 popupOptions 拿到参数和 open 传入参数是可以共用的, open 传入的参数会覆盖 popupOptions 返回的参数。
34 |
35 | 可以使用的属性如下:
36 |
37 | - openDelay: 显示 Popup 的延时,默认值为 0。
38 | - closeDelay: 隐藏 Popup 的延时,默认值为 0。
39 | - target: 默认值为 null,可以为 HTMLElement、Event、Array。
40 | - placement: 只有当 target 为 HTMLElement 的时候才起作用,Popup 相对于 target 摆放的位置,可选值有:left、right、top、bottom、innerLeft、innerRight、center,默认值为'top'。
41 | - alignment: 只有当 target 为 HTMLElement 的时候才起作用,Popup 相对于 target 布局的位置,可选值有:start、center、end,默认值为 'center'。
42 | - adjustLeft: Popup 在定位时位置在水平方向的偏移值,默认值为0。
43 | - adjustTop: Popup 在定位时位置在垂直方向的偏移值,默认值为0。
44 | - modal: 是否显示模态层,默认值为 false。
45 | - modalClass:模态层使用的 className。
46 | - zIndex: 在 modal 为 false 的时候该属性才起作用,该属性为 dom 的 style.zIndex的值,默认值为 null,即不设置 dom 的 zIndex。
47 | - closeOnPressEscape: 是否在按了 Esc 之后关闭 Popup,在 modal 为 true 的时候该属性才起作用,默认值为 false。
48 | - closeOnClickModal: 是否在点击了 Modal 层之后关闭 Popup,在 modal 为true的时候该属性才起作用,默认值为 false。
49 | - updatePositionOnResize:是否在 window resize 之后重新进行定位,默认值为 false。
--------------------------------------------------------------------------------
/src/basic/vbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/docs/button.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Button 组件用于创建各种按钮, Button-group 可创建按钮组。
4 |
5 | # Usage
6 |
7 | 使用 d-button 标签即可创建一个 Button 组件:
8 |
9 | ```HTML
10 | Primary Button
11 | ```
12 |
13 | 使用 d-button-group 标签来创建一个按钮组, 需在其中嵌套若干个由 d-button 标签创建的按钮:
14 |
15 | ```HTML
16 |
17 | 左
18 | 中
19 | 右
20 |
21 | ```
22 |
23 | # Properties
24 |
25 | Button 目前可以使用的属性如下:
26 |
27 | | Property | Description |
28 | | ---- | ---- |
29 | | type | Button 的颜色主题, 可设置为 "primary", "success", "info", "warning", "danger", 若不设置则为默认主题。 |
30 | | size | Button 的尺寸, 可设置为 "large" 或 "small", 若不设置则尺寸为中。 |
31 | | disabled | 添加 disabled 属性即可让按钮处于不可用状态,同时按钮样式也会改变。 |
32 | | icon | 显示在按钮文字前的图标, 值为 Icon 组件的类名。 |
33 |
34 | Button-group 目前可以使用的属性如下:
35 |
36 | | Property | Description |
37 | | ---- | ---- |
38 | | size | Button-group 的尺寸, 可设置为 "large" 或 "small", 若不设置则尺寸为中。无需再为 Button-group 中的 Button 组件设置尺寸。 |
39 | | selection-mode | Button-group 中可被选中的 Button 是否唯一, 设置为 'single' 时只能选中一个,设置为 'multiple' 时可选择多个, 默认值为 'none', 即按钮不可被选中。 |
40 |
41 | 嵌套于 Button-group 组件中的 Button 组件还可设置如下两个属性:
42 |
43 | | Property | Description |
44 | | ---- | ---- |
45 | | selected | 添加 selected 属性即可让 Button 组件处于默认选中状态。 |
46 | | value | Button-group 组件中被选中的 Button 发生变化时, 传向回调函数的值。 |
47 |
48 | 关于最后一个 value 属性:
49 | 当用户通过点击按钮, 使 Button-group 组件中被选中的 Button 发生变化时, 会触发 @select 事件, 调用相应的回调函数, 该回调函数的参数即为目前被选中的各 Button 组件的 value 值所组成的数组。绑定事件的方法如下:
50 |
51 | ```HTML
52 |
53 | 全部商家
54 | 甜品饮品
55 | 小吃零食
56 | 鲜花蛋糕
57 | 果蔬生鲜
58 |
59 | ```
--------------------------------------------------------------------------------
/examples/form/field.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Setting fields common properties in form component.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | This is a custom field.
26 |
27 |
28 | You can place anything in this field.
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/collapse-transition.js:
--------------------------------------------------------------------------------
1 | require('./collapse-transition.css');
2 |
3 | export default {
4 | beforeEnter(el) {
5 | el.dataset.oldPaddingTop = el.style.paddingTop;
6 | el.dataset.oldPaddingBottom = el.style.paddingBottom;
7 | el.style.height = '0';
8 | el.style.paddingTop = 0;
9 | el.style.paddingBottom = 0;
10 | },
11 |
12 | enter(el) {
13 | el.dataset.oldOverflow = el.style.overflow;
14 |
15 | el.style.display = 'block';
16 | if (el.scrollHeight !== 0) {
17 | el.style.height = el.scrollHeight + 'px';
18 | el.style.paddingTop = el.dataset.oldPaddingTop;
19 | el.style.paddingBottom = el.dataset.oldPaddingBottom;
20 | } else {
21 | el.style.height = '';
22 | el.style.paddingTop = el.dataset.oldPaddingTop;
23 | el.style.paddingBottom = el.dataset.oldPaddingBottom;
24 | }
25 |
26 | el.style.overflow = 'hidden';
27 | },
28 |
29 | afterEnter(el) {
30 | el.style.display = '';
31 | el.style.height = '';
32 | el.style.overflow = el.dataset.oldOverflow;
33 | },
34 |
35 | beforeLeave(el) {
36 | el.dataset.oldPaddingTop = el.style.paddingTop;
37 | el.dataset.oldPaddingBottom = el.style.paddingBottom;
38 | el.dataset.oldOverflow = el.style.overflow;
39 |
40 | el.style.display = 'block';
41 | if (el.scrollHeight !== 0) {
42 | el.style.height = el.scrollHeight + 'px';
43 | }
44 | el.style.overflow = 'hidden';
45 | },
46 |
47 | leave(el) {
48 | if (el.scrollHeight !== 0) {
49 | setTimeout(() => {
50 | el.style.height = 0;
51 | el.style.paddingTop = 0;
52 | el.style.paddingBottom = 0;
53 | });
54 | }
55 | },
56 |
57 | afterLeave(el) {
58 | el.style.display = el.style.height = '';
59 | el.style.overflow = el.dataset.oldOverflow;
60 | el.style.paddingTop = el.dataset.oldPaddingTop;
61 | el.style.paddingBottom = el.dataset.oldPaddingBottom;
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/examples/form/validation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 重置
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/msgbox.md:
--------------------------------------------------------------------------------
1 | # 简介
2 | MessageBox 是一个类似 SweetAlert 的组件,用来替代浏览器的 alert 和 confirm。
3 |
4 | # 用法
5 |
6 | ## 引用
7 |
8 | ```JavaScript
9 | import { MessageBox } from 'vue-desktop'
10 | ```
11 |
12 | ## 不需要callback
13 |
14 | 在不需要callback的情况下,只需要这么使用即可:
15 |
16 | MessageBox("Good job!", "You clicked the button!", "success");
17 |
18 | 第一个参数为 title,第二个参数为 message,第三个参数为 type。
19 |
20 | ## 需要callback
21 |
22 | 在需要 callback 的情况下,需要这么使用:
23 |
24 | MessageBox({
25 | title: 'I'm a title',
26 | message: 'I'm a message',
27 | type: 'success',
28 | showCancelButton: true
29 | }, function(action) {
30 | console.log('callback:', action);
31 | MessageBox('你点击了: ' + action);
32 | });
33 |
34 | 如果 callback 返回一个 false,则可以阻止 MessageBox 的关闭,你可以使用 MessageBox.close() 来关闭所有的 MessageBox。
35 |
36 | ## 需要自定义按钮
37 | 如果默认 Button 的样式无法满足你的需求,可以使用自定义按钮来完成你需要的功能。
38 |
39 | 自定义按钮使用buttons属性来配置,该属性为数组,每个button可以定义这么两个属性:
40 |
41 | - action: 触发的action,会在callback里面传入。
42 | - content: button的HTML。
43 |
44 | 举例说明:
45 |
46 | MessageBox({
47 | title: 'Title',
48 | message: 'Message',
49 | showConfirmButton: false,
50 | buttons: [{
51 | action: 'test',
52 | content: 'Test '
53 | }]
54 | }, function(action) {
55 | if (action === 'test') {
56 | MessageBox('自定义Button测试', '你点击了:' + action);
57 | }
58 | });
59 |
60 | # 参数列表
61 | 目前MessageBox支持如下参数:
62 |
63 | - title: MessageBox显示的标题。
64 | - message: MessageBox显示的内容。
65 | - type: MessageBox显示的图标的类型,可选值:success、warning、error,默认值为空。
66 | - showConfirmButton: 是否显示确定按钮,默认值为true。
67 | - showCancelButton: 是否显示取消按钮,默认值为false。
68 | - confirmButtonText: 确定按钮显示的文本,默认值为『确定』。
69 | - confirmButtonDisabled: 确定按钮是否不可点击,默认值为false。
70 | - cancelButtonText: 取消按钮显示的文本,默认值为『取消』。
71 | - confirmButtonClass: 确定按钮的className,默认值为空。注:msgbox-confirm这个class是一定存在的。
72 | - cancelButtonClass: 取消按钮的className,默认值为空。注:msgbox-cancel这个class是一定存在的。
73 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
3 | const isProduction = process.env.NODE_ENV === 'production';
4 |
5 | module.exports = {
6 | entry: {
7 | example: './examples/index.js',
8 | test: './test/index.js'
9 | },
10 | output: {
11 | path: './dist',
12 | publicPath: '/dist/',
13 | filename: '[name].js'
14 | },
15 | devServer: {
16 | stats: {
17 | children: false,
18 | chunks: false
19 | }
20 | },
21 | stats: {
22 | children: false,
23 | chunks: false
24 | },
25 | vue: {
26 | loaders: {
27 | js: 'babel!eslint',
28 | css: ExtractTextPlugin.extract('style', 'css')
29 | }
30 | },
31 | babel: {
32 | presets: ['es2015']
33 | //,plugins: ['transform-runtime']
34 | },
35 | module: {
36 | preLoaders: [
37 | { test: /\.js$/, exclude: /node_modules/, loader: 'eslint-loader' }
38 | ],
39 | loaders: [
40 | { test: /\.js$/, exclude: /node_modules\/(?!vue-desktop)/, loader: 'babel' },
41 | { test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css') },
42 | { test: /\.html$/, loader: 'html' },
43 | { test: /\.vue$/, loader: 'vue' },
44 | { test: /\.(ttf|svg|woff2|woff|eot)$/, loader: 'url?limit=20000&name=[path][name].[hash:6].[ext]' }
45 | ]
46 | }
47 | };
48 |
49 | if (isProduction) {
50 | module.exports.plugins = [
51 | new ExtractTextPlugin('[name].[contenthash:6].css'),
52 | new webpack.DefinePlugin({
53 | 'process.env': {
54 | NODE_ENV: '"production"'
55 | }
56 | }),
57 | new webpack.optimize.UglifyJsPlugin({
58 | compress: {
59 | warnings: false
60 | }
61 | }),
62 | new webpack.optimize.OccurenceOrderPlugin()
63 | ];
64 | } else {
65 | module.exports.plugins = [
66 | new ExtractTextPlugin('[name].css')
67 | ];
68 | module.exports.devtool = '#source-map';
69 | }
70 |
--------------------------------------------------------------------------------
/src/service/loading-mask.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
{{ text || 'Please wait...' }}
8 |
9 |
10 |
11 |
12 |
62 |
63 |
--------------------------------------------------------------------------------
/src/data/tree.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
86 |
--------------------------------------------------------------------------------
/src/basic/progress-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
57 |
58 |
--------------------------------------------------------------------------------
/src/basic/sticky.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
24 |
--------------------------------------------------------------------------------
/src/form/fields/label.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
6 | {{ textValue }}
7 |
8 |
9 | {{ hintMessage || '' }}
10 |
11 |
12 |
13 |
14 |
15 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/nav/tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tab1
5 | Change Tab
6 |
7 |
8 |
9 | Tab2
10 |
11 | Test2
12 |
13 |
14 |
15 |
16 | Tab3
17 |
18 | Test3
19 |
20 |
21 | Test4
22 |
23 |
24 |
25 |
26 | Tab{{ i }}
27 |
28 |
29 |
30 | Tab4
31 |
32 |
33 |
34 | Tab5
35 |
36 |
37 |
38 | Tab6
39 |
40 |
41 |
42 | Tab7
43 |
44 |
45 |
46 | Tab8
47 |
48 |
49 |
50 | Tab9
51 |
52 |
53 |
54 | Tab10
55 |
56 |
57 |
58 | Tab11
59 |
60 |
61 |
62 | Tab12
63 |
64 |
65 |
66 | Tab13
67 |
68 |
69 |
70 | Tab14
71 |
72 |
73 |
74 |
75 |
76 | Tab1
77 |
78 |
79 | Tab2
80 |
81 | Test2
82 |
83 |
84 |
85 | Tab3
86 |
87 | Test3
88 |
89 |
90 | Test4
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/examples/data/custom-grid.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 | Save
14 |
15 |
16 |
17 |
18 |
56 |
57 |
--------------------------------------------------------------------------------
/src/icon/index.html:
--------------------------------------------------------------------------------
1 | d-icon-close-circle
0xE909
d-icon-confirm-circle
0xE90B
d-icon-date-trigger
0xE90C
--------------------------------------------------------------------------------
/examples/basic/nav-menu.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 |
37 |
38 |
39 |
40 |
57 |
58 |
--------------------------------------------------------------------------------
/src/form/fields/check.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
6 |
7 | {{ hintMessage || '' }}
8 |
9 |
10 |
11 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/form-field.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | FormField 是表单中的表单项,有多种类型,目前支持的类型有:
4 |
5 | - field: 内部没有任何编辑器,使用 d-field 标签创建。
6 | - text:内部使用 TextEditor 作为自己的编辑器,使用 d-text-field 创建。
7 | - select:内部使用 Select 作为自己的编辑器,使用 d-select-field 创建。
8 | - checkbox:内部使用 CheckBox 作为自己的编辑器,使用 d-checkbox-field 创建。
9 | - radiogroup: 内部使用 RadioGroup 作为自己的编辑器,使用 d-radiogroup-field 创建。
10 |
11 | # Usage
12 |
13 | 一般情况下,一组 FormField 会有一组公用的属性,这些属性可以在 Form 组件上定义,在 FormField 没有定义该属性的时候,会使用 Form 上的属性作为默认值。
14 |
15 | 一个简单的例子如下:
16 |
17 | ```HTML
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```
26 |
27 | # Properties
28 |
29 | FormField 通用的属性如下:
30 |
31 | | Property | Description |
32 | | ---- | ---- |
33 | | schema | FormField 使用的 Schema。如果没有定义该属性,则默认值从 Form 中取得。 |
34 | | model | FormField 使用的 model,这个 model 可以是一个普通对象,也可以是 Schema 生成的一个 model。 |
35 | | property | FormField 中的编辑器绑定的 model 中的 property。 |
36 | | label | FormField 显示的 label 信息,如果定义了 Schema,没有定义 label 属性,则会从 Schema 中取得。 |
37 | | labelSuffix | FormField 中的 label 的后缀。如果没有定义该属性,则默认值从 Form 中取得。|
38 | | labelWidth | FormField 中的 label 显示的宽度,数值类型。如果没有定义该属性,则默认值从 Form 中取得。|
39 | | required | 是否在 label 的左侧显示一个必填的指示星号,如果定义了 schema 和 property 属性,并且该 property 的 required 属性为 true,则默认会显示必填项的星号。当然,你也可以定义 required 属性为 false 来关闭这个星号的显示。|
40 | | hideLabel | 是否隐藏 FormField 的 label 信息,Boolean 类型,默认值为 false。|
41 |
42 | TextField 可以使用的输入如下:
43 |
44 | | Property | Description |
45 | | ---- | ---- |
46 | | type | TextField 的类型,可选值:text、textarea、password。|
47 | | editorHeight | 文本框的高度。|
48 | | placeholder | 文本框使用的 placeholder。 |
49 | | editorWidth | 文本框的宽度,可以使用数值和百分比。|
50 |
51 | SelectField 可以使用的属性如下:
52 |
53 | | Property | Description |
54 | | ---- | ---- |
55 | | multiSelect | 是否可以多选,Boolean 类型,默认值为 false。 |
56 | | emptyRecord | 是否显示一个空的记录在最上方,Boolean 类型,默认值为 false。 |
57 | | editorWidth | Select的宽度,可以使用数值和百分比。|
58 |
59 | CheckBoxField 可以使用的属性如下:
60 |
61 | | Property | Description |
62 | | ---- | ---- |
63 | | trueValue | CheckBox 勾选的时候写到 model 中的值。 |
64 | | falseValue | CheckBox 不勾选的时候写到 model 中的值。 |
65 |
--------------------------------------------------------------------------------
/src/basic/dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
58 |
102 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-desktop",
3 | "version": "0.2.31",
4 | "description": "A UI library for building admin panel website.",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "prepublish": "mkdir -p lib & cp -r src/* lib & node_modules/babel-cli/bin/babel.js lib --out-dir lib",
8 | "dev": "webpack-dev-server --inline --hot --port 8088",
9 | "watch": "webpack --progress --hide-modules --watch",
10 | "build": "NODE_ENV=production webpack --progress --hide-modules",
11 | "test": "mocha -r chai -r sinon test/index.js",
12 | "coverage": "istanbul cover _mocha -- -r chai -r sinon -R spec test/index.js & open ./coverage/lcov-report/index.html"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git@github.com:ElemeFE/vue-desktop.git"
17 | },
18 | "files": [
19 | "LICENSE",
20 | "README.md",
21 | "lib"
22 | ],
23 | "keywords": [
24 | "vue",
25 | "vue-component"
26 | ],
27 | "dependencies": {
28 | "fecha": "^1.0.0",
29 | "vue-popup": "0.0.10",
30 | "wind-dom": "0.0.3"
31 | },
32 | "peerDependencies": {
33 | "vue": "^1.0.0",
34 | "vue-i18n": "^2.2.0"
35 | },
36 | "devDependencies": {
37 | "babel-cli": "^6.3.17",
38 | "babel-core": "^6.7.0",
39 | "babel-loader": "^6.2.4",
40 | "babel-plugin-transform-runtime": "^6.1.18",
41 | "babel-preset-es2015": "^6.1.18",
42 | "babel-preset-stage-1": "^6.5.0",
43 | "babel-runtime": "^6.0.0",
44 | "chai": "^3.3.0",
45 | "chai-as-promised": "^5.1.0",
46 | "css-loader": "^0.21.0",
47 | "eslint": "^2.7.0",
48 | "eslint-config-standard": "^5.1.0",
49 | "eslint-loader": "^1.3.0",
50 | "eslint-plugin-html": "^1.4.0",
51 | "eslint-plugin-promise": "^1.1.0",
52 | "eslint-plugin-standard": "^1.3.2",
53 | "extract-text-webpack-plugin": "^0.9.1",
54 | "file-loader": "^0.8.4",
55 | "highlight.js": "^8.9.1",
56 | "html-loader": "^0.3.0",
57 | "jade": "^1.11.0",
58 | "marked": "^0.3.5",
59 | "mocha": "^2.3.3",
60 | "sinon": "^1.17.1",
61 | "sinon-chai": "^2.8.0",
62 | "style-loader": "^0.13.0",
63 | "stylus-loader": "^1.4.0",
64 | "template-html-loader": "0.0.3",
65 | "url-loader": "^0.5.7",
66 | "vue-hot-reload-api": "1.2.0",
67 | "vue-html-loader": "^1.0.0",
68 | "vue-loader": "^8.1.0",
69 | "vue-router": "0.7.4",
70 | "webpack": "^1.12.2",
71 | "webpack-dev-server": "^1.12.0"
72 | },
73 | "author": "long.zhang@ele.me",
74 | "license": "MIT"
75 | }
76 |
--------------------------------------------------------------------------------
/src/popover.js:
--------------------------------------------------------------------------------
1 | var bindEvent = require('wind-dom').on;
2 | var unbindEvent = require('wind-dom').off;
3 |
4 | export default {
5 | props: {
6 | target: {},
7 | trigger: {
8 | type: String,
9 | default: 'mouseenter'
10 | }
11 | },
12 |
13 | beforeDestroy() {
14 | this.unbindTarget();
15 | },
16 |
17 | methods: {
18 | bindTarget: function() {
19 | var popover = this;
20 | var target = this.target;
21 | if (!target) return;
22 |
23 | var trigger = this.trigger;
24 |
25 | if (trigger === 'click') {
26 | var toggle = () => {
27 | if (popover.visible) {
28 | popover.close();
29 | } else {
30 | popover.open({
31 | target: target,
32 | placement: this.placement
33 | });
34 | }
35 | };
36 | popover.toggleListener = toggle;
37 |
38 | bindEvent(target, 'click', toggle);
39 | } else {
40 | var open = () => {
41 | popover.open({
42 | target: target,
43 | placement: this.placement
44 | });
45 | };
46 | var close = () => {
47 | popover.close();
48 | };
49 | popover.openListener = open;
50 | popover.closeListener = close;
51 |
52 | if (trigger === 'mouseenter') {
53 | bindEvent(target, 'mouseenter', open);
54 | bindEvent(target, 'mouseleave', close);
55 | } else if (trigger === 'focus') {
56 | bindEvent(target, 'focus', open);
57 | bindEvent(target, 'blur', close);
58 | }
59 | }
60 | },
61 | unbindTarget: function() {
62 | var popover = this;
63 | var target = popover.get('target');
64 | if (!target) return;
65 |
66 | var trigger = popover.get('trigger');
67 |
68 | if (trigger === 'click') {
69 | var toggle = popover.toggleListener;
70 | if (toggle) {
71 | bindEvent(target, 'click', toggle);
72 | }
73 | } else {
74 | var open = popover.openListener;
75 | var close = popover.closeListener;
76 | if (!open) return;
77 |
78 | if (trigger === 'mouseenter') {
79 | unbindEvent(target, 'mouseenter', open);
80 | unbindEvent(target, 'mouseleave', close);
81 | } else if (trigger === 'focus') {
82 | unbindEvent(target, 'focus', open);
83 | unbindEvent(target, 'blur', close);
84 | }
85 | }
86 | }
87 | }
88 | };
89 |
--------------------------------------------------------------------------------
/test/validator.js:
--------------------------------------------------------------------------------
1 | import { default as SchemaStore } from '../src/schema/store';
2 |
3 | describe('Validator Unit test', function() {
4 | it('type: required', function() {
5 | var validator = SchemaStore.getValidator('required');
6 |
7 | validator('').should.be.false;
8 | validator(null).should.be.false;
9 | validator(undefined).should.be.false;
10 |
11 | validator(0).should.be.true;
12 | validator(true).should.be.true;
13 | validator(false).should.be.true;
14 | validator(' ').should.be.true;
15 | });
16 |
17 | it('type: length', function() {
18 | var validator = SchemaStore.getValidator('length');
19 |
20 | validator('').should.be.true;
21 | validator(null).should.be.true;
22 | validator(undefined).should.be.true;
23 |
24 | validator('', { min: 1 }).should.be.false;
25 | validator(null, { min: 1 }).should.be.false;
26 | validator(undefined, { min: 1 }).should.be.false;
27 | });
28 |
29 | it('type: range', function() {
30 | var validator = SchemaStore.getValidator('range');
31 |
32 | validator(0).should.be.true;
33 | validator(null).should.be.true;
34 | validator(undefined).should.be.true;
35 | validator(null, { min: 1 }).should.be.true;
36 | validator(undefined, { min: 1 }).should.be.true;
37 |
38 | validator(0, { min: 1 }).should.be.false;
39 | validator('').should.be.false;
40 | });
41 |
42 | it('type: pattern', function() {
43 | var validator = SchemaStore.getValidator('pattern');
44 |
45 | (function() {
46 | validator('');
47 | }).should.throw;
48 |
49 | validator('', { pattern: /i/ }).should.be.false;
50 | validator('i', { pattern: /i/ }).should.be.true;
51 | });
52 |
53 | it('type: enum', function() {
54 | var validator = SchemaStore.getValidator('enum');
55 |
56 | validator(null, { enum: ['a', 'b', 'c'] }).should.be.true;
57 | validator(undefined, { enum: ['a', 'b', 'c'] }).should.be.true;
58 |
59 | validator('', { enum: ['a', 'b', 'c'] }).should.be.false;
60 | validator('a', { enum: ['a', 'b', 'c'] }).should.be.true;
61 | });
62 |
63 | it('type: custom', function() {
64 | var validator = SchemaStore.getValidator('custom');
65 |
66 | (function() {
67 | validator('');
68 | }).should.throw;
69 |
70 | validator('', { validate: function() { return true; } }).should.be.true;
71 | validator('', { validate: function() { return false; } }).should.be.false;
72 | validator('', { validate: function() {} }).should.be.false;
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/src/form/fields/radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
{{key}}
6 |
7 | {{ hintMessage || '' }}
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/markdown.css:
--------------------------------------------------------------------------------
1 | .markdown {
2 | font-family: "Avenir Next", Helvetica, Arial, sans-serif;
3 | padding: 1em;
4 | margin: auto;
5 | max-width: 48em;
6 | color: #5c6b77;
7 | display: block;
8 | }
9 |
10 | .markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 {
11 | font-weight: bold;
12 | }
13 |
14 | .markdown h1 {
15 | color: #000000;
16 | font-size: 28pt;
17 | }
18 |
19 | .markdown h2 {
20 | border-bottom: 1px solid #CCCCCC;
21 | color: #000000;
22 | font-size: 24px;
23 | }
24 |
25 | .markdown h3 {
26 | font-size: 18px;
27 | }
28 |
29 | .markdown h4 {
30 | font-size: 16px;
31 | }
32 |
33 | .markdown h5 {
34 | font-size: 14px;
35 | }
36 |
37 | .markdown h6 {
38 | color: #777777;
39 | background-color: inherit;
40 | font-size: 14px;
41 | }
42 |
43 | .markdown hr {
44 | height: 0.2em;
45 | border: 0;
46 | color: #CCCCCC;
47 | background-color: #CCCCCC;
48 | }
49 |
50 | .markdown p, .markdown blockquote, .markdown ul, .markdown ol, .markdown dl, .markdown li, .markdown table, .markdown pre {
51 | margin: 8px 0;
52 | }
53 |
54 | .markdown a, .markdown a:visited {
55 | color: #4183C4;
56 | background-color: inherit;
57 | text-decoration: none;
58 | }
59 |
60 | .markdown #message {
61 | border-radius: 6px;
62 | border: 1px solid #ccc;
63 | display: block;
64 | width: 100%;
65 | height: 60px;
66 | margin: 6px 0px;
67 | }
68 |
69 | .markdown button, .markdown #ws {
70 | font-size: 10pt;
71 | padding: 4px 6px;
72 | border-radius: 5px;
73 | border: 1px solid #bbb;
74 | background-color: #eee;
75 | }
76 |
77 | .markdown code, .markdown pre, .markdown #ws, .markdown #message {
78 | font-family: Monaco;
79 | font-size: 10pt;
80 | border-radius: 3px;
81 | background-color: #F8F8F8;
82 | color: inherit;
83 | }
84 |
85 | .markdown code {
86 | border: 1px solid #EAEAEA;
87 | margin: 0 2px;
88 | padding: 0 5px;
89 | }
90 |
91 | .markdown pre {
92 | border: 1px solid #CCCCCC;
93 | overflow: auto;
94 | padding: 4px 8px;
95 | }
96 |
97 | .markdown pre > code {
98 | border: 0;
99 | margin: 0;
100 | padding: 0;
101 | }
102 |
103 | .markdown table {
104 | border: 1px solid #e9e9e9;
105 | border-collapse: collapse;
106 | background-color: #fff;
107 | }
108 |
109 | .markdown table td,
110 | .markdown table th {
111 | border: 1px solid #e9e9e9;
112 | padding: 8px;
113 | }
114 |
115 | .markdown table th {
116 | background-color: #59677e;
117 | color: #fff;
118 | }
119 |
--------------------------------------------------------------------------------
/src/service/msgbox.js:
--------------------------------------------------------------------------------
1 | var CONFIRM_TEXT = '确定';
2 | var CANCEL_TEXT = '取消';
3 |
4 | var defaults = {
5 | title: '',
6 | message: '',
7 | type: '',
8 | showConfirmButton: true,
9 | showCancelButton: false,
10 | confirmButtonText: CONFIRM_TEXT,
11 | cancelButtonText: CANCEL_TEXT,
12 | confirmButtonClass: '',
13 | cancelButtonClass: ''
14 | };
15 |
16 | import Vue from 'vue';
17 | import { merge } from '../util';
18 |
19 | var MessageBoxConstructor = Vue.extend(require('./msgbox.vue'));
20 |
21 | var currentMsg, instance;
22 | var msgQueue = [];
23 |
24 | var initInstance = function() {
25 | instance = new MessageBoxConstructor({
26 | el: document.createElement('div')
27 | });
28 |
29 | instance.callback = function(action) {
30 | var result;
31 | if (currentMsg) {
32 | var callback = currentMsg.callback;
33 | if (typeof callback === 'function') {
34 | result = callback(action);
35 | }
36 | }
37 | if (result !== false) {
38 | showNextMsg();
39 | } else {
40 | return false;
41 | }
42 | };
43 | };
44 |
45 | var showNextMsg = function() {
46 | if (!instance) {
47 | initInstance();
48 | }
49 |
50 | if (!instance.visible || instance.closeTimer) {
51 | if (msgQueue.length > 0) {
52 | currentMsg = msgQueue.shift();
53 |
54 | var oldVisible = instance.visible;
55 | instance.visible = false;
56 |
57 | var options = currentMsg.options;
58 | for (var prop in options) {
59 | if (options.hasOwnProperty(prop)) {
60 | instance[prop] = options[prop];
61 | }
62 | }
63 |
64 | instance.visible = oldVisible;
65 |
66 | instance.open();
67 | }
68 | }
69 | };
70 |
71 | var MessageBox = function(options, callback) {
72 | if (typeof options === 'string') {
73 | options = {
74 | title: options
75 | };
76 | if (arguments[1]) {
77 | options.message = arguments[1];
78 | }
79 | if (arguments[2]) {
80 | options.type = arguments[2];
81 | }
82 | } else if (options.callback && !callback) {
83 | callback = options.callback;
84 | }
85 |
86 | msgQueue.push({
87 | options: merge({}, defaults, MessageBox.defaults || {}, options),
88 | callback: callback
89 | });
90 |
91 | showNextMsg();
92 | };
93 |
94 | MessageBox.setDefaults = function(defaults) {
95 | MessageBox.defaults = defaults;
96 | };
97 |
98 | MessageBox.close = function() {
99 | instance.close();
100 | msgQueue = [];
101 | currentMsg = null;
102 | };
103 |
104 | export default MessageBox;
105 |
--------------------------------------------------------------------------------
/examples/data/custom-grid-test.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Remove Column
4 | Clear Column
5 | Change Data
6 |
7 |
8 |
9 |
10 |
12 |
13 |
--------------------------------------------------------------------------------
/src/form/fields/check-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
6 |
8 |
9 |
10 | {{ hintMessage || '' }}
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/src/form/fields/field.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
6 |
7 |
8 |
88 |
89 |
--------------------------------------------------------------------------------
/examples/index.js:
--------------------------------------------------------------------------------
1 | var Vue = require('vue');
2 | Vue.config.debug = true;
3 | var VueRouter = require('vue-router');
4 | Vue.use(VueRouter);
5 |
6 | require('./markdown.css');
7 | require('./markdown');
8 | require('highlight.js/styles/agate.css');
9 |
10 | require('../src/index');
11 |
12 | var router = new VueRouter();
13 |
14 | // basic
15 | router.map({
16 | '/dialog': {
17 | component: require('./basic/dialog.vue')
18 | },
19 | '/button': {
20 | component: require('./basic/button.vue')
21 | },
22 | '/progress-bar': {
23 | component: require('./basic/progress-bar.vue')
24 | },
25 | '/alert': {
26 | component: require('./basic/alert.vue')
27 | },
28 | '/slider': {
29 | component: require('./basic/slider.vue')
30 | },
31 | '/sticky': {
32 | component: require('./basic/sticky.vue')
33 | },
34 | '/dropdown': {
35 | component: require('./basic/dropdown.vue')
36 | },
37 | '/navmenu': {
38 | component: require('./basic/nav-menu.vue')
39 | }
40 | });
41 |
42 | // form
43 | router.map({
44 | '/validation': {
45 | component: require('./form/validation.vue')
46 | },
47 | '/mapping': {
48 | component: require('./form/mapping.vue')
49 | },
50 | '/field': {
51 | component: require('./form/field.vue')
52 | },
53 | '/editor': {
54 | component: require('./form/editor.vue')
55 | },
56 | '/tags': {
57 | component: require('./form/tags.vue')
58 | },
59 | '/upload': {
60 | component: require('./form/upload.vue')
61 | }
62 | });
63 |
64 | // nav
65 | router.map({
66 | '/tabs': {
67 | component: require('./nav/tabs.vue')
68 | },
69 | '/accordion': {
70 | component: require('./nav/accordion.vue')
71 | },
72 | '/breadcrumb': {
73 | component: require('./nav/breadcrumb.vue')
74 | }
75 | });
76 |
77 | // data
78 | router.map({
79 | '/grid': {
80 | component: require('./data/grid.vue')
81 | },
82 | '/tree': {
83 | component: require('./data/tree.vue')
84 | },
85 | '/crud': {
86 | component: require('./data/crud.vue')
87 | },
88 | '/custom-grid-test': {
89 | component: require('./data/custom-grid-test.vue')
90 | },
91 | '/pagination': {
92 | component: require('./data/pagination.vue')
93 | }
94 | });
95 |
96 | // service
97 | router.map({
98 | '/msgbox': {
99 | component: require('./service/msgbox.vue')
100 | },
101 | '/notification': {
102 | component: require('./service/notification.vue')
103 | },
104 | '/tooltip': {
105 | component: require('./service/tooltip.vue')
106 | },
107 | '/loading-mask': {
108 | component: require('./service/loading-mask.vue')
109 | }
110 | });
111 |
112 | router.start(Vue.extend({
113 | components: {
114 | app: require('./app.vue')
115 | }
116 | }), 'body');
117 |
--------------------------------------------------------------------------------
/docs/schema/README.MD:
--------------------------------------------------------------------------------
1 | # Schema 使用说明
2 |
3 | ## 介绍
4 | vue-desktop 项目中 Field 和 Grid 的使用依赖于 Schema,Schema 是 vue-desktop 区别于其他 UI 项目的特点,在使用 vue-desktop 之前,需要先了解 Schema 的概念和用途。
5 |
6 | ## 简单示例
7 | Schema 用来描述表单里面的一个数据显示使用的 label、数据类型、校验规则等。
8 |
9 | 先来看一个简单的例子,我们有一个表单是这个样子:
10 |
11 | 
12 |
13 | Schema 里面定义的是数据的结构,比如我们这个表单需要这么几个属性:
14 |
15 | - userName: 字符串,必填项。
16 | - email: 字符串,必填项。
17 | - password: 字符串,必填项,长度介于6-20。
18 | - confirmPassword: 字符串,必填项,长度介于6-20,需要与 password 一致。
19 | - comment:字符串,可以不填。
20 |
21 | 那么我们的 Schema 需要这么定义:
22 |
23 | ```
24 | var userSchema = new Schema({
25 | userName: {
26 | label: ‘用户名’,
27 | whitespace: false,
28 | required: true
29 | },
30 |
31 | email: {
32 | label: ‘Email’,
33 | required: true
34 | },
35 |
36 | password: {
37 | label: ‘密码’,
38 | required: true,
39 | minLength: 6,
40 | maxLength: 20
41 | },
42 |
43 | confirmPassword: {
44 | label: ‘确认密码’,
45 | required: true,
46 | minLength: 6,
47 | maxLength: 20,
48 | rules: {
49 | type: ‘custom’,
50 | message: ‘两次输入的密码不一致’,
51 | validate() {
52 | return this.password === this.confirmPassword;
53 | }
54 | }
55 | },
56 |
57 | comment: {
58 | label: ‘备注’
59 | }
60 | });
61 | ```
62 |
63 | 可以看到,我们在这个 Schema 里面定义了字段的如下信息:
64 | - label:页面上看到的字段信息。
65 | - 校验规则:required、minLength、maxLength等。
66 |
67 | ## 使用说明
68 |
69 | ### 属性列表
70 |
71 | | 属性 | 说明 |
72 | |------|------|
73 | | type | 数据类型,可选值:string、boolean、number、float、integer、date、datetime。 |
74 | | label | 在页面上显示的文本信息,比如 Field 的 label 或者 Grid 的表头信息。 |
75 | | default | 该字段的默认值。|
76 | | format | 该字段显示为文本的时候使用的格式,目前仅数据类型为 date、datetime 的字段支持该属性。// TODO format 说明 |
77 | | required | 是否必填项目,默认值为 false。|
78 | | whitespace | 是否允许内容为带空格的字符串,默认值为 false。|
79 | | min | 该字段值的最小值,只对 number、integer、float 类型的字段起作用。|
80 | | max | 该字段值的最大值,只对 number、integer、float 类型的字段起作用。|
81 | | minLength | 该字段值的长度的最小值,只对 string 类型的字段起作用。|
82 | | minLength | 该字段值的长度的最大值,只对 string 类型的字段起作用。|
83 | | pattern | 该字段需要匹配的正则表达式。 |
84 | | enum | 该字段值的取值列表,需要定义为数组。比如只能取值 A、B、C,则定义为[ 'A', 'B', 'C' ] |
85 | | messages | 通过属性定义的校验规则都有默认的校验信息,如果不想使用默认的校验信息,可以使用 messages 属性来覆写。比如想覆写 pattern 类型的校验信息,则 messages 定义为 { pattern: '没有通过校验' }|
86 | | rules | 如果通过属性定义的校验规则无法满足需求,可以使用 rules 属性来增加自定义规则。rules 可以是一个数组,也可以是一个对象。rules 里面可以定义两个属性,一个是 message(校验失败后的信息),一个是 validate 方法(校验方法)。|
87 |
88 | ### 方法列表
89 |
90 | | 方法 | 说明 |
91 | | ------ | ------ |
92 | | create | 创建一个空的对象,该对象有 schema 中定义的所有字段,如果 schema 有默认值定义,则空对象该字段的值为默认值。|
93 | | validate(object, options, callback) | 校验 object 是否符合 schema 中定义的规则。 |
94 | | validateProperty(object, property) | 校验 object 的某个 property 是否符合规则。 |
95 | | save(object) | 保存 object 当前的值,可以通过 reset 方法来恢复保存的值。 |
96 | | reset(object) | 恢复保存的 object 的值,如果没有通过 save 方法保存过,则恢复为一个新建的对象。|
97 | | getPropertyDescriptor(property) | 取得某个 property 的定义。 |
98 |
--------------------------------------------------------------------------------
/icons/close-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/basic/button-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
44 |
45 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | require('./icon/iconfont.css');
2 | require('./common.css');
3 |
4 | import Alert from './basic/alert.vue';
5 | import Panel from './basic/panel.vue';
6 | import Dialog from './basic/dialog.vue';
7 | import Button from './basic/button.vue';
8 | import ButtonGroup from './basic/button-group.vue';
9 | import ProgressBar from './basic/progress-bar.vue';
10 | import Slider from './basic/slider.vue';
11 | import Sticky from './basic/sticky.vue';
12 | import DropdownButton from './basic/dropdown.vue';
13 | import DropdownItem from './basic/dropdown-item.vue';
14 | import DropdownDivider from './basic/dropdown-divider.vue';
15 | import Vbox from './basic/vbox.vue';
16 | import NavMenu from './basic/nav-menu.vue';
17 | import NavMenuItem from './basic/nav-menu-item.vue';
18 |
19 | import Accordion from './nav/accordion.vue';
20 | import AccordionPanel from './nav/accordion-panel.vue';
21 | import Tab from './nav/tab.vue';
22 | import Tabs from './nav/tabs.vue';
23 | import Breadcrumb from './nav/breadcrumb.vue';
24 | import BreadcrumbItem from './nav/breadcrumb-item.vue';
25 |
26 | import Grid from './data/grid.vue';
27 | import GridColumn from './data/grid-column.vue';
28 | import Tree from './data/tree.vue';
29 |
30 | import Pagination from './data/pagination.vue';
31 |
32 | export var Components = {
33 | Alert,
34 | Panel,
35 | Dialog,
36 | Button,
37 | ButtonGroup,
38 | ProgressBar,
39 | Slider,
40 | Sticky,
41 |
42 | DropdownButton,
43 | DropdownItem,
44 | DropdownDivider,
45 |
46 | Vbox,
47 |
48 | NavMenu,
49 | NavMenuItem,
50 |
51 | Accordion,
52 | AccordionPanel,
53 |
54 | Tab,
55 | Tabs,
56 |
57 | Breadcrumb,
58 | BreadcrumbItem,
59 |
60 | Grid,
61 | GridColumn,
62 | Tree,
63 | Pagination
64 | };
65 |
66 | import FormComponents from './form/index';
67 | import { merge } from './util';
68 |
69 | merge(Components, FormComponents);
70 |
71 | var initComponents = (Vue, prefix, components) => {
72 | if (arguments.length < 3) { // eslint-disable-line no-undef
73 | components = prefix;
74 | prefix = 'D';
75 | } else {
76 | if (!prefix) {
77 | prefix = 'D';
78 | }
79 | }
80 |
81 | if (!components) components = Object.keys(Components);
82 |
83 | if (components instanceof Array) {
84 | for (var i = 0, j = components.length; i < j; i++) {
85 | var key = components[i];
86 | Vue.component(prefix + key, Components[key]);
87 | }
88 | }
89 | };
90 |
91 | var Vue = require('vue');
92 | var i18n = require('vue-i18n');
93 |
94 | import { default as locales } from './locales/index';
95 |
96 | Vue.use(i18n, {
97 | lang: 'zh',
98 | locales: locales
99 | });
100 |
101 | initComponents(Vue);
102 |
103 | require('./service/tooltip');
104 |
105 | export { default as MessageBox } from './service/msgbox';
106 |
107 | export { default as Notification } from './service/notification';
108 |
109 | export { default as Schema } from './schema/index';
110 |
111 | export { default as LoadingMask } from './service/loading-mask';
112 |
--------------------------------------------------------------------------------
/src/form/fields/text.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ labelText }}
4 |
5 |
6 |
7 |
8 | {{ hintMessage || '' }}
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/grid.md:
--------------------------------------------------------------------------------
1 |
2 | # Overview
3 |
4 | Grid 是一个数据表格组件,用来展示一组数据。
5 |
6 | # Usage
7 |
8 | 使用 d-grid 标签即可创建一个 Grid 组件。
9 |
10 | ```HTML
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 测试1
21 |
22 |
23 | ```
24 |
25 | 其中 gridData 和 gridSchema 的定义如下:
26 |
27 | ```JavaScript
28 | import { Schema } from 'vue-desktop'
29 |
30 | var gridSchema = new Schema({
31 | prop1: {
32 | label: '测试1',
33 | required: true
34 | },
35 | prop2: {
36 | label: '测试2',
37 | required: true
38 | },
39 | prop3: {
40 | label: '测试3',
41 | type: 'date'
42 | },
43 | prop4: {
44 | label: '测试4'
45 | },
46 | prop5: {
47 | label: '测试5',
48 | mapping: {
49 | 'Male': true,
50 | 'Female': false
51 | }
52 | }
53 | });
54 | ```
55 |
56 | ```JavaScript
57 | var gridData = [
58 | {prop1: '11', prop2: '12', prop3: new Date(), prop4: '14', prop5: true},
59 | {prop1: '21', prop2: '22', prop3: new Date(), prop4: '24', prop5: false},
60 | {prop1: '31', prop2: '32', prop3: new Date(), prop4: '34', prop5: false},
61 | {prop1: '41', prop2: '42', prop3: new Date(), prop4: '44', prop5: true},
62 | {prop1: '51', prop2: '52', prop3: new Date(), prop4: '54', prop5: false}
63 | ];
64 | ```
65 |
66 | # Grid Properties
67 |
68 | Grid 目前可用的属性如下:
69 |
70 | | Property | Description |
71 | | ---- | ---- |
72 | | data | Grid 显示的数据。 |
73 | | schema | Grid 使用的 Schema。 |
74 | | height | Grid 的高度,默认高度为空,即自动高度。 |
75 | | fit | Grid 的列的宽度是否自撑开,Boolean 类型,默认为 false。|
76 | | selectionMode | selectionMode的可选值 single,multiple,none; 默认值 single。|
77 | | selection | 多选模式下返回数组,单选模式下返回选中的元素。 |
78 | | fixedColumnCount | 锁定列的数量,默认值为0。|
79 |
80 | # Grid 的事件
81 |
82 | Grid 目前支持的事件如下:
83 |
84 | | Property | Description | Params |
85 | | ---- | ---- | ---- |
86 | | selection-change | 当 Grid 的选择修改的时候会触发该事件。 | selected |
87 | | cell-mouse-enter | 当 Grid 的单元格 hover 进入的时候会触发该事件。 | row, column, cell, event |
88 | | cell-mouse-leave | 当 Grid 的单元格 hover 退出的时候会触发该事件。 | row, column, cell, event |
89 | | cell-click | 当 Grid 的某个单元格被点击的时候会触发该事件。| row, column, cell, event |
90 |
91 | # Grid Column Properties
92 |
93 | Grid Column 目前可用的属性如下:
94 |
95 | | Property | Description |
96 | | ---- | ---- |
97 | | label | Grid Column 显示的标题。如果不设置此属性,并且 Grid 定义了 Schema,并且 Grid Column 定义了property,则从 Schema 中获得 label。 |
98 | | property | Grid Column 要显示的字段名。 |
99 | | width | Grid Column 的宽度。 |
100 | | sortable | Grid Column 是否可以排序,在设置了 property 的情况下,该属性的默认值为 true,反之为 false。 |
101 | | type | Grid Column 的类型,默认为空,可选值:selection、index。如果设置了 selection 则显示多选按钮,如果设置了 index,则显示该行的索引(从1开始计算)。 |
102 | | formatter | Grid Column 的 formatter,Function 类型,可以用来格式化内容,在 formatter 执行的时候,会传入 row 和 column。 |
103 |
104 | ## Grid Column中的内容
105 |
106 | Grid Column 中可以定制该列显示的内容,在 Grid Column 中,可以使用 row 属性访问到每一行的数据。
107 |
108 | 比如想为上面例子中的 prop2 列的显示内容之后添加一个前缀,比如是『¥』。
109 |
110 | 那么,可以这么定义该列:
111 | ```HTML
112 | ¥{{row.prop2}}
113 | ```
114 |
--------------------------------------------------------------------------------
/examples/basic/button.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Button
4 |
5 |
6 |
7 | Primary Button
8 | Default Button
9 | Success Button
10 | Info Button
11 | Warning Button
12 | Danger Button
13 |
14 |
15 |
16 | Home
17 | Library
18 | Applications
19 | Settings
20 |
21 |
22 |
23 | Large Button
24 | Medium Button (default)
25 | Small Button
26 |
27 |
28 |
29 | Primary Button
30 | Primary Button (disabled)
31 | Default Button
32 | Default Button (disabled)
33 | Success Button
34 | Success Button (disabled)
35 |
36 |
37 |
38 |
39 | 确定
40 | 取消
41 |
42 |
43 |
44 | 左
45 | 中
46 | 右
47 |
48 |
49 |
50 | 左
51 | 中
52 | 中
53 | 右
54 |
55 |
56 |
57 |
58 |
59 | 下单立减
60 | 专享红包
61 | 特价秒杀
62 | 赠品优惠
63 | 在线支付
64 |
65 |
66 |
67 |
68 |
69 | 全部商家
70 | 甜品饮品
71 | 小吃零食
72 | 鲜花蛋糕
73 | 果蔬生鲜
74 |
75 |
76 |
77 |
78 |
79 | 大
80 | 大
81 | 大
82 |
83 |
84 | 默认
85 | 默认
86 | 默认
87 |
88 |
89 | 小
90 | 小
91 | 小
92 |
93 |
94 |
95 |
96 |
101 |
102 |
--------------------------------------------------------------------------------
/src/basic/nav-menu-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
83 |
84 |
--------------------------------------------------------------------------------
/src/service/notification.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{title}}
6 |
{{message}}
7 |
8 |
9 |
10 |
11 |
12 |
83 |
84 |
--------------------------------------------------------------------------------
/docs/tree.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Tree 是用来展现树形结构的组件,节点支持多选,节点可以显示图标。
4 |
5 | # Usage
6 |
7 | Tree 的使用可以依赖于 levelConfig,也可以不依赖于 levelConfig。
8 | - 在简单的场景下,可以不使用 levelConfig,但是要求 data 属性的格式为指定的格式。
9 | - 假设每一个层级的数据都不一样,有点层级可能还是在需要显示的时候才去服务器加载数据。在这种情况下,需要使用 levelConfig 来定义每一个层级的数据。
10 |
11 | ## 不使用 levelConfig
12 |
13 | 在不使用 levelConfig 的情况下,要求节点使用的文本使用 label 属性来定义,子节点使用 children 属性来定义,一个简单的例子如下:
14 |
15 | ```JavaScript
16 | export default {
17 | data() {
18 | return {
19 | data: [{
20 | label: 'bb',
21 | children: [{
22 | label: 'b1'
23 | }]
24 | }, {
25 | label: 'cc',
26 | children: [{
27 | label: 'cc1'
28 | }, {
29 | label: 'cc2'
30 | }]
31 | }]
32 | }
33 | }
34 | }
35 | ```
36 |
37 | ```HTML
38 |
39 | ```
40 |
41 | ## 使用 levelConfig
42 |
43 | 对 Tree 的每一个层级的节点来讲,每一个节点需要从 JavaScript 中的一个对象映射过来。对于数据来讲,需要关注的点有这么几个:label 用的属性是哪一个,children 用的属性是哪一个,以及下级节点与数据的映射关系。
44 |
45 | 举例来讲,我们有一个两级的树,第一级叫 regions,第二级叫 zones:
46 | - 第一级的数据使用的 label 使用 name 属性。在 label 显示为 label或name 的情况下,无需指定 labelProperty。
47 | - 第二级是一个懒加载的,例子里面我们使用一个虚拟的加载,使用 setTimeout 做一个简单的模拟,在500ms后有50%的概率返回两条数据。
48 |
49 | 那么,levelConfig 这么定义:
50 |
51 | ```JavaScript
52 | var count = 1;
53 | var levelConfig = {
54 | childrenProperty: 'zones',
55 |
56 | children: {
57 | lazy: true,
58 | load: function (node, callback) {
59 | var hasChild = Math.random() > 0.5;
60 | setTimeout(function () {
61 | var data;
62 | if (hasChild) {
63 | data = [{
64 | name: 'zone' + count++
65 | }, {
66 | name: 'zone' + count++
67 | }];
68 | } else {
69 | data = [];
70 | }
71 |
72 | node.children = data;
73 | if (callback) {
74 | callback();
75 | }
76 | }, 500);
77 | }
78 | }
79 | };
80 | ```
81 |
82 | 数据为:
83 | ```JavaScript
84 | var regions = [
85 | {
86 | 'name': 'region1'
87 | },
88 | {
89 | 'name': 'region2'
90 | }
91 | ];
92 | ```
93 |
94 | HTML 为:
95 |
96 | ```HTML
97 |
98 | ```
99 |
100 | # Properties
101 |
102 | Tree 目前可以使用的属性如下:
103 |
104 | | Property | Description |
105 | | ---- | ---- |
106 | | data | 数组类型。 |
107 | | levelConfig | 树的层级定义,具体使用说明请参考下面的表格。 |
108 | | lazyRender | 是否懒渲染子节点,默认值为 true。|
109 |
110 | levelConfig可以使用的属性如下:
111 |
112 | | Property | Description |
113 | | ---- | ---- |
114 | | labelProperty | label 使用的属性是哪一个,如果需要使用 name 或者 label 作为节点的文本,则无需定义该属性。 |
115 | | childrenProperty | children 使用的属性是哪一个,如果为 children,则无需定义该属性。 |
116 | | checkedProperty | Node 的 checkbox 选中使用的属性是哪一个,没有默认值,如果不定义,则表示不需要同步选中的节点。 |
117 | | lazy | 节点是否懒加载,默认为 false。 |
118 | | load | 如果 lazy 属性为 true,在需要展现该节点的时候,会使用 load 方法来加载数据。 |
119 | | recursive | 是否一个递归 level,默认值为 false。如果是一个递归 level,则 children 的 levelConfig 和自身相同。|
120 | | children | 下级节点的配置,同样是一个 levelConfig 。 |
121 |
122 | Tree 目前可以使用的方法如下:
123 |
124 | - getCheckedNodes(leafNodeOnly): 取得目前所有选中的节点,leafNodeOnly 用来表明是否只获取叶子节点,默认值为 false。
125 |
126 | ## lazy: true 的 levelConfig
127 |
128 | 对于 lazy: true 的 levelConfig,需要同时提供一个 load 方法,该方法是一个回调,需要这么做:
129 |
130 | ```JavaScript
131 | load: function (node, callback) {
132 | var hasChild = Math.random() > 0.5;
133 | setTimeout(function () {
134 | var data;
135 | if (hasChild) {
136 | data = [{
137 | name: 'zone' + count++
138 | }, {
139 | name: 'zone' + count++
140 | }];
141 | } else {
142 | data = [];
143 | }
144 |
145 | node.children = data;
146 | if (callback) {
147 | callback();
148 | }
149 | }, 500);
150 | }
151 | ```
152 |
153 | 需要注意两点:
154 |
155 | 1. 需要注意的是 callback 需要检查并执行。
156 | 2. 设置 node.children 用来设置 node 的子节点。
157 |
--------------------------------------------------------------------------------
/src/basic/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{title}}
6 |
7 |
{{closeText}}
8 |
9 |
10 |
11 |
12 |
119 |
120 |
--------------------------------------------------------------------------------
/src/service/msgbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
{{ message }}
10 |
11 |
12 | {{ confirmButtonText }}
13 | {{ cancelButtonText }}
14 |
15 |
16 |
17 |
18 |
99 |
100 |
151 |
--------------------------------------------------------------------------------
/src/basic/dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{title}}
4 |
5 |
6 |
7 |
8 |
9 |
48 |
49 |
--------------------------------------------------------------------------------
/src/service/tooltip.vue:
--------------------------------------------------------------------------------
1 |
109 |
110 |
111 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/common.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Modified from http://purecss.io/grids/
3 | */
4 |
5 | .d-cell {
6 | display: inline-block;
7 | *display: inline; /* IE < 8: fake inline-block */
8 | zoom: 1;
9 | letter-spacing: normal;
10 | word-spacing: normal;
11 | vertical-align: top;
12 | text-rendering: auto;
13 | }
14 |
15 | .d-cell-1,
16 | .d-cell-1-1,
17 | .d-cell-1-2,
18 | .d-cell-1-3,
19 | .d-cell-2-3,
20 | .d-cell-1-4,
21 | .d-cell-3-4,
22 | .d-cell-1-5,
23 | .d-cell-2-5,
24 | .d-cell-3-5,
25 | .d-cell-4-5,
26 | .d-cell-5-5,
27 | .d-cell-1-6,
28 | .d-cell-5-6,
29 | .d-cell-1-8,
30 | .d-cell-3-8,
31 | .d-cell-5-8,
32 | .d-cell-7-8,
33 | .d-cell-1-12,
34 | .d-cell-5-12,
35 | .d-cell-7-12,
36 | .d-cell-11-12,
37 | .d-cell-1-24,
38 | .d-cell-2-24,
39 | .d-cell-3-24,
40 | .d-cell-4-24,
41 | .d-cell-5-24,
42 | .d-cell-6-24,
43 | .d-cell-7-24,
44 | .d-cell-8-24,
45 | .d-cell-9-24,
46 | .d-cell-10-24,
47 | .d-cell-11-24,
48 | .d-cell-12-24,
49 | .d-cell-13-24,
50 | .d-cell-14-24,
51 | .d-cell-15-24,
52 | .d-cell-16-24,
53 | .d-cell-17-24,
54 | .d-cell-18-24,
55 | .d-cell-19-24,
56 | .d-cell-20-24,
57 | .d-cell-21-24,
58 | .d-cell-22-24,
59 | .d-cell-23-24,
60 | .d-cell-24-24 {
61 | display: inline-block;
62 | *display: inline;
63 | zoom: 1;
64 | letter-spacing: normal;
65 | word-spacing: normal;
66 | vertical-align: top;
67 | text-rendering: auto;
68 | }
69 |
70 | .d-cell-1-24 {
71 | width: 4.1667%;
72 | *width: 4.1357%;
73 | }
74 |
75 | .d-cell-1-12,
76 | .d-cell-2-24 {
77 | width: 8.3333%;
78 | *width: 8.3023%;
79 | }
80 |
81 | .d-cell-1-8,
82 | .d-cell-3-24 {
83 | width: 12.5000%;
84 | *width: 12.4690%;
85 | }
86 |
87 | .d-cell-1-6,
88 | .d-cell-4-24 {
89 | width: 16.6667%;
90 | *width: 16.6357%;
91 | }
92 |
93 | .d-cell-1-5 {
94 | width: 20%;
95 | *width: 19.9690%;
96 | }
97 |
98 | .d-cell-5-24 {
99 | width: 20.8333%;
100 | *width: 20.8023%;
101 | }
102 |
103 | .d-cell-1-4,
104 | .d-cell-6-24 {
105 | width: 25%;
106 | *width: 24.9690%;
107 | }
108 |
109 | .d-cell-7-24 {
110 | width: 29.1667%;
111 | *width: 29.1357%;
112 | }
113 |
114 | .d-cell-1-3,
115 | .d-cell-8-24 {
116 | width: 33.3333%;
117 | *width: 33.3023%;
118 | }
119 |
120 | .d-cell-3-8,
121 | .d-cell-9-24 {
122 | width: 37.5000%;
123 | *width: 37.4690%;
124 | }
125 |
126 | .d-cell-2-5 {
127 | width: 40%;
128 | *width: 39.9690%;
129 | }
130 |
131 | .d-cell-5-12,
132 | .d-cell-10-24 {
133 | width: 41.6667%;
134 | *width: 41.6357%;
135 | }
136 |
137 | .d-cell-11-24 {
138 | width: 45.8333%;
139 | *width: 45.8023%;
140 | }
141 |
142 | .d-cell-1-2,
143 | .d-cell-12-24 {
144 | width: 50%;
145 | *width: 49.9690%;
146 | }
147 |
148 | .d-cell-13-24 {
149 | width: 54.1667%;
150 | *width: 54.1357%;
151 | }
152 |
153 | .d-cell-7-12,
154 | .d-cell-14-24 {
155 | width: 58.3333%;
156 | *width: 58.3023%;
157 | }
158 |
159 | .d-cell-3-5 {
160 | width: 60%;
161 | *width: 59.9690%;
162 | }
163 |
164 | .d-cell-5-8,
165 | .d-cell-15-24 {
166 | width: 62.5000%;
167 | *width: 62.4690%;
168 | }
169 |
170 | .d-cell-2-3,
171 | .d-cell-16-24 {
172 | width: 66.6667%;
173 | *width: 66.6357%;
174 | }
175 |
176 | .d-cell-17-24 {
177 | width: 70.8333%;
178 | *width: 70.8023%;
179 | }
180 |
181 | .d-cell-3-4,
182 | .d-cell-18-24 {
183 | width: 75%;
184 | *width: 74.9690%;
185 | }
186 |
187 | .d-cell-19-24 {
188 | width: 79.1667%;
189 | *width: 79.1357%;
190 | }
191 |
192 | .d-cell-4-5 {
193 | width: 80%;
194 | *width: 79.9690%;
195 | }
196 |
197 | .d-cell-5-6,
198 | .d-cell-20-24 {
199 | width: 83.3333%;
200 | *width: 83.3023%;
201 | }
202 |
203 | .d-cell-7-8,
204 | .d-cell-21-24 {
205 | width: 87.5000%;
206 | *width: 87.4690%;
207 | }
208 |
209 | .d-cell-11-12,
210 | .d-cell-22-24 {
211 | width: 91.6667%;
212 | *width: 91.6357%;
213 | }
214 |
215 | .d-cell-23-24 {
216 | width: 95.8333%;
217 | *width: 95.8023%;
218 | }
219 |
220 | .d-cell-1,
221 | .d-cell-1-1,
222 | .d-cell-5-5,
223 | .d-cell-24-24 {
224 | width: 100%;
225 | }
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | const dateUtil = require('fecha');
2 |
3 | export function merge(target) {
4 | for (var i = 1, j = arguments.length; i < j; i++) {
5 | var source = arguments[i];
6 | for (var prop in source) {
7 | if (source.hasOwnProperty(prop)) {
8 | var value = source[prop];
9 | if (value !== undefined) {
10 | target[prop] = value;
11 | }
12 | }
13 | }
14 | }
15 |
16 | return target;
17 | }
18 |
19 | export function formatDate(date, format) {
20 | if (!(date instanceof Date)) return '';
21 | return dateUtil.format(date, format || 'YYYY-MM-DD');
22 | }
23 |
24 | export function parseDate(string, format) {
25 | return dateUtil.parse(string, format || 'YYYY-MM-DD');
26 | }
27 |
28 | export function debounce(fn, delay) {
29 | var timer;
30 |
31 | return function() {
32 | var context = this;
33 | var args = arguments;
34 | if (timer) {
35 | clearTimeout(timer);
36 | timer = null;
37 | }
38 | timer = setTimeout(function() {
39 | fn.apply(context, args);
40 | timer = null;
41 | }, delay);
42 | };
43 | }
44 |
45 | export function throttle(fn, delay) {
46 | var now, lastExec, timer, context, args;
47 |
48 | var execute = function() {
49 | fn.apply(context, args);
50 | lastExec = now;
51 | };
52 |
53 | return function() {
54 | context = this;
55 | args = arguments;
56 |
57 | now = Date.now();
58 |
59 | if (timer) {
60 | clearTimeout(timer);
61 | timer = null;
62 | }
63 |
64 | if (!lastExec) {
65 | execute();
66 | } else {
67 | var diff = delay - (now - lastExec);
68 | if (diff < 0) {
69 | execute();
70 | } else {
71 | timer = setTimeout(function() {
72 | execute();
73 | }, diff);
74 | }
75 | }
76 | };
77 | }
78 |
79 | export function getNestedPath(object, nestedProp) {
80 | let propertyArr = nestedProp.split('.');
81 | let property = propertyArr.pop();
82 | return getPath(object, propertyArr.join('.')).fields[property];
83 | }
84 |
85 | export function getPath(object, prop) {
86 | prop = prop || '';
87 | var paths = prop.split('.');
88 | var current = object;
89 | var result = null;
90 | for (var i = 0, j = paths.length; i < j; i++) {
91 | var path = paths[i];
92 | if (!current) break;
93 |
94 | if (i === j - 1) {
95 | result = current[path];
96 | break;
97 | }
98 | current = current[path];
99 | }
100 | return result;
101 | }
102 |
103 | export function setPath(object, prop, value) {
104 | if (prop === undefined || prop === null) return;
105 |
106 | if (typeof prop === 'object') {
107 | var target = prop;
108 | for (prop in target) {
109 | if (target.hasOwnProperty(prop)) {
110 | setPath(object, prop, target[prop]);
111 | }
112 | }
113 | } else {
114 | prop = prop || '';
115 | var paths = prop.split('.');
116 | var current = object;
117 | for (var i = 0, j = paths.length; i < j; i++) {
118 | var path = paths[i];
119 | if (!current) break;
120 | if (i === j - 1) {
121 | current[path] = value;
122 | break;
123 | }
124 | current = current[path];
125 | }
126 | }
127 | }
128 |
129 | var scrollbarWidth;
130 |
131 | export function getScrollbarWidth() {
132 | if (scrollbarWidth !== undefined) return scrollbarWidth;
133 |
134 | var outer = document.createElement('div');
135 | outer.style.visibility = 'hidden';
136 | outer.style.width = '100px';
137 | outer.style.position = 'absolute';
138 | outer.style.top = '-9999px';
139 | document.body.appendChild(outer);
140 |
141 | var widthNoScroll = outer.offsetWidth;
142 | outer.style.overflow = 'scroll';
143 |
144 | var inner = document.createElement('div');
145 | inner.style.width = '100%';
146 | outer.appendChild(inner);
147 |
148 | var widthWithScroll = inner.offsetWidth;
149 | outer.parentNode.removeChild(outer);
150 |
151 | return widthNoScroll - widthWithScroll;
152 | }
153 |
--------------------------------------------------------------------------------
/examples/form/mapping.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 |
--------------------------------------------------------------------------------
/examples/app.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
156 |
--------------------------------------------------------------------------------
/examples/data/tree.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | getCheckedNodes
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
26 |
--------------------------------------------------------------------------------