一.BaseCounter
接收参数max、min,当number内容改变时返回父组件on-change事件
//counter.vue
<template> <div class="counter-component"> <div class="counter-btn" @click="minus"> - </div> <div class="counter-show"> <input type="text" v-model="number" @keyup="fixNumber"> </div> <div class="counter-btn" @click="add"> + </div> </div> </template> <script> export default { props: { max: { type: Number, default: 5 }, min: { type: Number, default: 1 } }, data () { return { number: this.min } }, watch: { number () { this.$emit('on-change', this.number) } }, methods: { fixNumber () { let fix; if (typeof this.number === 'string') { fix = Number(this.number.replace(/\D/g, '')) } else { fix = this.number } if (fix > this.max || fix < this.min) { fix = this.min } this.number = fix }, minus () { if (this.number <= this.min) { return } this.number -- }, add () { if (this.number >= this.max) { return } this.number ++ } } } </script> <style scoped> .counter-component { position: relative; display: inline-block; overflow: hidden; vertical-align: middle; } .counter-show { float: left; } .counter-show input { border: none; border-top: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3; height: 23px; line-height: 23px; width: 30px; outline: none; text-indent: 4px; } .counter-btn { border: 1px solid #e3e3e3; float: left; height: 25px; line-height: 25px; width: 25px; text-align: center; cursor: pointer; } .counter-btn:hover { border-color: #4fc08d; background: #4fc08d; color: #fff; } </style>
//父组件
<v-counter @on-change="onParamChange('buyNum', $event)"></v-counter>
二.BaseSelection
//selection.vue
<template> <div class="selection-component"> <div class="selection-show" @click="toggleDrop"> <span>{{selections[nowIndex].label}}</span> <div class="arrow"></div> </div> <div class="selection-list" v-if="isDrop"> <ul> <li v-for="(item, index) in selections" @click="chooseSelection(index)">{{item.label}}</li> </ul> </div> </div> </template> <script> export default { props: { selections: { type: Array, default: [{ label: 'test', value: 0 }] } }, data () { return { isDrop: false, nowIndex: 0 } }, methods: { toggleDrop(){ this.isDrop = !this.isDrop; }, chooseSelection(index){ this.nowIndex = index; this.isDrop = false; //通过on-change事件,把要购买的东西传回给父组件 this.$emit('on-change', this.selections[this.nowIndex]); } } } </script> <style scoped> .selection-component { position: relative; display: inline-block; } .selection-show { border: 1px solid #e3e3e3; padding: 0 20px 0 10px; display: inline-block; position: relative; cursor: pointer; height: 25px; line-height: 25px; border-radius: 3px; background: #fff; } .selection-show .arrow { display: inline-block; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid #e3e3e3; width: 0; height: 0; margin-top: -1px; margin-left: 6px; margin-right: -14px; vertical-align: middle; } .selection-list { display: inline-block; position: absolute; left: 0; top: 25px; width: 100%; background: #fff; border-top: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3; z-index: 5; } .selection-list li { padding: 5px 15px 5px 10px; border-left: 1px solid #e3e3e3; border-right: 1px solid #e3e3e3; cursor: pointer; background: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .selection-list li:hover { background: #e3e3e3; } </style>//父组件
<v-selection :selections="buyTypes" @on-change="onParamChange('buyType', $event)"></v-selection>
三.BaseChooser
单选
//chooser.vue
<template> <div class="chooser-component"> <ul class="chooser-list"> <li v-for="(item, index) in selections" @click="chosenSelection(index)" :title="item.label" :class="{active:index === nowIndex}" >{{ item.label }}</li> </ul> </div> </div> </template> <script> export default { props: { selections: { type: Array, default: [{ label: 'test', value: 0 }] } }, data () { return { nowIndex: 0 } }, methods: { chosenSelection (index) { this.nowIndex = index; this.$emit('on-change', this.selections[index]) } } } </script> <style scoped> .chooser-component { position: relative; display: inline-block; } .chooser-list li{ display: inline-block; border: 1px solid #e3e3e3; height: 25px; line-height: 25px; padding: 0 8px; margin-right: 5px; border-radius: 3px; text-align: center; cursor: pointer; } .chooser-list li.active { border-color: #4fc08d; background: #4fc08d; color: #fff; } </style>//父组件
<v-chooser :selections="periodList" @on-change="onParamChange('period', $event)"></v-chooser>
四.BaseMultiplyChooser
//multiplyChooser.vue
<template> <div class="chooser-component"> <ul class="chooser-list"> <li v-for="(item, index) in selections" @click="toggleSelection(index)" :title="item.label" :class="{active: checkActive(index)}"> {{ item.label }} </li> </ul> </div> </template> <script> import _ from 'lodash' export default{ props: { selections: { type: Array, default: [{ label: 'test', value: 0 }] } }, data(){ return { nowIndexes: [0] } }, methods:{ toggleSelection(index){ if(this.nowIndexes.indexOf(index) === -1){ this.nowIndexes.push(index); }else { this.nowIndexes = _.remove(this.nowIndexes, (idx) => { return idx !== index }) } let nowObjArray = _.map(this.nowIndexes, (idx) => { return this.selections[idx] }) this.$emit('on-change', nowObjArray); }, checkActive(index){ return this.nowIndexes.indexOf(index) !== -1 } } } </script> <style scoped> .chooser-component { position: relative; display: inline-block; } .chooser-list li{ display: inline-block; border: 1px solid #e3e3e3; height: 25px; line-height: 25px; padding: 0 8px; margin-right: 5px; border-radius: 3px; text-align: center; cursor: pointer; } .chooser-list li.active { border-color: #4fc08d; background: #4fc08d; color: #fff; } </style>//父组件
<v-mul-chooser :selections="versionList" @on-change="onParamChange('versions', $event)"></v-mul-chooser>
五.BaseDialog
http://blog.csdn.net/xidongdong1/article/details/78666709
六.datePicker
<style scoped> .datetime-picker { position: relative; display: inline-block; font-family: "Segoe UI","Lucida Grande",Helvetica,Arial,"Microsoft YaHei"; -webkit-font-smoothing: antialiased; color: #333; } .datetime-picker * { box-sizing: border-box; } .datetime-picker input { width: 100%; padding: 5px 10px; height: 30px; outline: 0 none; border: 1px solid #ccc; font-size: 13px; } .datetime-picker .picker-wrap { position: absolute; z-index: 1000; width: 238px; height: 280px; margin-top: 2px; background-color: #fff; box-shadow: 0 0 6px #ccc; } .datetime-picker table { width: 100%; border-collapse: collapse; border-spacing: 0; text-align: center; font-size: 13px; } .datetime-picker tr { height: 34px; border: 0 none; } .datetime-picker th, .datetime-picker td { user-select: none; width: 34px; height: 34px; padding: 0; border: 0 none; line-height: 34px; text-align: center; } .datetime-picker td { cursor: pointer; } .datetime-picker td:hover { background-color: #f0f0f0; } .datetime-picker td.date-pass, .datetime-picker td.date-future { color: #aaa; } .datetime-picker td.date-active { background-color: #ececec; color: #3bb4f2; } .datetime-picker .date-head { background-color: #3bb4f2; text-align: center; color: #fff; font-size: 14px; } .datetime-picker .date-days { color: #3bb4f2; font-size: 14px; } .datetime-picker .show-year { display: inline-block; min-width: 62px; vertical-align: middle; } .datetime-picker .show-month { display: inline-block; min-width: 28px; vertical-align: middle; } .datetime-picker .btn-prev, .datetime-picker .btn-next { cursor: pointer; display: inline-block; padding: 0 10px; vertical-align: middle; } .datetime-picker .btn-prev:hover, .datetime-picker .btn-next:hover { background: rgba(16, 160, 234, 0.5); } </style> <template> <div class="datetime-picker" :style="{ width: width }"> <input type="text" :style="styleObj" :readonly="readonly" v-model="showValue" @click="show = !show"> <div class="picker-wrap" v-show="show"> <table class="date-picker"> <thead> <tr class="date-head"> <th colspan="4"> <span class="btn-prev" @click="yearClick(-1)"><</span> <span class="show-year">{{now.getFullYear()}}</span> <span class="btn-next" @click="yearClick(1)">></span> </th> <th colspan="3"> <span class="btn-prev" @click="monthClick(-1)"><</span> <span class="show-month">{{months[now.getMonth()]}}</span> <span class="btn-next" @click="monthClick(1)">></span> </th> </tr> <tr class="date-days"> <th v-for="day in days">{{day}}</th> </tr> </thead> <tbody> <tr v-for="i in 6"> <td v-for="j in 7" :class="date[i * 7 + j] && date[i * 7 + j].status" :date="date[i * 7 + j] && date[i * 7 + j].date" @click="pickDate(i * 7 + j)">{{date[i * 7 + j] && date[i * 7 + j].text}}</td> </tr> </tbody> </table> </div> </div> </template> <script> export default { props: { width: { type: String, default: '238px' }, readonly: { type: Boolean, default: false }, value: { type: String, default: '' }, format: { type: String, default: 'YYYY-MM-DD' }, styleObj: {type: Object, default: null} }, data () { return { show: false, showValue: '', days: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], date: [], now: new Date() }; }, watch: { now () { this.update(); }, show () { this.update(); } }, methods: { close () { this.show = false; }, update () { var arr = []; var time = new Date(this.now); time.setMonth(time.getMonth(), 1); // the first day var curFirstDay = time.getDay(); curFirstDay === 0 && (curFirstDay = 7); time.setDate(0); // the last day var lastDayCount = time.getDate(); for (let i = curFirstDay; i > 0; i--) { arr.push({ text: lastDayCount - i + 1, time: new Date(time.getFullYear(), time.getMonth(), lastDayCount - i + 1), status: 'date-pass' }); } time.setMonth(time.getMonth() + 2, 0); // the last day of this month var curDayCount = time.getDate(); time.setDate(1); // fix bug when month change var value = this.value || this.stringify(new Date()); for (let i = 0; i < curDayCount; i++) { let tmpTime = new Date(time.getFullYear(), time.getMonth(), i + 1); let status = ''; this.stringify(tmpTime) === value && (status = 'date-active'); arr.push({ text: i + 1, time: tmpTime, status: status }); } var j = 1; while (arr.length < 42) { arr.push({ text: j, time: new Date(time.getFullYear(), time.getMonth() + 1, j), status: 'date-future' }); j++; } this.date = arr; }, yearClick (flag) { this.now.setFullYear(this.now.getFullYear() + flag); this.now = new Date(this.now); }, monthClick (flag) { this.now.setMonth(this.now.getMonth() + flag); this.now = new Date(this.now); }, pickDate (index) { this.show = false; this.now = new Date(this.date[index].time); this.showValue = this.stringify(); this.$emit('on-change', this.showValue); }, parse (str) { var time = new Date(str); return isNaN(time.getTime()) ? null : time; }, stringify (time = this.now, format = this.format) { var year = time.getFullYear(); var month = time.getMonth() + 1; var date = time.getDate(); var monthName = this.months[time.getMonth()]; var map = { YYYY: year, MMM: monthName, MM: ('0' + month).slice(-2), M: month, DD: ('0' + date).slice(-2), D: date }; return format.replace(/Y+|M+|D+/g, function (str) { return map[str]; }); }, leave (e) { if (!this.$el.contains(e.target)) { this.close(); } } }, mounted () { this.now = this.parse(this.value) || new Date(); document.addEventListener('click', this.leave, false); }, beforeDestroy () { document.removeEventListener('click', this.leave, false); } }; </script>