提交 70941b8e 编写于 作者: Q qiang

refactor: 重构H5端picker

上级 e4c0e281
......@@ -8,7 +8,6 @@ module.exports = [
'uni-page-refresh',
'uni-actionsheet',
'uni-modal',
'uni-picker',
'uni-toast',
'uni-resize-sensor',
......
<template>
<uni-picker @click.stop="_click">
<div>
<slot/>
</div>
</uni-picker>
</template>
<script>
import {
emitter
} from 'uni-mixins'
const {
subscribe,
unsubscribe,
publishHandler
} = UniViewJSBridge
const mode = {
SELECTOR: 'selector',
MULTISELECTOR: 'multiSelector',
TIME: 'time',
DATE: 'date'
// 暂不支持城市选择
// REGION: 'region'
}
const fields = {
YEAR: 'year',
MONTH: 'month',
DAY: 'day'
}
export default {
name: 'Picker',
mixins: [emitter],
props: {
name: {
type: String,
default: ''
},
range: {
type: Array,
default () {
return []
}
},
rangeKey: {
type: String,
default: ''
},
value: {
type: [Number, String, Array],
default: 0
},
mode: {
type: String,
default: mode.SELECTOR,
validator (val) {
return Object.values(mode).indexOf(val) >= 0
}
},
fields: {
type: String,
default: 'day',
validator (val) {
return Object.values(fields).indexOf(val) >= 0
}
},
start: {
type: String,
default () {
if (this.mode === mode.TIME) {
return '00:00'
}
if (this.mode === mode.DATE) {
let year = (new Date()).getFullYear() - 100
switch (this.fields) {
case fields.YEAR:
return year
case fields.MONTH:
return year + '-01'
case fields.DAY:
return year + '-01-01'
}
}
return ''
}
},
end: {
type: String,
default () {
if (this.mode === mode.TIME) {
return '23:59'
}
if (this.mode === mode.DATE) {
let year = (new Date()).getFullYear() + 100
switch (this.fields) {
case fields.YEAR:
return year
case fields.MONTH:
return year + '-12'
case fields.DAY:
return year + '-12-31'
}
}
return ''
}
},
disabled: {
type: [Boolean, String],
default: false
}
},
data () {
return {
valueSync: this.value || 0,
visible: false,
valueChangeSource: ''
}
},
watch: {
value (val) {
if (Array.isArray(val)) {
if (!Array.isArray(this.valueSync)) {
this.valueSync = []
}
this.valueSync.length = val.length
val.forEach((val, index) => {
if (val !== this.valueSync[index]) {
this.$set(this.valueSync, index, val)
}
})
} else if (typeof val !== 'object') {
this.valueSync = val
}
},
valueSync (val) {
if (!this.valueChangeSource) {
this._show()
} else {
this.$emit('update:value', val)
}
}
},
created () {
this.$dispatch('Form', 'uni-form-group-update', {
type: 'add',
vm: this
})
Object.keys(this.$props).forEach(key => {
if (key !== 'value' && key !== 'name') {
this.$watch(key, this._show)
}
})
},
beforeDestroy () {
this.$dispatch('Form', 'uni-form-group-update', {
type: 'remove',
vm: this
})
},
destroyed () {
if (this.visible) {
const id = this.$page.id
publishHandler('hidePicker', {}, id)
}
},
methods: {
_click () {
if (this.disabled) {
return
}
const id = this.$page.id
subscribe(`${id}-picker-change`, this.change)
subscribe(`${id}-picker-columnchange`, this.columnchange)
subscribe(`${id}-picker-cancel`, this.cancel)
this.visible = true
this._show()
},
_show () {
if (this.visible) {
const id = this.$page.id
let options = Object.assign({}, this.$props)
options.value = this.valueSync
publishHandler('showPicker', options, id)
}
},
change (args) {
this.visible = false
const id = this.$page.id
unsubscribe(`${id}-picker-change`)
unsubscribe(`${id}-picker-columnchange`)
unsubscribe(`${id}-picker-cancel`)
if (!this.disabled) {
this.valueChangeSource = 'click'
let value = args.value
this.valueSync = Array.isArray(value) ? value.map(val => val) : value
this.$trigger('change', {}, {
value
})
}
},
columnchange (args) {
this.$trigger('columnchange', {}, args)
},
cancel (args) {
this.visible = false
const id = this.$page.id
unsubscribe(`${id}-picker-change`)
unsubscribe(`${id}-picker-columnchange`)
unsubscribe(`${id}-picker-cancel`)
this.$trigger('cancel', {}, {})
},
_getFormData () {
return {
value: this.valueSync,
key: this.name
}
},
_resetFormData () {
this.valueSync = ''
}
}
}
</script>
<style>
uni-picker {
display: block;
}
</style>
......@@ -21,10 +21,6 @@
v-if="$options.components.Modal"
v-bind="showModal"
@close="_onModalClose" />
<picker
v-if="$options.components.Picker"
v-bind="showPicker"
@close="_onPickerClose" />
</uni-app>
</template>
<script>
......
import Toast from './toast'
import Modal from './modal'
import Picker from './picker'
import ActionSheet from './actionSheet'
export default {
Toast,
Modal,
Picker,
ActionSheet
}
const defaultProps = {
visible: false,
mode: '',
range: [],
rangeKey: '',
value: '',
disabled: false,
start: '',
end: '',
fields: 'day',
customItem: ''
}
export default {
data () {
return {
showPicker: {
visible: false
}
}
},
created () {
// 订阅 View 层的 showPicker 事件
UniServiceJSBridge.subscribe('showPicker', (args, pageId) => {
// 根据不同参数,渲染不同类型 picker(注意全局仅一个 picker 组件对象,每次 showPicker 需传入当前类型 picker 的完整参数)
this.showPicker = Object.assign(defaultProps, args, {
pageId,
visible: true
})
})
// 订阅 View 层的 hidePicker 事件
UniServiceJSBridge.subscribe('hidePicker', () => {
this._onPickerClose()
})
// 订阅页面返回跳转时触发的 uni.onHidePopup 事件,隐藏 picker
UniServiceJSBridge.on('onHidePopup', () => {
this._onPickerClose()
})
},
methods: {
// 处理 Picker close 回调
_onPickerClose () {
// 隐藏 picker 重置数据
this.showPicker.visible = false
this.showPicker.mode = 'selector'
this.showPicker.range = []
this.showPicker.value = 0
}
}
}
<template>
<uni-picker @touchmove.prevent>
<uni-picker @click.stop="_show">
<div
ref="picker"
class="uni-picker-container"
@touchmove.prevent>
<transition name="uni-fade">
<div
v-show="visible"
class="uni-mask"
@click="_cancel"/>
@click="_cancel" />
</transition>
<div
:class="{'uni-picker-toggle':visible}"
......@@ -38,19 +42,24 @@
<div v-for="(item,index) in units" :key="index">{{item}}</div>
</div>-->
</div>
</div>
<div>
<slot />
</div>
</uni-picker>
</template>
<script>
import {
formatDateTime
} from 'uni-shared'
import { emitter } from 'uni-mixins'
import { formatDateTime } from 'uni-shared'
const mode = {
SELECTOR: 'selector',
MULTISELECTOR: 'multiSelector',
TIME: 'time',
DATE: 'date',
REGION: 'region'
DATE: 'date'
// 暂不支持城市选择
// REGION: 'region'
}
const fields = {
YEAR: 'year',
......@@ -59,10 +68,11 @@ const fields = {
}
export default {
name: 'Picker',
mixins: [emitter],
props: {
pageId: {
type: Number,
default: 0
name: {
type: String,
default: ''
},
range: {
type: Array,
......@@ -80,11 +90,17 @@ export default {
},
mode: {
type: String,
default: mode.SELECTOR
default: mode.SELECTOR,
validator (val) {
return Object.values(mode).indexOf(val) >= 0
}
},
fields: {
type: String,
default: fields.DAY
default: 'day',
validator (val) {
return Object.values(fields).indexOf(val) >= 0
}
},
start: {
type: String,
......@@ -93,7 +109,7 @@ export default {
return '00:00'
}
if (this.mode === mode.DATE) {
let year = (new Date()).getFullYear() - 150
let year = new Date().getFullYear() - 100
switch (this.fields) {
case fields.YEAR:
return year
......@@ -113,7 +129,7 @@ export default {
return '23:59'
}
if (this.mode === mode.DATE) {
let year = (new Date()).getFullYear() + 150
let year = new Date().getFullYear() + 100
switch (this.fields) {
case fields.YEAR:
return year
......@@ -129,14 +145,13 @@ export default {
disabled: {
type: [Boolean, String],
default: false
},
visible: {
type: Boolean,
default: false
}
},
data () {
return {
valueSync: this.value || 0,
visible: false,
valueChangeSource: '',
timeArray: [],
dateArray: [],
valueArray: [],
......@@ -199,9 +214,36 @@ export default {
}
},
watch: {
value (val) {
if (Array.isArray(val)) {
if (!Array.isArray(this.valueSync)) {
this.valueSync = []
}
this.valueSync.length = val.length
val.forEach((val, index) => {
if (val !== this.valueSync[index]) {
this.$set(this.valueSync, index, val)
}
})
} else if (typeof val !== 'object') {
this.valueSync = val
}
},
valueSync (value) {
if (this.valueChangeSource) {
this.$trigger(
'change',
{},
{
value
}
)
}
},
valueArray (val) {
if (this.mode === mode.TIME || this.mode === mode.DATE) {
let getValue = this.mode === mode.TIME ? this._getTimeValue : this._getDateValue
let getValue =
this.mode === mode.TIME ? this._getTimeValue : this._getDateValue
let valueArray = this.valueArray
let startArray = this.startArray
let endArray = this.endArray
......@@ -209,7 +251,11 @@ export default {
const dateArray = this.dateArray
let max = dateArray[2].length
let day = dateArray[2][valueArray[2]]
let realDay = new Date(`${dateArray[0][valueArray[0]]}/${dateArray[1][valueArray[1]]}/${day}`).getDate()
let realDay = new Date(
`${dateArray[0][valueArray[0]]}/${
dateArray[1][valueArray[1]]
}/${day}`
).getDate()
day = Number(day)
if (realDay < day) {
valueArray[2] -= realDay + max - day
......@@ -225,29 +271,56 @@ export default {
if (value !== this.oldValueArray[column]) {
this.oldValueArray[column] = value
if (this.mode === mode.MULTISELECTOR) {
// 触发 View 层 columnchange 事件
UniServiceJSBridge.publishHandler(this.pageId + '-picker-columnchange', {
this.$trigger('columnchange', {}, {
column,
value
}, this.pageId)
}
)
}
})
},
visible (val) {
if (!val) {
this.$nextTick(() => this._setValue())
}
})
}
},
created () {
this.$dispatch('Form', 'uni-form-group-update', {
type: 'add',
vm: this
})
this._createTime()
this._createDate()
this._setValue()
this.$watch('value', this._setValue)
this.$watch('valueSync', this._setValue)
this.$watch('mode', this._setValue)
},
beforeDestroy () {
this.$dispatch('Form', 'uni-form-group-update', {
type: 'remove',
vm: this
})
},
methods: {
_show () {
if (this.disabled) {
return
}
this.valueChangeSource = ''
this._setValue()
var $picker = this.$refs.picker
$picker.remove();
(document.querySelector('uni-app') || document.body).append($picker)
$picker.style.display = 'block'
setTimeout(() => {
this.visible = true
}, 20)
},
_getFormData () {
return {
value: this.valueSync,
key: this.name
}
},
_resetFormData () {
this.valueSync = ''
},
_createTime () {
var hours = []
var minutes = []
......@@ -263,7 +336,7 @@ export default {
},
_createDate () {
var years = []
var year = (new Date()).getFullYear()
var year = new Date().getFullYear()
for (let i = year - 150, end = year + 150; i <= end; i++) {
years.push(String(i))
}
......@@ -292,7 +365,7 @@ export default {
}
},
_setValue () {
var val = this.value
var val = this.valueSync
var valueArray
switch (this.mode) {
case mode.SELECTOR:
......@@ -308,7 +381,9 @@ export default {
mode: mode.TIME
})
}
valueArray = val.split(':').map((val, i) => this.timeArray[i].indexOf(val))
valueArray = val
.split(':')
.map((val, i) => this.timeArray[i].indexOf(val))
break
case mode.DATE:
// 处理默认值为当前日期
......@@ -317,7 +392,9 @@ export default {
mode: mode.DATE
})
}
valueArray = val.split('-').map((val, i) => this.dateArray[i].indexOf(val))
valueArray = val
.split('-')
.map((val, i) => this.dateArray[i].indexOf(val))
break
}
this.oldValueArray = [...valueArray]
......@@ -331,38 +408,60 @@ export default {
case mode.MULTISELECTOR:
return val.map(val => val)
case mode.TIME:
return this.valueArray.map((val, i) => this.timeArray[i][val]).join(':')
return this.valueArray
.map((val, i) => this.timeArray[i][val])
.join(':')
case mode.DATE:
return this.valueArray.map((val, i) => this.dateArray[i][val]).join('-')
return this.valueArray
.map((val, i) => this.dateArray[i][val])
.join('-')
}
},
_change () {
this.$emit('close')
// 触发 View 层 change 事件
UniServiceJSBridge.publishHandler(this.pageId + '-picker-change', {
value: this._getValue()
}, this.pageId)
this._close()
this.valueChangeSource = 'click'
let value = this._getValue()
this.valueSync = Array.isArray(value) ? value.map(val => val) : value
},
_cancel () {
// 通知父组件修改 visible
this.$emit('close')
// 触发 View 层 cancel 事件
UniServiceJSBridge.publishHandler(this.pageId + '-picker-cancel', {}, this.pageId)
this._close()
this.$trigger('cancel', {}, {})
},
_close () {
this.visible = false
setTimeout(() => {
var $picker = this.$refs.picker
$picker.remove()
this.$el.prepend($picker)
$picker.style.display = 'none'
}, 260)
}
}
}
</script>
<style>
uni-picker {
display: block;
}
.uni-picker-container {
display: none;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
box-sizing: border-box;
z-index: 999;
font-size: 16px;
}
uni-picker .uni-picker * {
.uni-picker-container .uni-picker * {
box-sizing: border-box;
}
uni-picker .uni-picker {
.uni-picker-container .uni-picker {
position: fixed;
left: 0;
bottom: 0;
......@@ -375,12 +474,12 @@ uni-picker .uni-picker {
transition: transform 0.3s, visibility 0.3s;
}
uni-picker .uni-picker.uni-picker-toggle {
.uni-picker-container .uni-picker.uni-picker-toggle {
visibility: visible;
transform: translate(0, 0);
}
uni-picker .uni-picker-content {
.uni-picker-container .uni-picker-content {
position: relative;
display: block;
width: 100%;
......@@ -388,7 +487,7 @@ uni-picker .uni-picker-content {
background-color: white;
}
uni-picker .uni-picker-item {
.uni-picker-container .uni-picker-item {
padding: 0;
height: 34px;
line-height: 34px;
......@@ -399,7 +498,7 @@ uni-picker .uni-picker-item {
overflow: hidden;
}
uni-picker .uni-picker-header {
.uni-picker-container .uni-picker-header {
display: block;
position: relative;
text-align: center;
......@@ -408,7 +507,7 @@ uni-picker .uni-picker-header {
background-color: #fff;
}
uni-picker .uni-picker-header:after {
.uni-picker-container .uni-picker-header:after {
content: "";
position: absolute;
left: 0;
......@@ -422,7 +521,7 @@ uni-picker .uni-picker-header:after {
transform: scaleY(0.5);
}
uni-picker .uni-picker-action {
.uni-picker-container .uni-picker-action {
display: block;
max-width: 50%;
top: 0;
......@@ -434,12 +533,12 @@ uni-picker .uni-picker-action {
overflow: hidden;
}
uni-picker .uni-picker-action.uni-picker-action-cancel {
.uni-picker-container .uni-picker-action.uni-picker-action-cancel {
float: left;
color: #888;
}
uni-picker .uni-picker-action.uni-picker-action-confirm {
.uni-picker-container .uni-picker-action.uni-picker-action-confirm {
float: right;
color: #007aff;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册