20 | git push -f git@github.com:mywebc/vueComponents.git master:gh-pages
21 |
22 | cd -
--------------------------------------------------------------------------------
/docs/.vuepress/components/button-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Button
4 | Button
5 | Button
6 | Button
7 |
8 |
9 |
19 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/cascader-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
55 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/collapse-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
通过single控制是否为手风琴模式
4 |
5 | 内容1
6 | 内容2
7 | 内容3
8 |
9 |
10 | 手风琴模式
11 |
12 | 内容1
13 | 内容2
14 | 内容3
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/grid-demos.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 |
41 |
42 |
43 |
44 |
45 |
56 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/icon-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/input-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
默认
4 |
5 | 禁用
6 |
7 | 只读
8 |
9 | 提示
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/layout-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | content
6 |
7 |
8 |
9 |
10 |
11 |
12 | sider
13 | content
14 |
15 |
16 |
17 |
18 |
19 | sider
20 |
21 |
22 | content
23 |
24 |
25 |
26 |
27 |
28 |
45 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/nav-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 首页
5 |
6 | 关于
7 | 企业文化
8 | 开发团队
9 |
10 | 联系方式
11 | 微信
12 | QQ
13 |
14 | 手机
15 | 移动
16 | 联通
17 | 电信
18 |
19 |
20 |
21 | 招聘
22 |
23 |
24 |
25 |
26 |
27 |
48 |
49 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/nav2-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 首页
6 |
7 |
8 | 关于
9 | 企业文化
10 | 开发团队
11 |
12 | 联系方式
13 | 微信
14 | QQ
15 |
16 | 手机
17 | 移动
18 | 联通
19 | 电信
20 |
21 |
22 |
23 | 招聘
24 |
25 |
26 |
27 |
28 |
48 |
49 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/pager-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/popover-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
默认位置为top,通过position控制
4 |
5 |
6 | popover内容
7 |
8 |
9 | hover点我
10 |
11 |
12 |
13 |
14 | popover内容
15 |
16 |
17 | hover点我
18 |
19 |
20 |
21 |
22 | popover内容
23 |
24 |
25 | hover点我
26 |
27 |
28 |
29 |
30 | popover内容
31 |
32 |
33 | hover点我
34 |
35 |
36 |
37 |
38 |
39 | popover内容
40 |
41 |
42 | click点我
43 |
44 |
45 |
46 |
47 | popover内容
48 |
49 |
50 | click点我
51 |
52 |
53 |
54 |
55 | popover内容
56 |
57 |
58 | click点我
59 |
60 |
61 |
62 |
63 | popover内容
64 |
65 |
66 | click点我
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/slides-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 1
6 |
7 |
8 | 2
9 |
10 |
11 | 3
12 |
13 |
14 |
15 |
16 |
17 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/table-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
基础用法
4 |
5 |
8 |
9 |
排序
10 |
11 |
15 |
16 |
复选框
17 |
18 |
23 |
24 |
loading
25 |
{this.isLoading = !this.isLoading}">Loading
26 |
27 |
31 |
32 |
固定表头
33 |
34 |
39 |
40 |
41 |
42 |
102 |
110 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/tabs-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
通过selected设置默认选项,disabled设置禁用选项, 默认方向为horizontal
4 |
5 |
6 | 选项一
7 | 选项二
8 | 选项三
9 |
10 |
11 | 第一个选项内容
12 | 第二个选项内容
13 | 第三个选项内容
14 |
15 |
16 |
17 | vertical方向
18 |
19 |
20 | 选项一
21 | 选项二
22 | 选项三
23 |
24 |
25 | 第一个选项内容
26 | 第二个选项内容
27 | 第三个选项内容
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/toast-demos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
autoClose属性控制是否自动关闭
4 | 默认
5 | closeButton属性控制自定义关闭
6 | 可关闭
7 | enableHtml属性控制是否转义html
8 | 展示html
9 | position属性控制位置(top,middle,bottom)
10 | 居中
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/.vuepress/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: 'GoUI',
3 | base: '/vueComponents/',
4 | description: '一些自己写的UI组件',
5 | themeConfig: {
6 | sidebarDepth: 0,// 禁用所有链接
7 | nav: [
8 | {text: '主页', link: '/'},
9 | {text: '博客', link: 'https://www.chenxiaolani.com/'},
10 | {text: 'Github', link: 'https://github.com/mywebc/vueComponents'},
11 | ],
12 | sidebar: [
13 | '/get-started/',
14 | // {
15 | // title: '介绍',
16 | // children: [
17 | // '/install/',
18 | // // '/get-started/'
19 | // ]
20 | // },
21 | {
22 | title: '组件',
23 | collapsable: false,
24 | children: [
25 | {
26 | title: "基础",
27 | collapsable: false,
28 | children: [
29 | '/components/icon',
30 | '/components/button'
31 | ],
32 | },
33 | {
34 | title: "布局",
35 | collapsable: false,
36 | children: [
37 | '/components/grid',
38 | '/components/layout',
39 | ]
40 | },
41 | {
42 | title: "导航",
43 | collapsable: false,
44 | children: [
45 | '/components/nav',
46 | '/components/pager',
47 | '/components/slides',
48 | '/components/tabs',
49 | '/components/collapse',
50 | ]
51 | },
52 | {
53 | title: "提示",
54 | collapsable: false,
55 | children: [
56 | '/components/popover',
57 | '/components/toast',
58 | ]
59 | },
60 | {
61 | title: "数据",
62 | collapsable: false,
63 | children: [
64 | '/components/input',
65 | '/components/table',
66 | '/components/cascader',
67 | ]
68 | }
69 |
70 | ]
71 | }
72 | ]
73 | }
74 | }
--------------------------------------------------------------------------------
/docs/.vuepress/styles/palette.styl:
--------------------------------------------------------------------------------
1 |
2 | $accentColor = #1fbcb6//默认主题颜色
3 | $textColor = #2c3e50//默认字体颜色 #02717d
4 | $borderColor = #eaecef//默认边框颜色
5 | $codeBgColor = #282c34 //默认背景颜色
6 |
7 | //$accentColor = #3eaf7c
8 | //$textColor = #2c3e50
9 | //$borderColor = #eaecef
10 | //$codeBgColor = #282c34
11 | . sidebar-group .sidebar-heading {
12 | opacity:1;
13 | font-weight 700;
14 | }
15 |
16 | .sidebar-links .sidebar-group-items li .active{
17 | background: #1ca9a430
18 | }
19 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ### GoUI
2 | #### 一套基于Vue.js2.5的ui组件库
3 |
--------------------------------------------------------------------------------
/docs/components/button.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Button - 按钮
3 | ---
4 |
5 | ## Button-按钮
6 |
7 | ### 示例
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 | Button
16 | Button
17 | Button
18 | Button
19 |
20 | ```
21 |
22 | ### Attributes
23 | | 参数 | 说明 | 类型 | 默认值 |
24 | | ------ | ------ | ------ | ------ |
25 | | icon | 可设置icon | String | 无 |
26 | | icon-position | icon位置 | String | left [right]|
27 | | loading | 是否loading | Boolean | false |
28 | | disabled | 是否禁用 | Boolean | false |
--------------------------------------------------------------------------------
/docs/components/cascader.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cascader - Cascader
3 | ---
4 |
5 | ## Cascader-Cascader
6 |
7 | ### 示例
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
20 |
21 | ```
22 |
23 | ### Attributes
24 | | 参数 | 说明 | 类型 | 默认值 |
25 | | ------ | ------ | ------ | ------ |
26 | | source | 数据源 | Array | [] |
27 | | popover-height | 下拉高度 | String | 无|
28 | | selected | 默认选中值 | Array | [] |
29 | | load-data | 加载函数 | Function | 无 |
--------------------------------------------------------------------------------
/docs/components/collapse.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Collapse - 手风琴
3 | ---
4 |
5 | ## Collapse-手风琴
6 | ### 示例
7 |
8 |
9 |
10 |
11 | ### 代码
12 | ```HTML
13 |
14 | 内容1
15 | 内容2
16 | 内容3
17 |
18 |
19 | 手风琴模式
20 |
21 | 内容1
22 | 内容2
23 | 内容3
24 |
25 | ```
26 |
27 | ### Attributes
28 | | 参数 | 说明 | 类型 | 默认值 |
29 | | ------ | ------ | ------ | ------ |
30 | | selected | 默认选中块 | Array | 无 |
31 | | single | 是否为手风琴模式 | Boolean | false |
32 |
--------------------------------------------------------------------------------
/docs/components/grid.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Grid - 网格
3 | ---
4 |
5 | ## Grid-网格
6 | ### 示例
7 |
8 |
9 |
10 |
11 | ### 代码
12 | ```HTML
13 |
14 | 等分
15 | 等分
16 |
17 |
18 | 右对齐
19 | 右对齐
20 |
21 |
22 | 间隙
23 | 间隙
24 |
25 |
26 | 偏移
27 | 偏移
28 |
29 | ```
30 | ### g-row Attributes
31 | | 参数 | 说明 | 类型 | 默认值 |
32 | | ------ | ------ | ------ | ------ |
33 | | align | 栅格对齐方式 | String | [left right center] |
34 | | gutter | 栅格间隔 | String,Number | 无|
35 |
36 |
37 | ### g-col Attributes
38 | | 参数 | 说明 | 类型 | 默认值 |
39 | | ------ | ------ | ------ | ------ |
40 | | span | 栅格占比 | String,Number | 无 |
41 | | offset | 栅格偏移差 | String,Number | 无|
42 |
--------------------------------------------------------------------------------
/docs/components/icon.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Icon - 图标
3 | ---
4 |
5 | ## Icon-图标
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ```
22 |
23 | ### Attributes
24 | | 参数 | 说明 | 类型 | 默认值 |
25 | | ------ | ------ | ------ | ------ |
26 | | name | icon名称 | String | 无|
27 |
--------------------------------------------------------------------------------
/docs/components/input.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Input - 输入框
3 | ---
4 |
5 | ## Input-输入框
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
16 |
17 |
18 |
19 |
20 | ```
21 |
22 | ### Attributes
23 | | 参数 | 说明 | 类型 | 默认值 |
24 | | ------ | ------ | ------ | ------ |
25 | | value | 输入框默认值 | String | 无|
26 | | disabled | 是否禁用 | Boolean | false |
27 | | readonly | 是否只读 | Boolean | false |
28 | | error | 提示信息 | String | 无 |
--------------------------------------------------------------------------------
/docs/components/layout.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Layout - 布局
3 | ---
4 |
5 | ## Layout-布局
6 | ## 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
16 | content
17 |
18 |
19 |
20 |
21 |
22 |
23 | sider
24 | content
25 |
26 |
27 |
28 |
29 |
30 | sider
31 |
32 |
33 | content
34 |
35 |
36 |
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/components/nav.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Nav - Nav
3 | ---
4 |
5 | ## Nav-Nav
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
16 | 首页
17 |
18 | 关于
19 | 企业文化
20 | 开发团队
21 |
22 | 联系方式
23 | 微信
24 | QQ
25 |
26 | 手机
27 | 移动
28 | 联通
29 | 电信
30 |
31 |
32 |
33 | 招聘
34 |
35 |
36 |
37 | 首页
38 |
39 |
40 | 关于
41 | 企业文化
42 | 开发团队
43 |
44 | 联系方式
45 | 微信
46 | QQ
47 |
48 | 手机
49 | 移动
50 | 联通
51 | 电信
52 |
53 |
54 |
55 | 招聘
56 |
57 |
58 | ```
59 |
60 | ### Attributes
61 | | 参数 | 说明 | 类型 | 默认值 |
62 | | ------ | ------ | ------ | ------ |
63 | | selected | 默认展示nav | String | 无|
64 | | vertical | nav方向是否vertical | Boolean | false |
65 |
--------------------------------------------------------------------------------
/docs/components/pager.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pager - 页码
3 | ---
4 |
5 | ## Pager - 页码
6 | ### 示例
7 |
8 |
9 |
10 |
11 | ### 代码
12 | ```HTML
13 |
14 | ```
15 |
16 |
17 |
18 |
19 | ### Attributes
20 | | 参数 | 说明 | 类型 | 默认值 |
21 | | ------ | ------ | ------ | ------ |
22 | | totalPage | 总条数(必填) | Number | 无|
23 | | currentPage | 当前页数(必填) | Number | 无 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/components/popover.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Popover - 弹出层
3 | ---
4 |
5 | ## Popover-弹出层
6 | ### 示例
7 |
8 |
9 |
10 |
11 | ### 代码
12 | ```HTML
13 |
14 |
15 | popover内容
16 |
17 |
18 | hover点我
19 |
20 |
21 |
22 |
23 |
24 | popover内容
25 |
26 |
27 | click点我
28 |
29 |
30 | ```
31 |
32 |
33 |
34 |
35 | ### Attributes
36 | | 参数 | 说明 | 类型 | 默认值 |
37 | | ------ | ------ | ------ | ------ |
38 | | trigger | 触发方式 | String | click[hover]|
39 | | position | 触发方位 | String | top[left bottom right] |
40 |
--------------------------------------------------------------------------------
/docs/components/slides.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Slides - Slides
3 | ---
4 |
5 | ## Slides-Slides
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
16 |
17 | 1
18 |
19 |
20 | 2
21 |
22 |
23 | 3
24 |
25 |
26 |
27 | ```
28 |
29 | ### Attributes
30 | | 参数 | 说明 | 类型 | 默认值 |
31 | | ------ | ------ | ------ | ------ |
32 | | selected | 默认展示第几个,name值 | String | 第一个 |
33 | | autoPlay | 是否自动播放 | Boolean | true |
34 |
--------------------------------------------------------------------------------
/docs/components/table.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Table - Table
3 | ---
4 |
5 | ## Table-Table
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 |
15 |
基础用法
16 |
17 |
20 |
21 |
排序
22 |
23 |
27 |
28 |
复选框
29 |
30 |
35 |
36 |
loading
37 |
{this.isLoading = !this.isLoading}">Loading
38 |
39 |
43 |
44 |
固定表头
45 |
46 |
51 |
52 |
53 | ```
54 |
55 | ### Attributes
56 | | 参数 | 说明 | 类型 | 默认值 |
57 | | ------ | ------ | ------ | ------ |
58 | | height | 表格高度 | Number | 无|
59 | | columns | 表头字段(必填,必须指定宽度)| Array | 无 |
60 | | dataSource | 表格数据 | Array | 无 |
61 | | order-by| 是否排序 | Boolean | false|
62 | | checkable | 是否需要复选框 | Boolean | false |
63 | | loading | 是否显示加载loading | Boolean | false|
64 | | fixed-header | 是否固定表头 | Boolean | false |
65 |
--------------------------------------------------------------------------------
/docs/components/tabs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Tabs - 选项卡
3 | ---
4 |
5 | # 选项卡
6 | ## 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 | 通过selected设置默认选项,disabled设置禁用选项, 默认方向为horizontal
15 |
16 |
17 | 选项一
18 | 选项二
19 | 选项三
20 |
21 |
22 | 第一个选项内容
23 | 第二个选项内容
24 | 第三个选项内容
25 |
26 |
27 |
28 | vertical方向
29 |
30 |
31 | 选项一
32 | 选项二
33 | 选项三
34 |
35 |
36 | 第一个选项内容
37 | 第二个选项内容
38 | 第三个选项内容
39 |
40 |
41 | ```
42 |
43 | ### Attributes
44 | | 参数 | 说明 | 类型 | 默认值 |
45 | | ------ | ------ | ------ | ------ |
46 | | selected | 默认选中块(必填) | String | 无 |
47 | | direction | tab方向 | String | horizontal[vertical] |
--------------------------------------------------------------------------------
/docs/components/toast.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Toast - Toast
3 | ---
4 |
5 | ## Toast-toast
6 | ### 示例
7 |
8 |
9 |
10 |
11 |
12 | ### 代码
13 | ```HTML
14 | autoClose属性控制是否自动关闭
15 | 默认
16 |
17 | closeButton属性控制自定义关闭
18 | 可关闭
19 |
20 | enableHtml属性控制是否转义html
21 | 展示html
22 |
23 | position属性控制位置(top,middle,bottom)
24 | 居中
25 | ```
26 | ```js
27 | showToast() {
28 | this.$toast('这是一段默认2秒自动关闭的提示', {
29 | autoClose: 2
30 | })
31 | },
32 | showToast2() {
33 | this.$toast('这是一段手动关闭的提示', {
34 | autoClose: false,
35 | closeButton: {
36 | text: '关闭文字',
37 | callback() {
38 | console.log('关闭成功')
39 | }
40 | }
41 | })
42 | },
43 | showToast3() {
44 | this.$toast('这是一个h3标题
', {
45 | enableHtml: true,
46 | autoClose: 2,
47 | })
48 | },
49 | showToast4() {
50 | this.$toast('这是一条居中提示', {
51 | autoClose: 2,
52 | position: 'middle'
53 | })
54 | }
55 | }
56 | ```
57 |
58 |
59 |
60 |
61 | ### Attributes
62 | | 参数 | 说明 | 类型 | 默认值 |
63 | | ------ | ------ | ------ | ------ |
64 | | autoClose | 是否自动关闭,若为number值,则为关闭时间 | String, Number | true |
65 | | closeButton | 是否有关闭按钮,可自定义关闭文字和回调 | Object | 关闭(按钮文字) |
66 | | enableHtml |是否允许插入html|Boolean|false|
67 | | position | toasti显示位置 | String | top[middle bottom]
68 |
69 |
--------------------------------------------------------------------------------
/docs/get-started/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 介绍
3 | ---
4 | ## 介绍
5 | 此项目为巩固vue用法和深入理解组件化而开发。
6 |
7 | ## 项目特点
8 | * 项目参考了ElementUI,AntdDesign等UI库的UI设计以及API设计;
9 | * 深入使用了Vue,如依赖注入,.sync,单向数据流等;
10 | * 未完待更新...;
11 |
--------------------------------------------------------------------------------
/docs/install/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 安装
3 | ---
4 |
5 | # 安装
--------------------------------------------------------------------------------
/karma.config.js:
--------------------------------------------------------------------------------
1 | var webpackConfig = require("@vue/cli-service/webpack.config.js");
2 | const path = require("path");
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | frameworks: ["mocha"],
7 |
8 | files: ["tests/**/*.spec.js"],
9 |
10 | preprocessors: {
11 | "**/*.spec.js": ["webpack", "sourcemap"]
12 | },
13 |
14 | webpack: webpackConfig,
15 |
16 | reporters: ["spec", "coverage"],
17 | coverageReporter: {
18 | dir: "./coverage",
19 | reporters: [{ type: "lcov", subdir: "." }, { type: "text-summary" }]
20 | },
21 | autoWatch: true,
22 |
23 | browsers: ["ChromeHeadless"]
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test-vue-1",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "test": "karma start --single-run",
9 | "docs:dev": "vuepress dev docs",
10 | "docs:build": "vuepress build docs",
11 | "test:unit": "karma start",
12 | "test:unit:old": "vue-cli-service test:unit"
13 | },
14 | "dependencies": {
15 | "core-js": "^2.6.5",
16 | "vue": "^2.6.10"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-babel": "^3.0.1",
20 | "@vue/cli-plugin-unit-mocha": "^3.0.1",
21 | "@vue/cli-service": "^3.0.1",
22 | "@vue/test-utils": "1.0.0-beta.29",
23 | "chai": "^4.2.0",
24 | "karma": "^4.2.0",
25 | "karma-chrome-launcher": "^3.1.0",
26 | "karma-mocha": "^1.3.0",
27 | "karma-sourcemap-loader": "^0.3.7",
28 | "karma-spec-reporter": "^0.0.32",
29 | "karma-webpack": "^4.0.2",
30 | "node-sass": "^4.9.0",
31 | "sass-loader": "^7.1.0",
32 | "sinon": "^7.4.1",
33 | "sinon-chai": "^3.3.0",
34 | "vue-template-compiler": "^2.6.10",
35 | "vuepress": "^1.0.3"
36 | },
37 | "postcss": {
38 | "plugins": {
39 | "autoprefixer": {}
40 | }
41 | },
42 | "browserslist": [
43 | "> 1%",
44 | "last 2 versions"
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Button from "./button/button";
3 | import Icon from "./icon";
4 | import ButtonGroup from "./button/button-group";
5 | import Input from "./input/input";
6 | import Row from "./grid/row";
7 | import Col from "./grid/col";
8 | import Layout from "./layout/layout";
9 | import Content from "./layout/content";
10 | import Header from "./layout/header";
11 | import Footer from "./layout/footer";
12 | import Sider from "./layout/sider";
13 |
14 | import plugin from "./plugin";
15 |
16 | import Tabs from "./tabs/tabs";
17 | import TabsHead from "./tabs/tabs-head";
18 | import TabsBody from "./tabs/tabs-body";
19 | import TabsItem from "./tabs/tabs-item";
20 | import TabsPane from "./tabs/tabs-pane";
21 |
22 | import Popover from "./popover/popover";
23 | import Collapse from "./collapse/collapse";
24 | import CollapseItem from "./collapse/collapse-item";
25 | import Cascader from "./cascader/cascader";
26 |
27 | Vue.component("g-button", Button);
28 | Vue.component("g-button-group", ButtonGroup);
29 | Vue.component("g-cascader", Cascader);
30 | Vue.component("g-col", Col);
31 | Vue.component("g-collapse", Collapse);
32 | Vue.component("g-collapse-item", CollapseItem);
33 | Vue.component("g-content", Content);
34 | Vue.component("g-footer", Footer);
35 | Vue.component("g-header", Header);
36 | Vue.component("g-icon", Icon);
37 | Vue.component("g-input", Input);
38 | Vue.component("g-layout", Layout);
39 | Vue.component("g-popover", Popover);
40 | Vue.component("g-row", Row);
41 | Vue.component("g-sider", Sider);
42 | Vue.component("g-tabs", Tabs);
43 | Vue.component("g-tabs-body", TabsBody);
44 | Vue.component("g-tabs-head", TabsHead);
45 | Vue.component("g-tabs-item", TabsItem);
46 | Vue.component("g-tabs-pane", TabsPane);
47 | Vue.use(plugin);
48 |
49 | new Vue({
50 | el: "#app",
51 | data: {
52 | selectedTab: "first",
53 | source: [
54 | {
55 | name: "江苏省",
56 | children: [
57 | {
58 | name: "南通市",
59 | children: [{ name: "开发区" }, { name: "崇川区" }]
60 | },
61 | {
62 | name: "宿迁市",
63 | children: [{ name: "宿迁区" }]
64 | }
65 | ]
66 | },
67 | {
68 | name: "浙江省",
69 | children: [
70 | {
71 | name: "湖州市",
72 | children: [{ name: "湖州区" }, { name: "湖州2区" }]
73 | },
74 | {
75 | name: "杭州市",
76 | children: [{ name: "杭州一区" }, { name: "杭州二区" }]
77 | }
78 | ]
79 | }
80 | ]
81 | },
82 | methods: {
83 | yyy(data) {
84 | console.log(data);
85 | },
86 | showToast() {
87 | this.$toast("加油", {
88 | enableHtml: true,
89 | position: "top",
90 | autoClose: false
91 | });
92 | },
93 | showToast2() {
94 | this.$toast("加油", {
95 | enableHtml: true,
96 | position: "middle",
97 | autoClose: false
98 | });
99 | },
100 | showToast3() {
101 | this.$toast("加油", {
102 | enableHtml: true,
103 | position: "bottom",
104 | autoClose: 2
105 | });
106 | }
107 | }
108 | });
109 |
--------------------------------------------------------------------------------
/src/button/button-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 |
--------------------------------------------------------------------------------
/src/button/button.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
43 |
44 |
95 |
--------------------------------------------------------------------------------
/src/cascader/cascader-items.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ item.name }}
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
31 |
32 |
33 |
34 |
35 |
97 |
98 |
139 |
--------------------------------------------------------------------------------
/src/cascader/cascader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ result || " " }}
5 |
6 |
7 |
16 |
17 |
18 |
19 |
20 |
122 |
123 |
150 |
--------------------------------------------------------------------------------
/src/cascader/demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
52 |
--------------------------------------------------------------------------------
/src/click-outside.js:
--------------------------------------------------------------------------------
1 | let onClickDocument = e => {
2 | let { target } = e;
3 | callbacks.forEach(item => {
4 | if (target === item.el || item.el.contains(target)) {
5 | return;
6 | } else {
7 | item.callback();
8 | }
9 | });
10 | };
11 | document.addEventListener("click", onClickDocument);
12 | let callbacks = [];
13 | export default {
14 | bind: function(el, binding, vnode) {
15 | callbacks.push({ el, callback: binding.value });
16 | }
17 | };
18 |
19 | let removeListener = () => {
20 | document.removeEventListener("click", onClickDocument);
21 | };
22 |
23 | export { removeListener };
24 |
--------------------------------------------------------------------------------
/src/collapse/collapse-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{title}}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
51 |
52 |
--------------------------------------------------------------------------------
/src/collapse/collapse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
53 |
54 |
--------------------------------------------------------------------------------
/src/demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 首页
8 |
9 | 关于
12 | 企业文化
13 | 开发团队
14 |
15 | 联系方式
18 | 微信
19 | QQ
20 |
21 |
22 | 手机
25 | 联通
26 | 移动
27 |
28 |
29 |
30 | 招聘
31 |
32 |
你好,我是中文
33 |
38 | 首页
39 |
40 | 关于
43 | 企业文化
44 | 开发团队
45 |
46 | 联系方式
49 | 微信
50 | QQ
51 |
52 |
53 | 手机
56 | 联通
57 | 移动
58 |
59 |
60 |
61 | 招聘
62 |
63 |
64 |
65 |
78 |
85 |
--------------------------------------------------------------------------------
/src/grid/col.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
90 |
91 |
--------------------------------------------------------------------------------
/src/grid/row.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
42 |
43 |
--------------------------------------------------------------------------------
/src/icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/src/icon/icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/src/input/input.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 | {{ error }}
16 |
17 |
18 |
19 |
20 |
43 |
44 |
84 |
--------------------------------------------------------------------------------
/src/layout/content.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/layout/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/layout/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/layout/layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
27 |
--------------------------------------------------------------------------------
/src/layout/sider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | // import Demo from "./demo.vue";
3 | // import PagerDemo from "./pager/demo";
4 | // import TableDemo from "./table/demo";
5 | import CascaderDemo from './cascader/demo'
6 |
7 | Vue.config.productionTip = false;
8 |
9 | new Vue({
10 | render: h => h(CascaderDemo)
11 | }).$mount("#app");
12 |
--------------------------------------------------------------------------------
/src/nav/nav-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
34 |
35 |
68 |
--------------------------------------------------------------------------------
/src/nav/nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
75 |
76 |
90 |
--------------------------------------------------------------------------------
/src/nav/sub-nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
99 |
100 |
181 |
--------------------------------------------------------------------------------
/src/pager/demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/pager/pager.vue:
--------------------------------------------------------------------------------
1 |
2 |
33 |
34 |
97 |
157 |
--------------------------------------------------------------------------------
/src/plugin.js:
--------------------------------------------------------------------------------
1 | import Toast from './toast/toast'
2 |
3 |
4 | // 提取函数
5 | function createToast({Vue, message, propsData}) {
6 | // 生成一个toast组件放到body里面
7 | let Construstor = Vue.extend(Toast)
8 | let toast = new Construstor({propsData})
9 | // 把信息给到插槽
10 | toast.$slots.default = [message]
11 | toast.$mount()
12 | document.body.appendChild(toast.$el)
13 | return toast
14 | }
15 | // 设置标记变量
16 | let currentToast
17 | export default {
18 | install (Vue, options) {
19 | Vue.prototype.$toast = function (message, toastOptions) {
20 | // 如果存在,把之前的销毁
21 | if (currentToast) {
22 | currentToast.close()
23 | }
24 | currentToast = createToast({Vue, message, propsData: toastOptions})
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/popover/popover.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
142 |
143 |
243 |
--------------------------------------------------------------------------------
/src/slides/slides-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
44 |
45 |
72 |
--------------------------------------------------------------------------------
/src/slides/slides.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
15 |
16 |
17 |
18 | {{ n }}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
177 |
178 |
216 |
--------------------------------------------------------------------------------
/src/svg.js:
--------------------------------------------------------------------------------
1 | !function (s) {
2 | var script = document.getElementsByTagName("script");
3 | if (!script || Object.keys(script).length === 0) {
4 | return;
5 | }
6 | var t,
7 | e = '',
8 | c = (t = document.getElementsByTagName("script"))[t.length - 1].getAttribute("data-injectcss");
9 | if (c && !s.__iconfont__svg__cssinject__) {
10 | s.__iconfont__svg__cssinject__ = !0;
11 | try {
12 | document.write("")
13 | } catch (t) {
14 | console && console.log(t)
15 | }
16 | }
17 | !function (t) {
18 | if (document.addEventListener) if (~["complete", "loaded", "interactive"].indexOf(document.readyState)) setTimeout(t, 0); else {
19 | var c = function () {
20 | document.removeEventListener("DOMContentLoaded", c, !1), t()
21 | };
22 | document.addEventListener("DOMContentLoaded", c, !1)
23 | } else document.attachEvent && (o = t, l = s.document, i = !1, (a = function () {
24 | try {
25 | l.documentElement.doScroll("left")
26 | } catch (t) {
27 | return void setTimeout(a, 50)
28 | }
29 | e()
30 | })(), l.onreadystatechange = function () {
31 | "complete" == l.readyState && (l.onreadystatechange = null, e())
32 | });
33 |
34 | function e() {
35 | i || (i = !0, o())
36 | }
37 |
38 | var o, l, i, a
39 | }(function () {
40 | var t, c;
41 | (t = document.createElement("div")).innerHTML = e, e = null, (c = t.getElementsByTagName("svg")[0]) && (c.setAttribute("aria-hidden", "true"), c.style.position = "absolute", c.style.width = 0, c.style.height = 0, c.style.overflow = "hidden", function (t, c) {
42 | c.firstChild ? function (t, c) {
43 | c.parentNode.insertBefore(t, c)
44 | }(t, c.firstChild) : c.appendChild(t)
45 | }(c, document.body))
46 | })
47 | }(window);
--------------------------------------------------------------------------------
/src/table/demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
58 |
66 |
--------------------------------------------------------------------------------
/src/table/table.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
203 |
--------------------------------------------------------------------------------
/src/tabs/tabs-body.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/src/tabs/tabs-head.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
34 |
35 |
--------------------------------------------------------------------------------
/src/tabs/tabs-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
50 |
--------------------------------------------------------------------------------
/src/tabs/tabs-pane.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
38 |
39 |
--------------------------------------------------------------------------------
/src/tabs/tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
60 |
61 |
--------------------------------------------------------------------------------
/src/toast/toast.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 | {{closeButton.text}}
11 |
12 |
13 |
14 |
15 |
16 |
85 |
86 |
158 |
--------------------------------------------------------------------------------
/src/validate.js:
--------------------------------------------------------------------------------
1 | class Validator {
2 | // 自行添加
3 | static add(name, fn) {
4 | Validator.prototype[name] = fn;
5 | }
6 |
7 | constructor() {}
8 | validate(data, rules) {
9 | let errors = {};
10 | rules.forEach(rule => {
11 | let value = data[rule.key];
12 | if (rule.required) {
13 | let error = this.required(value);
14 | if (error) {
15 | ensureObject(errors, rule.key);
16 | errors[rule.key].required = error;
17 | return;
18 | }
19 | }
20 | let validators = Object.keys(rule).filter(
21 | key => key !== "key" && key !== "required"
22 | );
23 | validators.forEach(validatorKey => {
24 | if (this[validatorKey]) {
25 | let error = this[validatorKey](value, rule[validatorKey]);
26 | if (error) {
27 | ensureObject(errors, rule.key);
28 | errors[rule.key][validatorKey] = error;
29 | }
30 | } else {
31 | throw `不存在的校验器: ${validatorKey}`;
32 | }
33 | });
34 | });
35 | return errors;
36 | }
37 |
38 | required(value) {
39 | if (value !== 0 && !value) {
40 | return "必填";
41 | }
42 | }
43 |
44 | pattern(value, pattern) {
45 | if (pattern === "email") {
46 | pattern = /^.+@.+$/;
47 | }
48 | if (pattern.test(value) === false) {
49 | return "格式不正确";
50 | }
51 | }
52 |
53 | minLength(value, minLength) {
54 | if (value.length < minLength) {
55 | return "太短";
56 | }
57 | }
58 |
59 | maxLength(value, maxLength) {
60 | if (value.length > maxLength) {
61 | return "太长";
62 | }
63 | }
64 | }
65 |
66 | function ensureObject(obj, key) {
67 | if (typeof obj[key] !== "object") {
68 | obj[key] = {};
69 | }
70 | }
71 |
72 | export default Validator;
73 |
--------------------------------------------------------------------------------
/styles/var.scss:
--------------------------------------------------------------------------------
1 | $border-color-hover: #666;
2 | $border-color: #999;
3 | $border-color-light: lighten($border-color, 30%);
4 | $border-radius: 4px;
5 | $box-shadow-color: rgba(0, 0, 0, 0.5);
6 | $button-active-bg: #eee;
7 | $button-bg: white;
8 | $button-height: 32px;
9 | $color: #333;
10 | $light-color: #666;
11 | $font-size: 14px;
12 | $small-font-size: 12px;
13 | $input-height: 32px;
14 | $red: #f1453d;
15 | $grey: #eee;
16 | $blue: #4a90e2;
17 | .box-shadow {
18 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
19 | }
20 | @keyframes spin {
21 | 0% {
22 | transform: rotate(0deg);
23 | }
24 | 100% {
25 | transform: rotate(360deg);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/unit/button.spec.js:
--------------------------------------------------------------------------------
1 | import chai, { expect } from "chai";
2 | import sinon from "sinon";
3 | import sinonChai from "sinon-chai";
4 | import { shallowMount, mount } from "@vue/test-utils";
5 | import Button from "../../src/button/button.vue";
6 | chai.use(sinonChai);
7 |
8 | describe("Button.vue", () => {
9 | it("存在.", () => {
10 | expect(Button).to.exist;
11 | });
12 | it("可以设置icon.", () => {
13 | const wrapper = mount(Button, {
14 | propsData: {
15 | icon: "settings"
16 | }
17 | });
18 | const useElement = wrapper.find("use");
19 | expect(useElement.attributes()["href"]).to.equal("#i-settings");
20 | });
21 | it("可以设置loading.", () => {
22 | const wrapper = mount(Button, {
23 | propsData: {
24 | icon: "settings",
25 | loading: true
26 | }
27 | });
28 | const vm = wrapper.vm;
29 | const useElements = vm.$el.querySelectorAll("use");
30 | expect(useElements.length).to.equal(1);
31 | expect(useElements[0].getAttribute("xlink:href")).to.equal("#i-loading");
32 | });
33 |
34 | xit("icon 默认的 order 是 1", () => {
35 | const wrapper = mount(Button, {
36 | propsData: {
37 | icon: "settings"
38 | }
39 | });
40 | const vm = wrapper.vm;
41 | const icon = vm.$el.querySelector("svg");
42 | expect(getComputedStyle(icon).order).to.eq("1");
43 | });
44 |
45 | xit("设置 iconPosition 可以改变 order", () => {
46 | const wrapper = mount(Butotn, {
47 | propsData: {
48 | icon: "settings",
49 | iconPosition: "right"
50 | }
51 | });
52 | const vm = wrapper.vm;
53 | const icon = vm.$el.querySelector("svg");
54 | expect(getComputedStyle(icon).order).to.eq("2");
55 | });
56 | it("点击 button 触发 click 事件", () => {
57 | const wrapper = mount(Button, {
58 | propsData: {
59 | icon: "settings"
60 | }
61 | });
62 | const vm = wrapper.vm;
63 |
64 | const callback = sinon.fake();
65 | vm.$on("click", callback);
66 | vm.$el.click();
67 | expect(callback).to.have.been.called;
68 | });
69 | });
70 |
--------------------------------------------------------------------------------
/tests/unit/button.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Button from '../../src/button/button'
4 |
5 | Vue.config.productionTip = false
6 | Vue.config.devtools = false
7 |
8 | describe('Button', () => {
9 | it('存在.', () => {
10 | expect(Button).to.be.ok
11 | })
12 | it('可以设置icon.', () => {
13 | const Constructor = Vue.extend(Button)
14 | // 给它传一个数据
15 | const vm = new Constructor({
16 | propsData: {
17 | icon: 'settings'
18 | }
19 | }).$mount()
20 | const useElement = vm.$el.querySelector('use')
21 | // 查看这个属性,期待它等于这个值
22 | expect(useElement.getAttribute('xlink:href')).to.equal('#i-settings')
23 | vm.$destroy()
24 | })
25 | it('可以设置loading.', () => {
26 | const Constructor = Vue.extend(Button)
27 | const vm = new Constructor({
28 | propsData: {
29 | icon: 'settings',
30 | loading: true
31 | }
32 | }).$mount()
33 | const useElements = vm.$el.querySelectorAll('use')
34 | expect(useElements.length).to.equal(1)
35 | expect(useElements[0].getAttribute('xlink:href')).to.equal('#i-loading')
36 | vm.$destroy()
37 | })
38 | it('icon 默认的 order 是 1', () => {
39 | const div = document.createElement('div')
40 | document.body.appendChild(div)
41 | const Constructor = Vue.extend(Button)
42 | const vm = new Constructor({
43 | propsData: {
44 | icon: 'settings',
45 | }
46 | }).$mount(div)
47 | const icon = vm.$el.querySelector('svg')
48 | expect(getComputedStyle(icon).order).to.eq('1')
49 | vm.$el.remove()
50 | vm.$destroy()
51 | })
52 | it('设置 iconPosition 可以改变 order', () => {
53 | const div = document.createElement('div')
54 | document.body.appendChild(div)
55 | const Constructor = Vue.extend(Button)
56 | const vm = new Constructor({
57 | propsData: {
58 | icon: 'settings',
59 | iconPosition: 'right'
60 | }
61 | }).$mount(div)
62 | const icon = vm.$el.querySelector('svg')
63 | expect(getComputedStyle(icon).order).to.eq('2')
64 | vm.$el.remove()
65 | vm.$destroy()
66 | })
67 | it('点击 button 触发 click 事件', () => {
68 | const Constructor = Vue.extend(Button)
69 | const vm = new Constructor({
70 | propsData: {
71 | icon: 'settings',
72 | }
73 | }).$mount()
74 | const callback = sinon.fake();
75 | vm.$on('click', callback)
76 | // 找到这个元素,调用它的点击事件
77 | vm.$el.click()
78 | // 期待回调
79 | expect(callback).to.have.been.called
80 | })
81 | })
82 |
--------------------------------------------------------------------------------
/tests/unit/col.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Row from '../../src/grid/row'
4 | import Col from '../../src/grid/col'
5 |
6 |
7 | Vue.config.productionTip = false
8 | Vue.config.devtools = false
9 |
10 | describe('Col', () => {
11 | it('存在.', () => {
12 | expect(Col).to.be.ok
13 | })
14 | it('接受span属性', () => {
15 | // 必须放到页面上
16 | const div = document.createElement('div')
17 | document.body.appendChild(div)
18 | const Constructor = Vue.extend(Col)
19 | const vm = new Constructor({
20 | propsData: {
21 | span: 1
22 | }
23 | }).$mount(div)
24 | // console.log(vm.$el)
25 | expect(vm.$el.classList.contains('col-1')).to.eq(true)
26 | div.remove()
27 | vm.$destroy()
28 | })
29 | it('接受offset属性', () => {
30 | const div = document.createElement('div')
31 | document.body.appendChild(div)
32 | const Constructor = Vue.extend(Col)
33 | const vm = new Constructor({
34 | propsData: {
35 | offset: 1
36 | }
37 | }).$mount(div)
38 | console.log(vm.$el)
39 | expect(vm.$el.classList.contains('offset-1')).to.eq(true)
40 | div.remove()
41 | vm.$destroy()
42 | })
43 | it('接受ipad属性', () => {
44 | const div = document.createElement('div')
45 | document.body.appendChild(div)
46 | const Constructor = Vue.extend(Col)
47 | const vm = new Constructor({
48 | propsData: {
49 | ipad: {span: 1, offset: 2}
50 | }
51 | }).$mount(div)
52 | console.log(vm.$el)
53 | expect(vm.$el.classList.contains('col-ipad-1')).to.eq(true)
54 | expect(vm.$el.classList.contains('offset-ipad-2')).to.eq(true)
55 | div.remove()
56 | vm.$destroy()
57 | })
58 | it('接受narrowPc属性', () => {
59 | const div = document.createElement('div')
60 | document.body.appendChild(div)
61 | const Constructor = Vue.extend(Col)
62 | const vm = new Constructor({
63 | propsData: {
64 | narrowPc: {span: 1, offset: 2}
65 | }
66 | }).$mount(div)
67 | console.log(vm.$el)
68 | expect(vm.$el.classList.contains('col-narrow-pc-1')).to.eq(true)
69 | expect(vm.$el.classList.contains('offset-narrow-pc-2')).to.eq(true)
70 | div.remove()
71 | vm.$destroy()
72 | })
73 | it('接受pc属性', () => {
74 | const div = document.createElement('div')
75 | document.body.appendChild(div)
76 | const Constructor = Vue.extend(Col)
77 | const vm = new Constructor({
78 | propsData: {
79 | pc: {span: 1, offset: 2}
80 | }
81 | }).$mount(div)
82 | console.log(vm.$el)
83 | expect(vm.$el.classList.contains('col-pc-1')).to.eq(true)
84 | expect(vm.$el.classList.contains('offset-pc-2')).to.eq(true)
85 | div.remove()
86 | vm.$destroy()
87 | })
88 | it('接受widePc属性', () => {
89 | const div = document.createElement('div')
90 | document.body.appendChild(div)
91 | const Constructor = Vue.extend(Col)
92 | const vm = new Constructor({
93 | propsData: {
94 | widePc: {span: 1, offset: 2}
95 | }
96 | }).$mount(div)
97 | console.log(vm.$el)
98 | expect(vm.$el.classList.contains('col-wide-pc-1')).to.eq(true)
99 | expect(vm.$el.classList.contains('offset-wide-pc-2')).to.eq(true)
100 | div.remove()
101 | vm.$destroy()
102 | })
103 | })
104 |
--------------------------------------------------------------------------------
/tests/unit/input.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Input from '../../src/input/input'
4 |
5 | Vue.config.productionTip = false
6 | Vue.config.devtools = false
7 |
8 | describe('Input', () => {
9 | it('存在.', () => {
10 | expect(Input).to.be.ok
11 | })
12 | // 测试props
13 | describe('props', () => {
14 | const Constructor = Vue.extend(Input)
15 | let vm
16 | afterEach(function () {
17 | vm.$destroy()
18 | })
19 | it('可以接受value', () => {
20 | // 给它传一个数据
21 | vm = new Constructor({
22 | propsData: {
23 | value: '1234'
24 | }
25 | }).$mount()
26 | const inputElement = vm.$el.querySelector('input')
27 | // 查看这个属性,期待它等于这个值
28 | expect(inputElement.value).to.equal('1234')
29 | })
30 | it('可以接受disabled', () => {
31 | // 给它传一个数据
32 | vm = new Constructor({
33 | propsData: {
34 | disabled: true
35 | }
36 | }).$mount()
37 | const inputElement = vm.$el.querySelector('input')
38 | // 查看这个属性,期待它等于这个值
39 | expect(inputElement.disabled).to.equal(true)
40 | })
41 | it('可以接受readonly', () => {
42 | // 给它传一个数据
43 | vm = new Constructor({
44 | propsData: {
45 | readonly: true
46 | }
47 | }).$mount()
48 | const inputElement = vm.$el.querySelector('input')
49 | // 查看这个属性,期待它等于这个值
50 | expect(inputElement.readOnly).to.equal(true)
51 | })
52 | it('可以接受error', () => {
53 | // 给它传一个数据
54 | vm = new Constructor({
55 | propsData: {
56 | error: '最大值超过2'
57 | }
58 | }).$mount()
59 | const useElement = vm.$el.querySelector('use')
60 | // 查看这个属性,期待它等于这个值
61 | expect(useElement.getAttribute('xlink:href')).to.equal('#i-error')
62 | const errorMesage = vm.$el.querySelector('.error-message')
63 | // 查看这个属性,期待它等于这个值
64 | expect(errorMesage.innerText).to.equal("最大值超过2")
65 | })
66 | })
67 | // 测试input事件
68 | describe('事件', () => {
69 | const Constructor = Vue.extend(Input)
70 | let vm
71 | afterEach(function () {
72 | vm.$destroy()
73 | })
74 | it('支持change/input/focus/blur事件', () => {
75 | ['change','input','focus','blur'].forEach((eventName) => {
76 | vm = new Constructor({}).$mount()
77 | const callback = sinon.fake();
78 | vm.$on(eventName, callback)
79 | // 触发input的change事件
80 | let event = new Event(eventName)
81 | Object.defineProperty(
82 | event, 'target', {
83 | value: {value: 'hi'}, enumerable: true
84 | }
85 | )
86 | let inputElement = vm.$el.querySelector('input')
87 | inputElement.dispatchEvent(event)
88 | expect(callback).to.have.been.calledWith('hi')
89 | })
90 | })
91 | // it('支持input事件', () => {
92 | // vm = new Constructor({}).$mount()
93 | // const callback = sinon.fake();
94 | // vm.$on('input', callback)
95 | // // 触发input的change事件
96 | // let event = new Event('input')
97 | // let inputElement = vm.$el.querySelector('input')
98 | // inputElement.dispatchEvent(event)
99 | // expect(callback).to.have.been.calledWith(event)
100 | // })
101 | // it('支持focus事件', () => {
102 | // vm = new Constructor({}).$mount()
103 | // const callback = sinon.fake();
104 | // vm.$on('focus', callback)
105 | // // 触发input的change事件
106 | // let event = new Event('focus')
107 | // let inputElement = vm.$el.querySelector('input')
108 | // inputElement.dispatchEvent(event)
109 | // expect(callback).to.have.been.calledWith(event)
110 | // })
111 | // it('支持blur事件', () => {
112 | // vm = new Constructor({}).$mount()
113 | // const callback = sinon.fake();
114 | // vm.$on('blur', callback)
115 | // // 触发input的change事件
116 | // let event = new Event('blur')
117 | // let inputElement = vm.$el.querySelector('input')
118 | // inputElement.dispatchEvent(event)
119 | // expect(callback).to.have.been.calledWith(event)
120 | // })
121 | })
122 | })
123 |
--------------------------------------------------------------------------------
/tests/unit/nav.spec.js:
--------------------------------------------------------------------------------
1 | import chai, { expect } from "chai";
2 | import sinon from "sinon";
3 | import sinonChai from "sinon-chai";
4 | import { shallowMount, mount } from "@vue/test-utils";
5 | import Nav from "../../src/nav/nav";
6 | import NavItem from "../../src/nav/nav-item";
7 | import SubNav from "../../src/nav/sub-nav";
8 | import Vue from "vue";
9 |
10 | chai.use(sinonChai);
11 |
12 | describe("nav.vue", () => {
13 | it("存在.", () => {
14 | expect(Nav).to.exist;
15 | });
16 | it("支持selected属性", () => {
17 | Vue.component("g-nav-item", NavItem);
18 | Vue.component("g-sub-nav", SubNav);
19 | const wrapper = mount(Nav, {
20 | propsData: {
21 | selected: "home"
22 | },
23 | slots: {
24 | default: `
25 | 首页
26 |
27 | 关于
30 | 企业文化
31 | 开发团队
32 |
33 | 联系方式
36 | 微信
37 | QQ
38 |
39 |
40 | 手机
43 | 联通
44 | 移动
45 |
46 |
47 |
48 | 招聘`
49 | }
50 | });
51 | setTimeout(() => {
52 | expect(wrapper.find('[data-name="home"].selected').exists()).to.be.true;
53 | });
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/tests/unit/pager.spec.js:
--------------------------------------------------------------------------------
1 | import chai, {expect} from 'chai'
2 | import sinon from 'sinon'
3 | import sinonChai from 'sinon-chai'
4 | import {shallowMount, mount} from '@vue/test-utils'
5 | import Pager from '../../src/pager/pager.vue'
6 | chai.use(sinonChai)
7 |
8 | describe('Pager.vue', () => {
9 | it('存在.', () => {
10 | expect(Pager).to.exist
11 | })
12 | it('它可以设置currentPage', () => {
13 | const wrapper = mount(Pager, {
14 | propsData: {
15 | totalPage: 8,
16 | currentPage:3,
17 | }
18 | })
19 | expect(wrapper.find('[data-number="3"].current').exists()).to.be.true
20 | })
21 |
22 | it('它可以设置totalPage', () => {
23 | const wrapper = mount(Pager, {
24 | propsData: {
25 | totalPage: 8,
26 | currentPage:8,
27 | }
28 | })
29 | expect(wrapper.find('.disabled').exists()).to.be.true
30 | })
31 |
32 | it('它可以设置hide pager', () => {
33 | const wrapper = mount(Pager, {
34 | propsData: {
35 | totalPage: 1,
36 | currentPage:1,
37 | hideIfOnePage:false
38 | }
39 | })
40 | expect(wrapper.find('.g-pager')).to.be.not.true
41 | })
42 |
43 | })
--------------------------------------------------------------------------------
/tests/unit/popover.spec.js:
--------------------------------------------------------------------------------
1 | import chai, {expect} from 'chai'
2 | import sinon from 'sinon'
3 | import sinonChai from 'sinon-chai'
4 | import {shallowMount, mount} from '@vue/test-utils'
5 | import Popover from '../../src/popover/popover'
6 |
7 | chai.use(sinonChai)
8 |
9 | describe('Popover', () => {
10 |
11 | it('存在.', () => {
12 | expect(Popover).to.exist
13 | })
14 |
15 | it('可以设置position.', () => {
16 | const wrapper = mount(Popover, {
17 | slots: {
18 | default: {template: ``},
19 | content: '弹出内容
'
20 | },
21 | propsData: {
22 | position: 'bottom'
23 | }
24 | })
25 | wrapper.find('button').trigger('click')
26 | let classes = wrapper.find('.content-wrapper').classes()
27 | expect(classes).to.include('position-bottom')
28 | })
29 | it('可以设置 trigger', () => {
30 | const wrapper = mount(Popover, {
31 | slots: {
32 | default: {template: ``},
33 | content: '弹出内容
'
34 | },
35 | propsData: {
36 | position: 'bottom',
37 | trigger: 'hover'
38 | }
39 | })
40 | expect(wrapper.find('.content-wrapper').element).to.not.exist
41 | wrapper.find('.popover').trigger('mouseenter')
42 | expect(wrapper.find('.content-wrapper').element).to.exist
43 |
44 | })
45 |
46 | })
--------------------------------------------------------------------------------
/tests/unit/row.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Row from '../../src/grid/row'
4 | import Col from '../../src/grid/col'
5 |
6 |
7 | Vue.config.productionTip = false
8 | Vue.config.devtools = false
9 |
10 | describe('Row', () => {
11 | it('存在.', () => {
12 | expect(Row).to.be.ok
13 | })
14 | it('接受gutter属性', (done) => {
15 | Vue.component('g-row', Row)
16 | Vue.component('g-col', Col)
17 | const div = document.createElement('div')
18 | document.body.appendChild(div)
19 | div.innerHTML = `
20 |
21 |
22 |
23 | >
24 | `
25 | const vm = new Vue({
26 | el: div
27 | })
28 | setTimeout(() => {
29 | const row = vm.$el.querySelector('.row')
30 | expect(getComputedStyle(row).marginLeft).to.eq('-10px')
31 | expect(getComputedStyle(row).marginRight).to.eq('-10px')
32 | const cols = vm.$el.querySelectorAll('.col')
33 | expect(getComputedStyle(cols[0]).paddingRight).to.eq('10px')
34 | expect(getComputedStyle(cols[1]).paddingLeft).to.eq('10px')
35 | done()
36 | vm.$el.remove()
37 | vm.$destroy()
38 | })
39 | })
40 | it('接受align属性', () => {
41 | // 必须放到页面上
42 | const div = document.createElement('div')
43 | document.body.appendChild(div)
44 | const Constructor = Vue.extend(Row)
45 | const vm = new Constructor({
46 | propsData: {
47 | align: 'right'
48 | }
49 | }).$mount(div)
50 | const element = vm.$el
51 | expect(getComputedStyle(element).justifyContent).to.eq('flex-end')
52 | div.remove()
53 | vm.$destroy()
54 | })
55 | })
56 |
--------------------------------------------------------------------------------
/tests/unit/slides.spec.js:
--------------------------------------------------------------------------------
1 | import chai, { expect } from "chai";
2 | import sinon from "sinon";
3 | import sinonChai from "sinon-chai";
4 | import { shallowMount, mount } from "@vue/test-utils";
5 | import Slides from "../../src/slides/slides.vue";
6 | import SlidesItem from "../../src/slides/slides-item.vue";
7 | import Vue from "vue";
8 |
9 | chai.use(sinonChai);
10 |
11 | describe("Slides.vue", () => {
12 | it("存在.", () => {
13 | expect(Slides).to.exist;
14 | });
15 |
16 | it("接受 GoSlidesItem,默认展示第一个", done => {
17 | Vue.component("GSlidesItem", SlidesItem);
18 | const wrapper = mount(Slides, {
19 | propsData: {
20 | autoPlay: false
21 | },
22 | slots: {
23 | default: `
24 |
25 | 1
26 |
27 |
28 | 2
29 |
30 |
31 | 3
32 |
33 | `
34 | }
35 | });
36 | setTimeout(() => {
37 | expect(wrapper.find(".box1").exists()).to.be.true;
38 | done();
39 | });
40 | });
41 | it("selected 是几,选中的就是几", done => {
42 | Vue.component("GSlidesItem", SlidesItem);
43 | const wrapper = mount(Slides, {
44 | propsData: {
45 | autoPlay: false,
46 | selected: "2"
47 | },
48 | slots: {
49 | default: `
50 |
51 | 1
52 |
53 |
54 | 2
55 |
56 |
57 | 3
58 |
59 | `
60 | }
61 | });
62 | setTimeout(() => {
63 | expect(wrapper.find(".box2").exists()).to.be.true;
64 | done();
65 | });
66 | });
67 |
68 | it("点击第二个就展示第二个", done => {
69 | Vue.component("GSlidesItem", SlidesItem);
70 | const wrapper = mount(Slides, {
71 | propsData: {
72 | autoPlay: false,
73 | selected: "1"
74 | },
75 | slots: {
76 | default: `
77 |
78 | 1
79 |
80 |
81 | 2
82 |
83 |
84 | 3
85 |
86 | `
87 | },
88 | listeners: {
89 | "update:selected": x => {
90 | expect(x).to.eq("2");
91 | done();
92 | }
93 | }
94 | });
95 | setTimeout(() => {
96 | wrapper.find('[data-index="1"]').trigger("click");
97 | });
98 | });
99 |
100 | it("会自动播放", done => {
101 | Vue.component("GSlidesItem", SlidesItem);
102 | const callback = sinon.fake();
103 | const wrapper = mount(Slides, {
104 | propsData: {
105 | autoPlay: true,
106 | autoPlayDelay: 20,
107 | selected: "1"
108 | },
109 | slots: {
110 | default: `
111 |
112 | 1
113 |
114 |
115 | 2
116 |
117 |
118 | 3
119 |
120 | `
121 | },
122 | listeners: {
123 | "update:selected": callback
124 | }
125 | });
126 | setTimeout(() => {
127 | expect(callback).to.have.been.calledWith("2");
128 | done();
129 | }, 21);
130 | });
131 | it("可以点击上一张", done => {
132 | Vue.component("GSlidesItem", SlidesItem);
133 | const callback = sinon.fake();
134 | const wrapper = mount(Slides, {
135 | propsData: {
136 | autoPlay: true,
137 | autoPlayDelay: 20,
138 | selected: "1"
139 | },
140 | slots: {
141 | default: `
142 |
143 | 1
144 |
145 |
146 | 2
147 |
148 |
149 | 3
150 |
151 | `
152 | },
153 | listeners: {
154 | "update:selected": callback
155 | }
156 | });
157 | setTimeout(() => {
158 | wrapper.find('[data-action="prev"]').trigger("click");
159 | expect(callback).to.have.been.calledWith("3");
160 | done();
161 | }, 21);
162 | });
163 | it("可以点击下一张", done => {
164 | Vue.component("GSlidesItem", SlidesItem);
165 | const callback = sinon.fake();
166 | const wrapper = mount(Slides, {
167 | propsData: {
168 | autoPlay: true,
169 | autoPlayDelay: 20,
170 | selected: "1"
171 | },
172 | slots: {
173 | default: `
174 |
175 | 1
176 |
177 |
178 | 2
179 |
180 |
181 | 3
182 |
183 | `
184 | },
185 | listeners: {
186 | "update:selected": callback
187 | }
188 | });
189 | setTimeout(() => {
190 | wrapper.find('[data-action="next"]').trigger("click");
191 | expect(callback).to.have.been.calledWith("2");
192 | done();
193 | }, 21);
194 | });
195 | });
196 |
--------------------------------------------------------------------------------
/tests/unit/tabs-body.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Tabs from '../../src/tabs/tabs'
4 | import TabsHead from '../../src/tabs/tabs-head'
5 | import TabsBody from '../../src/tabs/tabs-body'
6 | import TabsItem from '../../src/tabs/tabs-item'
7 | import TabsPane from '../../src/tabs/tabs-pane'
8 |
9 | Vue.component('g-tabs', Tabs)
10 | Vue.component('g-tabs-head', TabsHead)
11 | Vue.component('g-tabs-body', TabsBody)
12 | Vue.component('g-tabs-item', TabsItem)
13 | Vue.component('g-tabs-pane', TabsPane)
14 |
15 | Vue.config.productionTip = false
16 | Vue.config.devtools = false
17 |
18 | describe('TabsBody', () => {
19 | it('存在.', () => {
20 | expect(TabsBody).to.exist
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/unit/tabs-head.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Tabs from '../../src/tabs/tabs'
4 | import TabsHead from '../../src/tabs/tabs-head'
5 | import TabsBody from '../../src/tabs/tabs-body'
6 | import TabsItem from '../../src/tabs/tabs-item'
7 | import TabsPane from '../../src/tabs/tabs-pane'
8 |
9 | Vue.component('g-tabs', Tabs)
10 | Vue.component('g-tabs-head', TabsHead)
11 | Vue.component('g-tabs-body', TabsBody)
12 | Vue.component('g-tabs-item', TabsItem)
13 | Vue.component('g-tabs-pane', TabsPane)
14 |
15 | Vue.config.productionTip = false
16 | Vue.config.devtools = false
17 |
18 | describe('TabsHead', () => {
19 | it('存在.', () => {
20 | expect(TabsHead).to.exist
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/unit/tabs-item.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Tabs from '../../src/tabs/tabs'
4 | import TabsHead from '../../src/tabs/tabs-head'
5 | import TabsBody from '../../src/tabs/tabs-body'
6 | import TabsItem from '../../src/tabs/tabs-item'
7 | import TabsPane from '../../src/tabs/tabs-pane'
8 |
9 | Vue.component('g-tabs', Tabs)
10 | Vue.component('g-tabs-head', TabsHead)
11 | Vue.component('g-tabs-body', TabsBody)
12 | Vue.component('g-tabs-item', TabsItem)
13 | Vue.component('g-tabs-pane', TabsPane)
14 |
15 | Vue.config.productionTip = false
16 | Vue.config.devtools = false
17 |
18 | describe('TabsItem', () => {
19 |
20 | it('存在.', () => {
21 | expect(TabsItem).to.exist
22 | })
23 |
24 | // it('接受 name 属性', () => {
25 | // const Constructor = Vue.extend(TabsItem)
26 | // const vm = new Constructor({
27 | // propsData: {
28 | // name: 'xxx',
29 | // }
30 | // }).$mount()
31 | // expect(vm.$el.getAttribute('data-name')).to.eq('xxx')
32 | // })
33 | // it('接受 disabled 属性', () => {
34 | // const Constructor = Vue.extend(TabsItem)
35 | // const vm = new Constructor({
36 | // propsData: {
37 | // disabled: true,
38 | // }
39 | // }).$mount()
40 | // expect(vm.$el.classList.contains('disabled')).to.be.true
41 | // const callback = sinon.fake();
42 | // vm.$on('click', callback)
43 | // vm.$el.click()
44 | // expect(callback).to.have.not.been.called
45 | // })
46 | })
--------------------------------------------------------------------------------
/tests/unit/tabs-pane.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Tabs from '../../src/tabs/tabs'
4 | import TabsHead from '../../src/tabs/tabs-head'
5 | import TabsBody from '../../src/tabs/tabs-body'
6 | import TabsItem from '../../src/tabs/tabs-item'
7 | import TabsPane from '../../src/tabs/tabs-pane'
8 |
9 | Vue.component('g-tabs', Tabs)
10 | Vue.component('g-tabs-head', TabsHead)
11 | Vue.component('g-tabs-body', TabsBody)
12 | Vue.component('g-tabs-item', TabsItem)
13 | Vue.component('g-tabs-pane', TabsPane)
14 |
15 | Vue.config.productionTip = false
16 | Vue.config.devtools = false
17 |
18 | describe('TabsPane', () => {
19 | it('存在.', () => {
20 | expect(TabsPane).to.exist
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/unit/tabs.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Tabs from '../../src/tabs/tabs'
4 | import TabsHead from '../../src/tabs/tabs-head'
5 | import TabsBody from '../../src/tabs/tabs-body'
6 | import TabsItem from '../../src/tabs/tabs-item'
7 | import TabsPane from '../../src/tabs/tabs-pane'
8 |
9 | Vue.component('g-tabs', Tabs)
10 | Vue.component('g-tabs-head', TabsHead)
11 | Vue.component('g-tabs-body', TabsBody)
12 | Vue.component('g-tabs-item', TabsItem)
13 | Vue.component('g-tabs-pane', TabsPane)
14 |
15 | Vue.config.productionTip = false
16 | Vue.config.devtools = false
17 |
18 | describe('Tabs', () => {
19 | it('存在.', () => {
20 | expect(Tabs).to.exist
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/unit/toast.test.js:
--------------------------------------------------------------------------------
1 | const expect = chai.expect;
2 | import Vue from 'vue'
3 | import Toast from '../../src/toast/toast'
4 |
5 | Vue.config.productionTip = false
6 | Vue.config.devtools = false
7 |
8 | describe('Toast', () => {
9 |
10 | it('存在.', () => {
11 | expect(Toast).to.exist
12 | })
13 |
14 | describe('props', function () {
15 | this.timeout(15000)
16 | it('接受 autoClose', (done) => {
17 | let div = document.createElement('div')
18 | document.body.appendChild(div)
19 | const Constructor = Vue.extend(Toast)
20 | const vm = new Constructor({
21 | propsData: {
22 | autoClose: 1,
23 | }
24 | }).$mount(div)
25 | // vm.$on('close', () => {
26 | // expect(document.body.contains(vm.$el)).to.eq(false)
27 | // done()
28 | // })
29 | setTimeout(() => {
30 | expect(document.body.contains(vm.$el)).to.eq(false)
31 | done()
32 | },2000)
33 | })
34 | it('接受 closeButton', (done) => {
35 | const callback = sinon.fake();
36 | const Constructor = Vue.extend(Toast)
37 | const vm = new Constructor({
38 | propsData: {
39 | closeButton: {
40 | text: '关闭吧',
41 | callback,
42 | },
43 | }
44 | }).$mount()
45 | let closeButton = vm.$el.querySelector('.close')
46 | expect(closeButton.textContent.trim()).to.eq('关闭吧')
47 | setTimeout(() => {
48 | closeButton.click()
49 | expect(callback).to.have.been.called
50 | done()
51 | },200)
52 | })
53 | it('接受 enableHtml', () => {
54 | const Constructor = Vue.extend(Toast)
55 | const vm = new Constructor({
56 | propsData: {enableHtml: true}
57 | })
58 | vm.$slots.default = ['hi']
59 | vm.$mount()
60 | let strong = vm.$el.querySelector('#test')
61 | expect(strong).to.exist
62 | })
63 | it('接受 position', () => {
64 | const Constructor = Vue.extend(Toast)
65 | const vm = new Constructor({
66 | propsData: {
67 | position: 'bottom'
68 | }
69 | }).$mount()
70 | expect(vm.$el.classList.contains('position-bottom')).to.eq(true)
71 | })
72 | })
73 | })
--------------------------------------------------------------------------------
/tests/unit/validate.spec.js:
--------------------------------------------------------------------------------
1 | import chai, { expect } from "chai";
2 | import sinon from "sinon";
3 | import sinonChai from "sinon-chai";
4 | import { shallowMount, mount } from "@vue/test-utils";
5 | import Validator from "../../src/validate.js";
6 |
7 | chai.use(sinonChai);
8 |
9 | describe("Validate", () => {
10 | it("存在.", () => {
11 | expect(Validator).to.exist;
12 | });
13 |
14 | it("required true 报错", () => {
15 | let data = {
16 | email: ""
17 | };
18 | let rules = [{ key: "email", required: true }];
19 | let validator = new Validator();
20 | let errors = validator.validate(data, rules);
21 | expect(errors.email.required).to.eq("必填");
22 | });
23 |
24 | it("required true 通过", () => {
25 | let data = {
26 | email: 0
27 | };
28 | let rules = [{ key: "email", required: true }];
29 | let validator = new Validator();
30 | let errors = validator.validate(data, rules);
31 | expect(errors.email).to.not.exist;
32 | });
33 |
34 | it("pattern 报错", () => {
35 | let data = {
36 | email: "@frank.com"
37 | };
38 | let rules = [{ key: "email", pattern: /^.+@.+$/ }];
39 | let validator = new Validator();
40 | let errors = validator.validate(data, rules);
41 | expect(errors.email.pattern).to.eq("格式不正确");
42 | });
43 |
44 | it("pattern 通过", () => {
45 | let data = {
46 | email: "1@frank.com"
47 | };
48 | let rules = [{ key: "email", pattern: /^.+@.+$/ }];
49 | let validator = new Validator();
50 | let errors = validator.validate(data, rules);
51 | expect(errors.email).to.not.exist;
52 | });
53 |
54 | it("pattern email 报错", () => {
55 | let data = {
56 | email: "@frank.com"
57 | };
58 | let rules = [{ key: "email", pattern: "email" }];
59 | let validator = new Validator();
60 | let errors = validator.validate(data, rules);
61 | expect(errors.email.pattern).to.eq("格式不正确");
62 | });
63 | it("pattern email 通过", () => {
64 | let data = {
65 | email: "1@frank.com"
66 | };
67 | let rules = [{ key: "email", pattern: "email" }];
68 | let validator = new Validator();
69 | let errors = validator.validate(data, rules);
70 | expect(errors.email).to.not.exist;
71 | });
72 |
73 | it("require & pattern", () => {
74 | let data = {
75 | email: ""
76 | };
77 | let rules = [{ key: "email", pattern: "email", required: true }];
78 | let validator = new Validator();
79 | let errors = validator.validate(data, rules);
80 | expect(errors.email.required).to.exist;
81 | expect(errors.email.pattern).to.not.exist;
82 | });
83 | it("pattern & minLength", () => {
84 | let data = {
85 | email: ""
86 | };
87 | let rules = [{ key: "email", pattern: "email", minLength: 6 }];
88 | let validator = new Validator();
89 | let errors = validator.validate(data, rules);
90 | expect(errors.email.minLength).to.exist;
91 | expect(errors.email.pattern).to.exist;
92 | });
93 | it("maxLength", () => {
94 | let data = {
95 | email: "123123123123"
96 | };
97 | let rules = [{ key: "email", pattern: "email", maxLength: 10 }];
98 | let validator = new Validator();
99 | let errors = validator.validate(data, rules);
100 | expect(errors.email.maxLength).to.exist;
101 | });
102 | it("many keys", () => {
103 | let data = {
104 | email: "123123123123"
105 | };
106 | let rules = [
107 | {
108 | key: "email",
109 | required: true,
110 | minLength: 5,
111 | maxLength: 10,
112 | hasNumber: true,
113 | hasLowerCaseAndUpperCase: true,
114 | hasDot: true,
115 | hasUnderscore: true,
116 | hasFrank: true
117 | }
118 | ];
119 | let fn = () => {
120 | let validator = new Validator();
121 | validator.validate(data, rules);
122 | };
123 | expect(fn).to.throw();
124 | });
125 | it("自定义测试规则 hasNumber", () => {
126 | let data = {
127 | email: "abcabcabcabc"
128 | };
129 | let validator = new Validator();
130 | validator.hasNumber = value => {
131 | if (!/\d/.test(value)) {
132 | return "必须含有数字";
133 | }
134 | };
135 | let rules = [{ key: "email", required: true, hasNumber: true }];
136 | let errors;
137 | let fn = () => {
138 | errors = validator.validate(data, rules);
139 | };
140 | expect(fn).to.not.throw();
141 | expect(errors.email.hasNumber).to.eq("必须含有数字");
142 | });
143 | it("两个 validator 互相不影响", () => {
144 | let data = {
145 | email: "abcabcabcabc"
146 | };
147 | let validator1 = new Validator();
148 | let validator2 = new Validator();
149 | validator1.hasNumber = value => {
150 | if (!/\d/.test(value)) {
151 | return "必须含有数字";
152 | }
153 | };
154 | let rules = [{ key: "email", required: true, hasNumber: true }];
155 | let errors;
156 | expect(() => {
157 | validator1.validate(data, rules);
158 | }).to.not.throw();
159 | expect(() => {
160 | validator2.validate(data, rules);
161 | }).to.throw();
162 | });
163 |
164 | it("可以全局添加新规则", () => {
165 | let data = {
166 | email: "abcabcabcabc"
167 | };
168 | let validator1 = new Validator();
169 | let validator2 = new Validator();
170 | Validator.add("hasNumber", value => {
171 | if (!/\d/.test(value)) {
172 | return "必须含有数字";
173 | }
174 | });
175 | let rules = [{ key: "email", required: true, hasNumber: true }];
176 | let errors;
177 | expect(() => {
178 | validator1.validate(data, rules);
179 | }).to.not.throw();
180 | expect(() => {
181 | validator2.validate(data, rules);
182 | }).to.not.throw();
183 | });
184 | });
185 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | module.exports = {
3 | css: {
4 | loaderOptions: {
5 | sass: {
6 | includePaths: [path.join(__dirname, 'styles')]
7 | },
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------