14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
57 |
--------------------------------------------------------------------------------
/src/tab/tab.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
VueUI-tab
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 | -
15 | tab1
16 |
17 | -
18 | tab2
19 |
20 | -
21 | tab3
22 |
23 |
24 |
25 |
26 |
27 |
28 |
content2
29 |
content3
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
49 |
--------------------------------------------------------------------------------
/src/pager/pager.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
VueUI-pager
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
50 |
--------------------------------------------------------------------------------
/src/datepicker/datepicker.css:
--------------------------------------------------------------------------------
1 | .vue-datepicker{
2 | position: relative;
3 | display: inline-block;
4 | }
5 | .vue-datepicker-input{
6 | width: 186px;
7 | }
8 | .vue-datepicker-popup{
9 | position: absolute;
10 | border: 1px solid #ccc;
11 | border-radius: 5px;
12 | padding: 10px;
13 | display: none;
14 | background: #fff;
15 | margin-top: 2px;
16 | z-index: 1000;
17 | }
18 | .vue-datepicker-inner{
19 | width: 218px;
20 | border: 1px solid #ccc;
21 | }
22 | .vue-datepicker-body{
23 | padding: 5px 10px;
24 | }
25 | .vue-datepicker-body span{
26 | display: inline-block;
27 | width: 28px;
28 | line-height: 28px;
29 | height: 28px;
30 | text-align: center;
31 | cursor: pointer;
32 | }
33 | .vue-datepicker-item-gray{
34 | color: #999;
35 | }
36 | .vue-datepicker-item-red{
37 | color: #ff5555;
38 | }
39 | .vue-datepicker-dateRange span{
40 | }
41 | .vue-datepicker-dateRange span:hover, .vue-datepicker-dateRange-item-hover{
42 | background-color : #dbebff;
43 | }
44 | .vue-datepicker-weekRange{
45 | border-bottom: 1px solid #ccc;
46 | }
47 | .vue-datepicker-label{
48 | background-color: #f8f8f8;
49 | border-bottom: 1px solid #e5e5e5;
50 | font-weight: 700;
51 | padding: 7px 0;
52 | text-align: center;
53 | }
54 | .vue-datepicker-ctrl{
55 | position: relative;
56 | height: 30px;
57 | line-height: 30px;
58 | color: #3775c0;
59 | text-align: center;
60 | border-bottom: 1px solid #ccc;
61 | }
62 | .vue-datepicker-ctrl i{
63 | position: absolute;
64 | cursor: pointer;
65 | top: 1px;
66 | }
67 | .vue-month-btn{
68 | font-weight: bold;
69 | -webkit-user-select:none;
70 | -moz-user-select:none;
71 | -ms-user-select:none;
72 | user-select:none;
73 | }
74 | .vue-datepicker-preMonthBtn{
75 | left: 4px;
76 | }
77 | .vue-datepicker-nextMonthBtn{
78 | right: 4px;
79 | }
80 |
--------------------------------------------------------------------------------
/src/table/table.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
VueUI-table
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
107 |
--------------------------------------------------------------------------------
/src/vueUI.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | window.VueUI = function (){
6 | var VueUI = {}
7 |
8 | var componentPool = {}
9 | var comCounter = 1
10 |
11 | function getComId(){
12 | return (new Date).getTime() + '_' + comCounter
13 | }
14 |
15 | //将外部传进来的参数mix到data
16 | function mixConfig(){
17 | for (var key in this.config){
18 | this[key] = this.config[key]
19 | }
20 | }
21 |
22 | //监控外部参数的变化同步到data
23 | function syncConfig(){
24 | var me = this
25 | me.$watch('config', function (){
26 | mixConfig.call(me)
27 | }, true)
28 | }
29 |
30 | //处理vue-attr
31 | function handleVueAttr(){
32 | var me = this
33 |
34 | ;[].slice.call(me.$el.attributes).forEach(function (item){
35 | var key = item.name
36 | var value = item.value
37 |
38 | if (key.indexOf('vue-attr-') == 0){
39 | me[key.slice(9)] = value
40 | }
41 | })
42 | }
43 |
44 | //处理vue-model
45 | function handleVueModel(){
46 | var me = this
47 |
48 | ;[{a:'vue-model', b:'value'}, {a:'vue-model-text', b:'text'}].forEach(function (item){
49 | var a = item.a
50 | var b = item.b
51 |
52 | var attr = me.$el.getAttribute(a)
53 | if (!attr){
54 | return
55 | }
56 |
57 | var parentObj = me.$parent
58 | var parentAttr = attr
59 |
60 | var attrList = attr.split('.')
61 |
62 | if (attrList.length > 1){
63 | attrList.slice(0, -1).forEach(function (k){
64 | parentObj = parentObj[k]
65 | })
66 | parentAttr = attrList.slice(-1)[0]
67 | }
68 |
69 | //只有vue-model是双向(多重双向会导致数据混乱)
70 | if (a == 'vue-model'){
71 | me[b] = parentObj[parentAttr]
72 | me.$parent.$watch(attr, function (){
73 | me[b] = parentObj[parentAttr]
74 | })
75 | }
76 |
77 | me.$watch(b, function (){
78 | parentObj[parentAttr] = me[b]
79 | })
80 | })
81 | }
82 |
83 | VueUI.component = function (key, options){
84 | //在created方法中做一些全局管理操作
85 | var _compiled = options['compiled'] || VueUI.emptyFunc
86 |
87 | options['compiled'] = function (){
88 | //设置id,并保存到pool
89 | var comId = this.$el.getAttribute('vue-id') || getComId()
90 | componentPool[comId] = this
91 |
92 | handleVueAttr.call(this)
93 | handleVueModel.call(this)
94 | mixConfig.call(this)
95 | syncConfig.call(this)
96 |
97 | _compiled.call(this)
98 | }
99 | //调用系统的方式
100 | Vue.component(key, options)
101 | }
102 |
103 | VueUI.getComponent = VueUI.$ = function (id){
104 | return componentPool[id]
105 | }
106 |
107 | VueUI.getComId = getComId
108 | VueUI.emptyFunc = Function.prototype
109 |
110 | VueUI.resetArray = function (a, b){
111 | while (a.length){
112 | a.pop()
113 | }
114 | b.forEach(function (x){
115 | a.push(x)
116 | })
117 | }
118 |
119 | VueUI.winClick = function (targetDom, callback){
120 | $(window).on('click', function (e){
121 | var dom = e.target
122 |
123 | while (dom){
124 | if (dom == targetDom){
125 | return
126 | }
127 | dom = dom.parentElement
128 | if (dom == document.body){
129 | break
130 | }
131 | }
132 |
133 | callback()
134 | })
135 | }
136 |
137 | return VueUI
138 |
139 | }()
--------------------------------------------------------------------------------
/src/pager/pager.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | VueUI.component('vue-pager', {
6 | template :
7 | '',
14 | data : function (){
15 | return {
16 | pageRange : [],
17 | totalPage : 0,
18 | currPage : 1,
19 | prevShow : 3,
20 | nextShow : 3,
21 | onChange : VueUI.emptyFunc,
22 | config : {}
23 | }
24 | },
25 | watch : {
26 | totalPage : function (){
27 | this.getPageRange()
28 | },
29 | currPage : function (){
30 | this.getPageRange()
31 | this.onChange(this.currPage)
32 | },
33 | prevShow : function (){
34 | this.getPageRange()
35 | },
36 | nextShow : function (){
37 | this.getPageRange()
38 | }
39 | },
40 | methods : {
41 | getPageRange : function (){
42 | var start = 0
43 | var end = 0
44 | var showLen = this.prevShow + this.nextShow + 1
45 | var totalPage = Math.max(this.totalPage, 1)
46 | var currPage = this.currPage
47 |
48 | if (totalPage <= 1){
49 | start = end = 1
50 | }
51 | else if (totalPage <= showLen){
52 | start = 1
53 | end = totalPage
54 | }
55 | else {
56 | if (currPage <= this.prevShow + 1){
57 | start = 1
58 | end = showLen
59 | }
60 | else if (currPage >= totalPage - this.nextShow){
61 | end = totalPage
62 | start = totalPage - showLen + 1
63 | }
64 | else {
65 | start = currPage - this.prevShow
66 | end = currPage + this.nextShow
67 | }
68 | }
69 |
70 | this.pageRange = []
71 |
72 | //上一页
73 | if (currPage != 1){
74 | this.pageRange.push({num:currPage-1, text:'«'})
75 | }
76 | //第一页
77 | if (start >= 2){
78 | this.pageRange.push({num:1, text:1})
79 | }
80 | //省略好
81 | if (start > 2){
82 | this.pageRange.push({text:'..'})
83 | }
84 | //显示的页码列表
85 | for (var i=start; i<=end; i++){
86 | this.pageRange.push({
87 | num : i,
88 | text : i,
89 | className : (i==currPage) ? 'active' : ''
90 | })
91 | }
92 | //省略号
93 | if (end < totalPage-1){
94 | this.pageRange.push({text:'..'})
95 | }
96 | //最后一页
97 | if (end <= totalPage-1){
98 | this.pageRange.push({num:totalPage, text:totalPage})
99 | }
100 | //下一页
101 | if (currPage != totalPage){
102 | this.pageRange.push({num:currPage+1, text:'»'})
103 | }
104 | },
105 | pageClick : function (i){
106 | if (!i){
107 | return false
108 | }
109 | if (i == this.currPage){
110 | return false
111 | }
112 |
113 | this.currPage = i
114 | this.getPageRange()
115 | }
116 | },
117 | compiled : function (){
118 | this.getPageRange()
119 | }
120 | })
--------------------------------------------------------------------------------
/src/modal/modal.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | VueUI.component('vue-modal', {
6 | template :
7 | '
' +
8 | '
' +
9 | '
' +
10 | '
' +
11 | '' +
15 | '
' +
16 | '{{{content}}}' +
17 | '' +
18 | '
' +
19 | '' +
23 | '
' +
24 | '
' +
25 | '
'
26 | ,
27 | data : function (){
28 | return {
29 | config : {},
30 |
31 | title : '', //标题
32 | content : '', //内容
33 | toggle : false, //是否显示
34 | width : 500, //宽度
35 |
36 | // 按钮相关
37 | isShowCancelBtn : false,
38 | cancelBtnText : '取消',
39 | cancelBtnCallback : VueUI.emptyFunc,
40 |
41 | isShowOkBtn : false,
42 | okBtnText : '确认',
43 | okBtnCallback : VueUI.emptyFunc,
44 | }
45 | },
46 | watch : {
47 | content : function (){
48 | this.$compile(this.$el.querySelector('.modal-body'))
49 | },
50 | title : function (){
51 | this.title = this.title || document.title
52 | },
53 | toggle : function (){
54 | if (this.toggle){
55 | this.syncHeight()
56 | }
57 |
58 | document.body.style.overflow = this.toggle ? 'hidden' : 'auto'
59 | }
60 | },
61 | methods : {
62 | cancelBtnClick : function (){
63 | this.toggle = false
64 | this.cancelBtnCallback()
65 | },
66 | okBtnClick : function (){
67 | this.toggle = false
68 | this.okBtnCallback()
69 | },
70 | syncHeight : function (){
71 | var height = Math.max(this.$$el.find('.modal-dialog').height() + 60, document.documentElement.clientHeight)
72 | this.$backdrop.height(height)
73 | },
74 | show : function (){
75 | this.toggle = true
76 | },
77 | hide : function (){
78 | this.toggle = false
79 | }
80 | },
81 | compiled : function (){
82 | this.title = this.title || document.title
83 |
84 | this.$$el = $(this.$el)
85 | this.$backdrop = this.$$el.find('.vue-modal-backdrop')
86 | }
87 | })
88 |
89 | new function (){
90 | var str =
91 | '
' +
92 | '' +
93 | '' +
94 | '
'
95 | $('body').append(str)
96 |
97 | new Vue({
98 | el : '#VueUIAlertConfirm',
99 | data : {
100 | VueUIAlertConf : {
101 | isShowOkBtn : true
102 | },
103 | VueUIConfirmConf : {
104 | isShowOkBtn : true,
105 | isShowCancelBtn : true
106 | }
107 | }
108 | })
109 |
110 | var alertVU = VueUI.getComponent('VueUIAlert')
111 | var confirmVU = VueUI.getComponent('VueUIConfirm')
112 |
113 | VueUI.alert = function (conf){
114 | if ($.type(conf) == 'object'){
115 | alertVU.title = conf.title
116 | alertVU.content = conf.content || ''
117 | alertVU.okBtnCallback = conf.okCallback || VueUI.emptyFunc
118 | }
119 | else {
120 | alertVU.content = conf
121 | alertVU.title = document.title
122 | alertVU.okBtnCallback = VueUI.emptyFunc
123 | }
124 | alertVU.toggle = true
125 | }
126 |
127 | VueUI.confirm = function (conf){
128 | confirmVU.title = conf.title
129 | confirmVU.content = conf.content || '',
130 | confirmVU.okBtnCallback = conf.okCallback || VueUI.emptyFunc
131 | confirmVU.cancelBtnCallback = conf.cancelCallback || VueUI.emptyFunc
132 | confirmVU.toggle = true
133 | }
134 | }()
--------------------------------------------------------------------------------
/src/suggest/suggest.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | VueUI.component('vue-suggest', {
6 | template :
7 | '
' +
8 | '
' +
9 | '
' +
10 | '' +
15 | '
' +
16 | '
'
17 | ,
18 | data : function (){
19 | return {
20 | config : {},
21 | display : false,
22 |
23 | width : 300,
24 | data : [],
25 | valid : false, //是否校验是有效值
26 |
27 | value : '',
28 | text : '',
29 | index : -1,
30 | isBlock : false, //标记是否对text的change发请求
31 | isBlur : true,
32 |
33 | url : '', //请求地址
34 | field : 'words', //请求字段名
35 |
36 | filterData : function (data){ //处理返回数据
37 | return data
38 | }
39 | }
40 | },
41 | watch : {
42 | text : function (){
43 | if (this.isBlock || this.isBlur){
44 | return false
45 | }
46 | this.value = ''
47 | this.delayRequest()
48 | },
49 | display : function (val){
50 | if (!val){
51 | if (this.valid && !this.value){
52 | this.text = ''
53 | }
54 | }
55 | }
56 | },
57 | methods : {
58 | keydown : function (e){
59 | var me = this
60 | switch (e.keyCode){
61 | case 13:
62 | me.display = false
63 | break
64 |
65 | case 38:
66 | e.preventDefault()
67 | me.setIndex(me.index--)
68 | break
69 |
70 | case 40:
71 | e.preventDefault()
72 | me.setIndex(me.index++)
73 | break
74 |
75 | default:
76 | break
77 | }
78 | },
79 | focus : function (){
80 | this.isBlur = false
81 | if (this.text){
82 | this.delayRequest()
83 | }
84 | },
85 | blur : function (){
86 | this.isBlur = true
87 | },
88 | delayRequest : function (){
89 | var me = this
90 | if (me.reqTimer){
91 | clearTimeout(me.reqTimer)
92 | }
93 | me.reqTimer = setTimeout(function (){
94 | me.sendRequest()
95 | }, 150);
96 | },
97 | sendRequest : function (){
98 | var me = this
99 | var params = {}
100 |
101 | if (!me.text){
102 | return false
103 | }
104 |
105 | params[this.field] = this.text
106 | params['-'] = (new Date).getTime()
107 |
108 | $.getJSON(this.url, params).done(function (data){
109 | me.data = me.filterData(data)
110 | me.index = -1
111 | if (me.data.length){
112 | me.display = true
113 | }
114 | })
115 | },
116 | setIndex : function (){
117 | var me = this
118 |
119 | if (!me.display){
120 | return false
121 | }
122 |
123 | //暂时关闭对text的监控,此时发生的text变化不发起请求
124 | me.isBlock = true
125 | setTimeout(function (){
126 | me.isBlock = false
127 | }, 50)
128 |
129 | if (!this.data.length) {
130 | return
131 | }
132 |
133 | var min = 0
134 | var max = this.data.length - 1
135 |
136 | if (this.index < min){
137 | this.index = max
138 | }
139 | if (this.index > max){
140 | this.index = min
141 | }
142 |
143 | this.value = this.data[this.index].value
144 | this.text = this.data[this.index].text
145 | },
146 | itemClick : function (idx){
147 | this.index = idx
148 | this.setIndex()
149 | this.display = false
150 | }
151 | },
152 | compiled : function (){
153 | var me = this
154 | me.$$el = $(me.$el)
155 | me.$input = me.$$el.find('.form-control')
156 |
157 | //设置宽度
158 | me.$$el.find('.vue-suggest').outerWidth(me.width)
159 | me.$$el.find('.vue-suggest-options-div').outerWidth(me.width)
160 |
161 | //设置全局事件
162 | VueUI.winClick(me.$el, function (){
163 | me.display = false
164 | })
165 | }
166 | })
--------------------------------------------------------------------------------
/dist/vueUI.css:
--------------------------------------------------------------------------------
1 | .vue-datepicker{
2 | position: relative;
3 | display: inline-block;
4 | }
5 | .vue-datepicker-input{
6 | width: 186px;
7 | }
8 | .vue-datepicker-popup{
9 | position: absolute;
10 | border: 1px solid #ccc;
11 | border-radius: 5px;
12 | padding: 10px;
13 | display: none;
14 | background: #fff;
15 | margin-top: 2px;
16 | z-index: 1000;
17 | }
18 | .vue-datepicker-inner{
19 | width: 218px;
20 | border: 1px solid #ccc;
21 | }
22 | .vue-datepicker-body{
23 | padding: 5px 10px;
24 | }
25 | .vue-datepicker-body span{
26 | display: inline-block;
27 | width: 28px;
28 | line-height: 28px;
29 | height: 28px;
30 | text-align: center;
31 | cursor: pointer;
32 | }
33 | .vue-datepicker-item-gray{
34 | color: #999;
35 | }
36 | .vue-datepicker-item-red{
37 | color: #ff5555;
38 | }
39 | .vue-datepicker-dateRange span{
40 | }
41 | .vue-datepicker-dateRange span:hover, .vue-datepicker-dateRange-item-hover{
42 | background-color : #dbebff;
43 | }
44 | .vue-datepicker-weekRange{
45 | border-bottom: 1px solid #ccc;
46 | }
47 | .vue-datepicker-label{
48 | background-color: #f8f8f8;
49 | border-bottom: 1px solid #e5e5e5;
50 | font-weight: 700;
51 | padding: 7px 0;
52 | text-align: center;
53 | }
54 | .vue-datepicker-ctrl{
55 | position: relative;
56 | height: 30px;
57 | line-height: 30px;
58 | color: #3775c0;
59 | text-align: center;
60 | border-bottom: 1px solid #ccc;
61 | }
62 | .vue-datepicker-ctrl i{
63 | position: absolute;
64 | cursor: pointer;
65 | top: 1px;
66 | }
67 | .vue-month-btn{
68 | font-weight: bold;
69 | -webkit-user-select:none;
70 | -moz-user-select:none;
71 | -ms-user-select:none;
72 | user-select:none;
73 | }
74 | .vue-datepicker-preMonthBtn{
75 | left: 4px;
76 | }
77 | .vue-datepicker-nextMonthBtn{
78 | right: 4px;
79 | }
80 |
81 | .vue-modal{
82 | display: block;
83 | overflow-x: hidden;
84 | overflow-y: auto;
85 | }
86 | .vue-modal-backdrop{
87 | position: absolute;
88 | }
89 | .vue-pager{
90 | font-size: 0;
91 | }
92 | .vue-pager-pagination{
93 | margin: 0;
94 | }
95 | .vue-select{
96 | position: relative;
97 | height: 34px;
98 | display: inline-block;
99 | }
100 | .vue-select-content{
101 | display: none;
102 | }
103 | .vue-select-btn{
104 | text-align: left;
105 | position: relative;
106 | height: 34px;
107 | padding-right: 22px!important;
108 | font-size: 14px;
109 | }
110 | .vue-select-btn-text{
111 | display: inline-block;
112 | overflow: hidden;
113 | height: 20px;
114 | }
115 | .vue-select-btn .caret{
116 | position: absolute;
117 | right: 8px;
118 | top: 14px;
119 | }
120 | .vue-select-options-div{
121 | position: absolute;
122 | max-height: 270px;
123 | overflow-y: hidden;
124 | overflow-x: hidden;
125 | border: 1px solid rgba(0,0,0,.15);
126 | border-radius: 4px;
127 | top: 36px;
128 | z-index: 10000;
129 | }
130 | .vue-select-options-ul{
131 | position: static;
132 | float: none;
133 | display: block;
134 | min-width: 0!important;
135 | margin: 0;
136 | border: none;
137 | }
138 | .vue-select-options-ul li:hover{
139 | background: #f5f5f5;
140 | }
141 | .vue-select-options-ul a{
142 | padding: 3px 12px!important;
143 | overflow: hidden;
144 | text-decoration: none;
145 | }
146 | .vue-select-option-curr{
147 | background: #f5f5f5;
148 | }
149 | .vue-select-options-ul-scaleY, .vue-select-options-ul-scaleY li{
150 | transform:scaleY(-1);
151 | -webkit-transform:scaleY(-1);
152 | }
153 | .vue-suggest{
154 | position: relative;
155 | display: inline-block;
156 | }
157 | .vue-suggest-options-div{
158 | position: absolute;
159 | max-height: 270px;
160 | border: 1px solid rgba(0,0,0,.15);
161 | top: 36px;
162 | z-index: 10000;
163 | background: #fff;
164 | overflow: auto;
165 | }
166 | .vue-suggest-options-ul{
167 | position: static;
168 | float: none;
169 | display: block;
170 | min-width: 0!important;
171 | margin: 0;
172 | border: none;
173 | padding-top: 0!important;
174 | padding-bottom: 0!important;
175 | }
176 | .vue-suggest-options-ul li:hover{
177 | background: #f5f5f5;
178 | }
179 | .vue-suggest-options-ul a{
180 | padding: 3px 12px!important;
181 | overflow: hidden;
182 | text-decoration: none;
183 | text-overflow: ellipsis;
184 | white-space: nowrap;
185 | }
186 | .vue-suggest-option-curr{
187 | background: #f5f5f5;
188 | }
189 | .vue-tab-content{
190 | display: none;
191 | }
192 | .vue-table{}
193 | .vue-table-pager-td{
194 | text-align: right;
195 | overflow: hidden;
196 | }
197 | .vue-table-totalCount{
198 | float: left;
199 | margin: 0;
200 | margin-top: 5px;
201 | }
202 | .vue-table-pager{
203 | float: right;
204 | }
205 | .vue-table thead, .vue-table tfoot{
206 | background-color: #f8f8f8;
207 | }
208 | .vue-table-cb-td{
209 | width: 50px;
210 | text-align: center;
211 | }
212 | .vue-table-th{
213 | position: relative;
214 | }
215 | .vue-table-th .glyphicon{
216 | position: relative;
217 | left: 5px;
218 | top: 2px;
219 | font-size: 12px;
220 | cursor: pointer;
221 | }
222 | .vue-table-glyphicon-disabled{
223 | color: #999;
224 | }
225 | .vue-table-empty{
226 | text-align: center;
227 | line-height: 60px!important;
228 | }
--------------------------------------------------------------------------------
/src/select/select.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | VueUI.component('vue-select', {
6 | template :
7 | '
' +
8 | '
' +
9 | '
' +
13 | '
' +
14 | '' +
19 | '
' +
20 | '
'
21 | ,
22 | data : function (){
23 | return {
24 | config : {},
25 | //数据
26 | data : [],
27 | //组件宽度
28 | width: 100,
29 | //是否显示options
30 | display : false,
31 | //当前值
32 | value : '',
33 | //当前文本
34 | text : '',
35 | //当前索引
36 | index : 0,
37 | onChange : VueUI.emptyFunc
38 | }
39 | },
40 | watch : {
41 | data : function (){
42 | this.syncCurr('data')
43 | },
44 | value : function (){
45 | this.syncCurr('value')
46 | },
47 | index : function (){
48 | this.syncCurrByIndex()
49 | this.onChange(this.value, this.text, this.index)
50 | }
51 | },
52 | methods : {
53 | buttonClick : function (){
54 | this.toggleOptions()
55 | },
56 | itemClick : function (idx){
57 | this.index = idx
58 | this.toggleOptions()
59 | },
60 | syncCurr : function (key){
61 | if (this.data.length == 0){
62 | return
63 | }
64 |
65 | for (var i=0, option; i
10){
124 | $div.css('overflow-y', 'scroll')
125 | }
126 | else {
127 | $div.css('overflow-y', 'hidden')
128 | }
129 |
130 | if ( (divH >= (pageH-selectY)) && (selectY >= divH) ){
131 | marginTop = -(btnH + divH + 4)
132 | scrollTop = 1e8
133 | fn = 'addClass'
134 | }
135 | else {
136 | marginTop = 0
137 | scrollTop = 0
138 | fn = 'removeClass'
139 | }
140 |
141 | $div.css('margin-top', marginTop)
142 | $ul[fn]('vue-select-options-ul-scaleY')
143 |
144 | Vue.nextTick(function (){
145 | $div.scrollTop(scrollTop)
146 | })
147 | }
148 | },
149 | compiled : function (){
150 | var me = this
151 |
152 | this.syncCurr()
153 |
154 | var $dom = $(this.$el)
155 | var $btn = $dom.find('.vue-select-btn')
156 |
157 | //检查是否有硬编码的option
158 | var $options = $dom.find('option')
159 | if ($options.length > 0){
160 | this.data = []
161 |
162 | $options.each(function (){
163 | me.data.push({
164 | value : this.value,
165 | text : this.text
166 | })
167 | })
168 | }
169 |
170 | //设置各种宽度
171 | $dom.find('.vue-select').outerWidth(this.width)
172 | $btn.find('.vue-select-btn-text').width(this.width - 35)
173 | $dom.find('.vue-select-options-div').outerWidth(this.width)
174 |
175 | VueUI.winClick(me.$el, function (){
176 | me.display = false
177 | })
178 | }
179 | })
--------------------------------------------------------------------------------
/src/table/table.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 bravf(bravfing@126.com)
3 | */
4 |
5 | VueUI.component('vue-table', {
6 | template :
7 | ''
29 | ,
30 | data : function (){
31 | return {
32 | config : {},
33 | data : [], //数据
34 | totalCount : 0, // 数据总量
35 | columns : [], //列
36 | columnsLen : 0, //总列数
37 | isShowHead : true, //是否显示表格头
38 | isShowFoot : true, //是否显示表格尾
39 | isCheckable : false, //是否可以选择数据
40 | sortField : '', //当前排序字段
41 | sortDir : 0, //0表示降序,1表示升序
42 | onSortChange : VueUI.emptyFunc, //当排序信息改变
43 |
44 | //分页相关参数
45 | pagerConfig : {
46 | totalPage : 0,
47 | onChange : VueUI.emptyFunc
48 | },
49 | totalPage : 0,
50 | onPagerChange : VueUI.emptyFunc,
51 | vuePageId : VueUI.getComId() + '_table_pager'
52 | }
53 | },
54 | watch : {
55 | totalPage : function (){
56 | this.pagerConfig.totalPage = this.totalPage
57 | },
58 | onPagerChange : function (){
59 | this.pagerConfig.onChange = this.onPagerChange
60 | },
61 | data : function (){
62 | var me = this
63 | this.unCheckedMaster()
64 |
65 | if (this.data.length > 0){
66 | me.compileTbody()
67 | }
68 | },
69 | sortField : function (){
70 | this.syncSort()
71 | },
72 | sortDir : function (){
73 | this.syncSort()
74 | }
75 | },
76 | methods : {
77 | compileTbody : function (){
78 | this.$compile(this.$el.getElementsByTagName('tbody')[0])
79 | },
80 | sortClick : function (idx){
81 | var column = this.columns[idx]
82 | if (!column.isSortable){
83 | return
84 | }
85 |
86 | this.sortField = column.field
87 | column.sortDir = (column.sortDir=='0') ? '1' : '0'
88 | this.sortDir = column.sortDir
89 |
90 | this.onSortChange(this.sortField, this.sortDir)
91 | },
92 | syncSort : function (){ //同步排序相关
93 | var me = this
94 | var columns = me.columns
95 |
96 | me.$$el.find('.vue-table-th').each(function (idx){
97 | var arrow = $(this).find('.glyphicon')
98 | if (!arrow.length){
99 | return
100 | }
101 | if (me.sortField == columns[idx].field){
102 | arrow.attr('class', 'glyphicon glyphicon-arrow-' + ['up', 'down'][me.sortDir])
103 | }
104 | else {
105 | arrow.addClass('vue-table-glyphicon-disabled')
106 | }
107 | })
108 |
109 | },
110 | masterCbChange : function (e){
111 | var cbs = this.$$el.find('.vue-table-cb').prop('checked', e.target.checked)
112 | },
113 | cbChange : function (){
114 | var me = this
115 | var isAllChecked = true
116 |
117 | me.$$el.find('.vue-table-cb').each(function (){
118 | if (!this.checked){
119 | isAllChecked = false
120 | return false
121 | }
122 | })
123 |
124 | me.$$el.find('.vue-table-master-cb').prop('checked', isAllChecked)
125 | },
126 | unCheckedMaster : function (){
127 | if (!this.isCheckable){
128 | return
129 | }
130 | this.$$el.find('.vue-table-master-cb').prop('checked', false)
131 | },
132 | handleColumns : function (){
133 | function getDefaultConf(){
134 | return {
135 | width : 150,
136 | textAlign : 'left',
137 | isSortable : false
138 | }
139 | }
140 |
141 | var columns = this.columns
142 | if (!columns.length){
143 | return
144 | }
145 |
146 | var me = this
147 | var hasAuto = false //检查是否有width=auto的列,不然就设置最后一项width=auto
148 |
149 | for (var i=0,c,len=columns.length; i' +
8 | '' +
9 | '' +
29 | ' '
30 | ,
31 | data : function (){
32 | var today = new Date
33 | return {
34 | config : {},
35 | value : '',
36 | weekRange : ['一', '二', '三', '四', '五', '六', '日'],
37 | dateRange : [], //需要绘制的日期区间
38 | currDate : new Date, //当前日期
39 | popupDisplay : 'none'
40 | }
41 | },
42 | watch : {
43 | currDate : function (){
44 | this.getDateRange()
45 | },
46 | value : function (){
47 | var valueDate = this.parse(this.value)
48 | if (valueDate){
49 | this.currDate = valueDate
50 | }
51 | }
52 | },
53 | methods : {
54 | inputClick : function (e){
55 | this.popupDisplay = this.popupDisplay=='none' ? 'block' : 'none'
56 | },
57 | preNextMonthClick : function (flag){
58 | var year = this.currDate.getFullYear()
59 | var month = this.currDate.getMonth()
60 | var date = this.currDate.getDate()
61 |
62 | if (flag == 0){
63 | var preMonth = this.getYearMonth(year, month-1)
64 | this.currDate = new Date(preMonth.year, preMonth.month, date)
65 | }
66 | else {
67 | var nextMonth = this.getYearMonth(year, month+1)
68 | this.currDate = new Date(nextMonth.year, nextMonth.month, date)
69 | }
70 | },
71 | itemClick : function (date){
72 | this.currDate = date
73 | this.value = this.stringify(this.currDate)
74 | this.popupDisplay = 'none'
75 | },
76 | getYearMonth : function (year, month){
77 | if (month > 11){
78 | year++
79 | month = 0
80 | }
81 | else if (month < 0){
82 | year--
83 | month = 11
84 | }
85 | return {year:year, month:month}
86 | },
87 | stringify : function (date, format){
88 | format = format || 'yyyy-MM-dd'
89 |
90 | var year = date.getFullYear()
91 | var month = date.getMonth() + 1
92 | var day = date.getDate()
93 |
94 | return format
95 | .replace(/yyyy/g, year)
96 | .replace(/MM/g, ('0'+month).slice(-2))
97 | .replace(/dd/g, ('0'+day).slice(-2))
98 | .replace(/yy/g, year)
99 | .replace(/M/g, month)
100 | .replace(/d/g, day)
101 | },
102 | parse : function (str){
103 | var date = new Date(str)
104 | return isNaN(date.getFullYear()) ? null : date
105 | },
106 | getDayCount : function (year, month){ //得到每月总天数
107 | var dict = [31,28,31,30,31,30,31,31,30,31,30,31]
108 |
109 | //如果2月
110 | if (month == 1){
111 | //如果瑞年
112 | if ( (year%400==0) || (year%4==0 && year%100!=0) ){
113 | return 29
114 | }
115 | return 28
116 | }
117 |
118 | return dict[month]
119 | },
120 | getDateRange : function (){
121 | this.dateRange = []
122 |
123 | var time = {
124 | year : this.currDate.getFullYear(),
125 | month : this.currDate.getMonth(),
126 | day : this.currDate.getDate()
127 | }
128 | //本月第一天
129 | var currMonthFirstDay = new Date(time.year, time.month, 1)
130 | //本月第一天是周几?
131 | var firstDayWeek = currMonthFirstDay.getDay()
132 | if (firstDayWeek == 0){
133 | firstDayWeek = 7
134 | }
135 | //本月总天数
136 | var dayCount = this.getDayCount(time.year, time.month)
137 |
138 | //如果需要补足上月
139 | if (firstDayWeek > 1){
140 | var preMonth = this.getYearMonth(time.year, time.month-1)
141 |
142 | //上月总天数
143 | var prevMonthDayCount = this.getDayCount(preMonth.year, preMonth.month)
144 | for (var i=1; i