Commit 63c1508e authored by JingChao's avatar JingChao

修复问题

parent 0ce9e464
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
<!-- safari私有meta标签 允许全屏模式浏览 指定safari顶部状态栏样式(黑色) --> <!-- safari私有meta标签 允许全屏模式浏览 指定safari顶部状态栏样式(黑色) -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black">
<script type="text/javascript" src="./static/vuePlatform.js"></script>
<script type="text/javascript" src="../../cordova.js"></script>
<title>车租易</title> <title>车租易</title>
</head> </head>
<body> <body>
......
...@@ -50,3 +50,73 @@ export function detectOS () { ...@@ -50,3 +50,73 @@ export function detectOS () {
return 'other' return 'other'
} }
} }
export function range (num, min, max) {
return Math.min(Math.max(num, min), max)
}
function trimExtraChar (value, char, regExp) {
const index = value.indexOf(char)
if (index === -1) {
return value
}
if (char === '-' && index !== 0) {
return value.slice(0, index)
}
return value.slice(0, index + 1) + value.slice(index).replace(regExp, '')
}
export function formatNumber (value, allowDot) {
if (value) {
if (allowDot) {
value = trimExtraChar(value, '.', /\./g)
} else {
value = value.split('.')[0]
}
value = trimExtraChar(value, '-', /-/g)
const regExp = allowDot ? /[^-0-9.]/g : /[^-0-9]/g
return value.replace(regExp, '')
}
}
export function isDef (val) {
return val !== undefined && val !== null && val !== ''
}
export function isUndefined (value) {
return Object.prototype.toString.call(value) === '[object Undefined]'
}
export function isString (value) {
return Object.prototype.toString.call(value) === '[object String]'
}
export function isNumber (value) {
return Object.prototype.toString.call(value) === '[object Number]'
}
export function isBoolean (value) {
return Object.prototype.toString.call(value) === '[object Boolean]'
}
export function isNull (value) {
return Object.prototype.toString.call(value) === '[object Null]'
}
export function isObject (value) {
return Object.prototype.toString.call(value) === '[object Object]'
}
export function isFunction (value) {
return Object.prototype.toString.call(value) === '[object Function]'
}
export function isArray (value) {
return Object.prototype.toString.call(value) === '[object Array]'
}
export function isDate (value) {
return Object.prototype.toString.call(value) === '[object Date]'
}
export function isRegExp (value) {
return Object.prototype.toString.call(value) === '[object RegExp]'
}
...@@ -20,6 +20,7 @@ curreny-input 金额输入框 ...@@ -20,6 +20,7 @@ curreny-input 金额输入框
``` ```
v-model 绑定value值 number值 v-model 绑定value值 number值
disable 是否只读 true/false disable 是否只读 true/false
...@@ -5,19 +5,31 @@ ...@@ -5,19 +5,31 @@
<template> <template>
<input <input
:value="formatValue" :readonly="disable" type="text" ref="currencyInput"
v-bind="$attrs"
:value="formatValue" :readonly="readonly" :disabled="disabled" type="text"
@input="onInput($event.target.value)" @focus="onFocus" @blur="onBlur"> @input="onInput($event.target.value)" @focus="onFocus" @blur="onBlur">
</template> </template>
<script> <script>
import {formatNumber} from '../../../packages/common/utils'
export default { export default {
name: 'CurrencyInput', name: 'CurrencyInput',
inheritAttrs: false,
props: { props: {
value: { value: {
type: Number, type: Number | String,
default: 0, default: 0,
}, },
disable: { decimal: {
type: Boolean,
default: true,
},
disabled: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
...@@ -35,9 +47,16 @@ export default { ...@@ -35,9 +47,16 @@ export default {
}, },
}, },
computed: { computed: {
inputMode () {
if (this.decimal) {
return 'decimal'
} else {
return 'numeric'
}
},
formatValue () { formatValue () {
let currency = this.$options.filters['currency'] let currency = this.$options.filters['currency']
if (!this.focused) { if (!this.focused && this.value) {
return currency(this.value) return currency(this.value)
} else { } else {
return this.value return this.value
...@@ -46,19 +65,42 @@ export default { ...@@ -46,19 +65,42 @@ export default {
}, },
methods: { methods: {
onInput: function (value) { onInput: function (value) {
const allowDot = this.decimal
value = formatNumber(value, allowDot)
const { currencyInput } = this.$refs
if (currencyInput && value !== currencyInput.value) {
currencyInput.value = value
}
let uncurrency = this.$options.filter['uncurrency'] let uncurrency = this.$options.filter['uncurrency']
this.currencyValue = uncurrency(value) this.currencyValue = uncurrency(value)
this.$emit('input', this.currencyValue) this.$emit('input', this.currencyValue)
}, },
onFocus (event) { onFocus (event) {
if (this.readonly || this.disabled) {
if (this.$refs.currencyInput) {
this.$refs.currencyInput.blur()
this.focused = false
}
} else {
this.focused = true this.focused = true
if (this.decimal) {
setTimeout(function () { setTimeout(function () {
event.target.type = 'number' event.target.type = 'text'
event.target.inputMode = 'decimal'
event.target.focus() event.target.focus()
}, 0) }, 0)
} else {
setTimeout(function () {
event.target.type = 'tel'
event.target.inputMode = 'numeric'
event.target.focus()
}, 0)
}
}
}, },
onBlur (event) { onBlur (event) {
event.target.type = 'text' event.target.type = 'text'
event.target.inputMode = ''
this.focused = false this.focused = false
}, },
}, },
......
/**
* @Author think
* @Date 2020-07-30 09:34
*/
<template>
<div :style="{'min-height':minHeight}" :class="{'h-field-disabled':disabled}" class="h-field h-date">
<div v-if="showLeftIcon" class="field-icon field-left-icon" @click="onClickLeftIcon">
<img v-if="!hasLeftIcon" :src="leftIcon">
<slot name="left-icon"/>
</div>
<div v-if="label" :class="{'required': required}" :style="{'flex':proportion[0] }" class="field-title field-label">
<span>{{ label }}</span>
</div>
<div :style="{'flex':proportion[1] }" class="field-value">
<div class="field-body">
<input
v-bind="$attrs"
v-model="value"
:disabled="disabled" :placeholder="dataPlaceholder" :class="('field-control-'+inputAlign)" class="field-control"
type="text" readonly
@click="showDate">
<!--<slot name="icon"/>-->
<i v-if="showClean" class="field-icon field-right-icon icon ion-close-circled" @click="cleanValue"/>
<!--<slot name="icon"/>-->
<img v-if="!showClean" :src="rightIcon" class="field-right-icon date-field-icon" >
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DateField',
inheritAttrs: false,
props: {
value: {
default: null,
type: String | Date,
},
placeholder: {
type: String,
default: null,
},
clearable: {
type: Boolean,
default: true,
},
format: {
default: 'YYYY-MM-DD',
type: String,
},
minYear: {
type: String,
default: '1800',
},
maxYear: {
type: String,
default: '2500',
},
disabled: {
type: Boolean,
default: false,
},
label: {
type: String,
default: '',
required: true,
},
required: {
type: Boolean,
default: false,
},
inputAlign: {
type: String,
default: 'right',
},
proportion: {
// name/content 横向面积比例
type: Array,
default: () => [1, 2],
},
itemHeight: {
type: Number,
default: 45,
},
showIcon: {
type: Boolean,
default: true,
},
leftIcon: {
type: String,
default: null,
},
rightIcon: {
type: String,
default: require('./right-gray@2x.png'),
},
},
data () {
return {
}
},
computed: {
minHeight () {
if (this.$parent.itemHeight) {
return this.$parent.itemHeight + 'px'
} else {
return this.itemHeight + 'px'
}
},
hasLeftIcon () {
return !!this.$slots['left-icon']
},
showLeftIcon () {
return !!(this.leftIcon || this.$slots['left-icon'])
},
dataPlaceholder () {
return this.placeholder ? this.placeholder : '请输入' + this.label
},
showClean () {
let vm = this
if (vm.disabled) {
return false
}
if (vm.clearable && (vm.value !== '' && vm.value !== undefined && vm.value !== null)) {
return true
} else {
return !vm.showIcon
}
},
},
methods: {
cleanValue () {
this.$emit('input', null)
this.$emit('clean', null)
},
showDate () {
let vm = this
if (!vm.disabled) {
let date = new Date().format('yyyy-MM-dd')
if (vm.value) {
date = vm.value
}
vm.$vux.datetime.show({
cancelText: '取消',
confirmText: '确定',
minYear: vm.minYear,
maxYear: vm.maxYear,
format: vm.format,
value: date,
onConfirm (val) {
vm.$emit('input', val)
vm.$emit('onSelect', val)
},
})
}
},
},
}
</script>
<style lang="less">
.h-date{
background-color: #fff;
position: relative;
.field-value{
.date-field-icon{
height: 0.25rem;
}
}
}
</style>
/**
* @Author think
* @Date 2020-07-30 09:34
*/
<template>
<section :style="{'min-height':minHeight}" class="h-date">
<section :style="{'min-height':minHeight}" :class="{'vue-1px-b':hasBorder}" class="date-border">
<section :class="{'required':required}" :style="{'flex':proportion[0] }" class="name">{{ label }}</section>
<section :style="{'flex':proportion[1] }" class="date-content">
<input
v-model="value" :disabled="disabled" :placeholder="dataPlaceholder" type="text"
readonly
@click="showDate">
<!--<slot name="icon"/>-->
<i v-if="showClean" class="icon ion-close-circled" @click="cleanValue"/>
<!--<slot name="icon"/>-->
<img v-if="!showClean" :src="selectIcon" class="icon" >
</section>
</section>
</section>
</template>
<script>
export default {
name: 'DateFiled',
props: {
value: {
default: null,
type: String | Date,
},
placeholder: {
type: String,
default: null,
},
clearable: {
type: Boolean,
default: false,
},
format: {
default: 'YYYY-MM-DD',
type: String,
},
minYear: {
type: String,
default: '1800',
},
maxYear: {
type: String,
default: '2500',
},
disabled: {
type: Boolean,
default: false,
},
label: {
type: String,
default: '',
required: true,
},
required: {
type: Boolean,
default: false,
},
proportion: {
// name/content 横向面积比例
type: Array,
default: () => [1, 2],
},
itemHeight: {
type: Number,
default: 45,
},
hasBorder: {
type: Boolean,
default: true,
},
showIcon: {
type: Boolean,
default: true,
},
rightIcon: {
type: String,
default: '',
},
},
data () {
return {
Icon: require('./right-gray@2x.png'),
}
},
computed: {
minHeight () {
if (this.$parent.itemHeight) {
return this.$parent.itemHeight + 'px'
} else {
return this.itemHeight + 'px'
}
},
selectIcon () {
return this.rightIcon ? this.rightIcon : this.Icon
},
dataPlaceholder () {
return this.placeholder ? this.placeholder : '请输入' + this.label
},
showClean () {
let vm = this
if (vm.clearable && (vm.value !== '' && vm.value !== undefined && vm.value !== null)) {
return true
} else {
return !vm.showIcon
}
},
},
methods: {
cleanValue () {
this.$emit('input', null)
this.$emit('clean', null)
},
showDate () {
let vm = this
if (!vm.disabled) {
let date = new Date().format('yyyy-MM-dd')
if (vm.value) {
date = vm.value
}
vm.$vux.datetime.show({
cancelText: '取消',
confirmText: '确定',
minYear: vm.minYear,
maxYear: vm.maxYear,
format: vm.format,
value: date,
onConfirm (val) {
vm.$emit('input', val)
vm.$emit('onSelect', val)
},
})
}
},
},
}
</script>
<style lang="less">
.h-date{
width: 100%;
display: flex;
align-items: center;
border: none;
padding: 0 0 0 0.3rem;
background-color: #fff;
.date-border{
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 0.3rem 0 0;
min-height: 45px;
}
.name{
line-height: 0.5rem;
font-size: 14px;
color: #333;
}
.required {
display: flex;
align-items: center;
}
.required::after {
content: '*';
color: #D24E4E;
//height: 0.16rem;
padding-top: 0.08rem;
margin-left: 0.05rem;
}
.date-content{
height: 100%;
width: 100%;
font-size: 14px;
color: #666;
display: flex;
align-items: center;
input{
font-size: 14px;
color: #666;
line-height: 0.4rem;
width: 100%;
text-align: right;
border: none;
}
.icon{
height: 0.25rem;
margin-left: 4px
}
}
}
</style>
Field 输入框
```html
<h-field v-model="number" label="金额"/>
<h-field
v-model="number" format type="number"
clearable error
required label="金额"/>
<h-field
v-model="name"
clearable
required label="姓名"/>
<h-field
v-model="age"
:decimal="false"
type="number"
clearable error
required label="年龄"/>
<h-field
v-model="phone" :left-icon="leftIcon"
type="tel"
required label="手机号"/>
<h-field
v-model="password"
type="password"
required label="密码">
<i slot="left-icon" class="field-icon field-right-icon icon ion-close-circled"/>
</h-field>
<h-field
v-model="address" :autosize="true"
type="textarea"
inputAlign="left"
rows="1"
error
required label="通讯地址"/>
<h-field
v-model="homeAddress"
:autosize="true"
:word-limit="true" type="textarea" maxlength="50"
inputAlign="left"
clearable error
required label="家庭地址"/>
```
|字段名称 |字段说明 |类型 |必填 |默认 |
| ----|------|-------|------|------|
|value|当前值|String|Y|-|
|type|输入类型|String|N|text|
|decimal|是否支持小数(type=number有效)|Boolean|N|false|
|proportion|label与value比例|Array|N|[1,2]|
|required|是否必填|Boolean|N|false|
|readonly|只读属性|Boolean|N|false|
|disabled|禁用属性|Boolean|N|false|
|itemHeight|字端默认高度|Number|N|45|
|label|输入框左侧文本|String|Y|-|
|leftIcon|左侧图标名称或图片链接|String|N|-|
|rightIcon|右侧图标名称或图片链接|String|N|-|
|clearable|是否启用清除图标,点击清除图标后会清空输入框|Boolean|false|-|
|clearTrigger|显示清除图标的时机,always 表示输入框不为空时展示,focus 表示输入框聚焦且不为空时展示|String|N|focus|
|format|是否启用金额千分位化(type=number有效)|Boolean|false|-|
|maxlength|输入的最大字符数|Number,String|false|-|
|inputAlign|输入框对齐方式,可选值为 center left|String|false|right|
|placeholder|输入框默认提示|String|N|请输入+label|
|showPlaceholder|是否显示placeholder|Boolean|N|true|
|error|必输校验后输入框标红|Boolean|N|false|
|autosize|是否自适应内容高度,只对 textarea 有效,可传入对象,如 { maxHeight: 100, minHeight: 50 },单位为px|Boolean,Object|N|-|
|wordLimit|是否显示字数统计,需要设置maxlength属性|Boolean|N|false|
This diff is collapsed.
...@@ -101,7 +101,7 @@ export default { ...@@ -101,7 +101,7 @@ export default {
this.$refs.input.value = '' this.$refs.input.value = ''
} }
}, },
change ($event) { change (event) {
let vm = this let vm = this
let { files } = event.target let { files } = event.target
if (vm.disabled || !files.length) { if (vm.disabled || !files.length) {
...@@ -124,13 +124,11 @@ export default { ...@@ -124,13 +124,11 @@ export default {
.catch(vm.resetInput) .catch(vm.resetInput)
} }
} }
vm.fileRead(files) vm.fileRead(toArray(files))
}, },
fileRead (files) { fileRead (files) {
const oversize = isOversize(files, this.maxSize) const oversizeFiles = isOversize(files, this.maxSize)
if (oversize) {
files = files.filter(file => file.size <= this.maxSize)
}
if (Array.isArray(files)) { if (Array.isArray(files)) {
const maxCount = this.maxCount - this.fileList.length const maxCount = this.maxCount - this.fileList.length
...@@ -144,17 +142,18 @@ export default { ...@@ -144,17 +142,18 @@ export default {
content: contents[index], content: contents[index],
})) }))
this.onAfterRead(fileList, oversize) this.onAfterRead(fileList, oversizeFiles)
}) })
} else { } else {
readFile(files, this.resultType).then(content => { readFile(files, this.resultType).then(content => {
this.onAfterRead({ file: files, content: content }, oversize) this.onAfterRead({ file: files, content: content }, oversizeFiles)
}) })
} }
}, },
onAfterRead (files, oversize) { onAfterRead (files, oversizeFiles) {
if (oversize) { if (oversizeFiles.length) {
this.$emit('oversize', toArray(files)) this.$emit('oversize', toArray(oversizeFiles))
files = files.filter(file => file.size <= this.maxSize)
// return // return
} }
this.resetInput() this.resetInput()
......
...@@ -23,7 +23,7 @@ export function readFile (file, resultType) { ...@@ -23,7 +23,7 @@ export function readFile (file, resultType) {
} }
export function isOversize (files, maxSize) { export function isOversize (files, maxSize) {
return toArray(files).some(file => file.size > maxSize) return toArray(files).filter(file => file.size > maxSize)
} }
export function isImageDataUrl (dataUrl) { export function isImageDataUrl (dataUrl) {
......
/** /**
* @Author Think * @Author Think
* @Date 2018/11/24 * @Date 2018/11/24
*/ */
<template> <template>
<div :class="{'h-ios': isIos}" class="h-view"> <div :class="{'h-ios': isIos}" class="h-view">
<slot /> <slot/>
</div> </div>
</template> </template>
...@@ -42,39 +42,48 @@ export default { ...@@ -42,39 +42,48 @@ export default {
}, },
created () { created () {
this.fullScreen && detectOS() === 'ios' && (this.isIos = true) this.fullScreen && detectOS() === 'ios' && (this.isIos = true)
document.body.classList.add('platform-' + detectOS())
}, },
} }
</script> </script>
<style lang="less" scoped> <style lang="less">
.h-view { ::selection {
background: #3367d6;
color: #fff;
}
input:hover ,input:focus{
caret-color: #3367d6;
}
.h-view {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
// padding-bottom: 44px; // padding-bottom: 44px;
// background-color: $bgColor; // background-color: $bgColor;
} }
.platform-ios{
.h-view{ .platform-ios {
.h-view {
// padding-bottom: 64px; // padding-bottom: 64px;
} }
} }
// iPhoneX适配 // iPhoneX适配
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) { @media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
.platform-ios { .platform-ios {
.h-view { .h-view {
// padding-bottom: 120px; // padding-bottom: 120px;
} }
} }
} }
// iPhoneX Max适配 // iPhoneX Max适配
@media only screen and (device-width: 414px) and (device-height: 896px) { @media only screen and (device-width: 414px) and (device-height: 896px) {
.platform-ios { .platform-ios {
.h-view { .h-view {
// padding-bottom: 120px; // padding-bottom: 120px;
} }
} }
} }
</style> </style>
<template> <template>
<div :class="type" class="function">{{ text }}</div> <div :class="type" class="function" @click="itemClick">{{ text }}</div>
</template> </template>
<script> <script>
...@@ -22,8 +22,8 @@ export default { ...@@ -22,8 +22,8 @@ export default {
this.$parent && this.$parent.optionItem.splice(this.$parent.optionItem.indexOf(this), 1) this.$parent && this.$parent.optionItem.splice(this.$parent.optionItem.indexOf(this), 1)
}, },
methods: { methods: {
buttonClick (e) { itemClick (e) {
this.$emit('press', this.type) this.$parent && this.$parent.reset()
}, },
}, },
} }
......
<template> <template>
<div :class="cusClass" class="swipeout-list"> <div :class="cusClass" class="swipeout-list">
<div ref="item" :class="bottomBorder" class="item" data-type="0"> <div ref="optionItem" :class="bottomBorder" class="option-item" data-type="0">
<div <div
class="list-box" class="list-box"
@touchstart.capture="touchStart" @touchstart.capture="touchStart"
...@@ -62,7 +62,7 @@ export default { ...@@ -62,7 +62,7 @@ export default {
}, },
methods: { methods: {
touchStart (ev) { touchStart (ev) {
this.$refs.item.style.transform = 'translate3d(0px,0px,0px)' this.$refs.optionItem.style.transform = 'translate3d(0px,0px,0px)'
this.reset() this.reset()
ev = ev || event ev = ev || event
// tounches类数组,等于1时表示此时有只有一只手指在触摸屏幕 // tounches类数组,等于1时表示此时有只有一只手指在触摸屏幕
...@@ -88,7 +88,7 @@ export default { ...@@ -88,7 +88,7 @@ export default {
}, },
// 判断当前是否有滑块处于滑动状态 // 判断当前是否有滑块处于滑动状态
checkSlide () { checkSlide () {
let listItems = this.$refs.item let listItems = this.$refs.optionItem
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
if (listItems[i].dataset.type === '1') { if (listItems[i].dataset.type === '1') {
return true return true
...@@ -106,10 +106,10 @@ export default { ...@@ -106,10 +106,10 @@ export default {
}) })
}, },
reset () { reset () {
let l = document.getElementsByClassName('item').length let l = document.getElementsByClassName('option-item').length
for (let i = 0; i < l; i++) { for (let i = 0; i < l; i++) {
document.getElementsByClassName('item')[i].style.transform = 'translate3d(0px,0px,0px)' document.getElementsByClassName('option-item')[i].style.transform = 'translate3d(0px,0px,0px)'
document.getElementsByClassName('item')[i].dataset.type = '0' document.getElementsByClassName('option-item')[i].dataset.type = '0'
} }
}, },
}, },
...@@ -124,14 +124,14 @@ export default { ...@@ -124,14 +124,14 @@ export default {
overflow: visible; overflow: visible;
padding: 0 0 0 15px; padding: 0 0 0 15px;
width: 100%; width: 100%;
.item[data-type="0"] { .option-item[data-type="0"] {
transform: translate3d(0px, 0px, 0px); transform: translate3d(0px, 0px, 0px);
transition: all 0.4s; transition: all 0.4s;
} }
.item[data-type="1"] { .option-item[data-type="1"] {
transition: all 1s; transition: all 1s;
} }
.item { .option-item {
overflow: visible; overflow: visible;
position: relative; position: relative;
height: 100%; height: 100%;
......
<template> <template>
<div <div
:class="[showActivated,focus]" :class="[showActivated,cusClass]"
:style="{'min-height':minHeight}" :style="{'min-height':minHeight}"
class="hls-item"> class="hls-item">
<div <div
...@@ -11,14 +11,12 @@ ...@@ -11,14 +11,12 @@
@touchcancel="end" @touchcancel="end"
@mousedown="start" @mousedown="start"
@mouseup="end" @mouseup="end"
@mouseleave="end" @mouseleave="end">
@focusin="focusin" <div v-if="showName && hasName" :style="{'min-height':minHeight,'flex':proportion[0] }" class="add-name">
@focusout="focusout">
<div v-if="showName" :style="{'min-height':minHeight,'flex':proportion[0] }" class="add-name">
<slot name="left-icon"/> <slot name="left-icon"/>
<slot name="name"/> <slot name="name"/>
</div> </div>
<div v-if="showContent" :style="{'min-height':minHeight,'flex':proportion[1] }" class="add-content"> <div v-if="showContent && hasContent" :style="{'min-height':minHeight,'flex':proportion[1] }" class="add-content">
<slot name="content"/> <slot name="content"/>
<slot name="right-icon"/> <slot name="right-icon"/>
<img v-if="showArrow" :src="rightIcon" class="right-icon" style="height: 0.2rem"> <img v-if="showArrow" :src="rightIcon" class="right-icon" style="height: 0.2rem">
...@@ -55,6 +53,10 @@ export default { ...@@ -55,6 +53,10 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
cusClass: {
type: String,
default: '',
},
hasBorder: { hasBorder: {
type: Boolean, type: Boolean,
default: true, default: true,
...@@ -67,7 +69,6 @@ export default { ...@@ -67,7 +69,6 @@ export default {
data () { data () {
return { return {
showActivated: '', showActivated: '',
focus: '',
hasTouchEvent: 'ontouchstart' in document, hasTouchEvent: 'ontouchstart' in document,
Icon: require('./right-gray@2x.png'), Icon: require('./right-gray@2x.png'),
} }
...@@ -82,6 +83,12 @@ export default { ...@@ -82,6 +83,12 @@ export default {
bottomBorder () { bottomBorder () {
return this.hasBorder ? 'vue-1px-b' : '' return this.hasBorder ? 'vue-1px-b' : ''
}, },
hasName () {
return !!this.$slots['name'] || !!this.$slots['left-icon']
},
hasContent () {
return !!this.$slots['content'] || !!this.$slots['right-icon']
},
}, },
mounted () { mounted () {
}, },
...@@ -90,12 +97,6 @@ export default { ...@@ -90,12 +97,6 @@ export default {
// 移动浏览器中长按元素会触发显示菜单,导致touchend事件不会触发,需要阻止该行为 // 移动浏览器中长按元素会触发显示菜单,导致touchend事件不会触发,需要阻止该行为
e.preventDefault() e.preventDefault()
}, },
focusin (e) {
this.focus = 'focus'
},
focusout (e) {
this.focus = ''
},
start (e) { start (e) {
if (e.target.readOnly) return if (e.target.readOnly) return
if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' || e.target.nodeName === 'BUTTON' || e.target.nodeName === 'LABEL') return if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' || e.target.nodeName === 'BUTTON' || e.target.nodeName === 'LABEL') return
...@@ -157,15 +158,15 @@ export default { ...@@ -157,15 +158,15 @@ export default {
} }
.required { .required {
display: flex; position: relative;
} }
.required::after { .required::before {
content: '*'; position: absolute;
left: -8px;
color: #D24E4E; color: #D24E4E;
height: 8px; font-size: 14px;
padding-top: 2px; content: '*';
margin-left: 2px;
} }
} }
......
...@@ -20,7 +20,10 @@ export default { ...@@ -20,7 +20,10 @@ export default {
cusClass: { cusClass: {
type: String, type: String,
default: '', default: '',
},
showFocusBorder: {
type: Boolean,
default: false,
}, },
}, },
data () { data () {
......
...@@ -34,6 +34,10 @@ export default { ...@@ -34,6 +34,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
showBottomBorder: {
type: Boolean,
default: false,
},
overflowX: { overflowX: {
type: Boolean, type: Boolean,
default: true, default: true,
...@@ -83,7 +87,7 @@ export default { ...@@ -83,7 +87,7 @@ export default {
throw 'tab index out of bound exception' throw 'tab index out of bound exception'
} else { } else {
this.defaultActive === value this.defaultActive === value
this.setTabActive(value) // this.setTabActive(value)
} }
}, },
}, },
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<section :class="[tabClass]" class="h-tab-item" @click="titleClick"> <section :class="[tabClass]" class="h-tab-item" @click="titleClick">
<div class="h-item"> <div class="h-item">
<slot/> <slot/>
<div class="bottom-border"/> <div v-if="showBottomBorder" class="bottom-border"/>
</div> </div>
<div v-show="showDivider" class="tab-divider"/> <div v-show="showDivider" class="tab-divider"/>
</section> </section>
...@@ -21,6 +21,9 @@ export default { ...@@ -21,6 +21,9 @@ export default {
showDivider () { showDivider () {
return this.$parent.showDivider return this.$parent.showDivider
}, },
showBottomBorder () {
return this.$parent.showBottomBorder
},
tabClass () { tabClass () {
if (this.$parent.hasBorder) { if (this.$parent.hasBorder) {
return this.$parent.position === 'top' ? 'vue-1px-b' : 'vue-1px-t' return this.$parent.position === 'top' ? 'vue-1px-b' : 'vue-1px-t'
......
...@@ -13,7 +13,7 @@ export default { ...@@ -13,7 +13,7 @@ export default {
data () { data () {
return { return {
width: 50, width: 50,
height: 80, height: 60,
} }
}, },
computed: { computed: {
...@@ -33,10 +33,10 @@ export default { ...@@ -33,10 +33,10 @@ export default {
this.ratio = 1 this.ratio = 1
this.width *= this.ratio this.width *= this.ratio
this.height *= this.ratio this.height *= this.ratio
this.initRadius = 18 * this.ratio this.initRadius = 11 * this.ratio // 外面阴影
this.minHeadRadius = 12 * this.ratio this.minHeadRadius = 12 * this.ratio
this.minTailRadius = 5 * this.ratio this.minTailRadius = 5 * this.ratio
this.initArrowRadius = 10 * this.ratio this.initArrowRadius = 6 * this.ratio // 里面的刷新
this.minArrowRadius = 6 * this.ratio this.minArrowRadius = 6 * this.ratio
this.arrowWidth = 3 * this.ratio this.arrowWidth = 3 * this.ratio
this.maxDistance = 40 * this.ratio this.maxDistance = 40 * this.ratio
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
:bubbleY="bubbleY" :bubbleY="bubbleY"
name="pulldown" name="pulldown"
> >
<div v-if="pullDown" ref="pulldown" :style="pullDownStyle" :class="c('__pulldown')"> <div
v-if="pullDown" ref="pulldown" :style="pullDownStyle" :class="c('__pulldown')">
<div v-if="pullDownBefore" :class="c('__pulldown__before')"> <div v-if="pullDownBefore" :class="c('__pulldown__before')">
<Bubble :y="bubbleY"/> <Bubble :y="bubbleY"/>
</div> </div>
...@@ -113,8 +114,8 @@ export default { ...@@ -113,8 +114,8 @@ export default {
// 下拉刷新配置 // 下拉刷新配置
type: Object, type: Object,
default: () => ({ default: () => ({
threshold: 90, // 触发 pullingDown 的距离 threshold: 40, // 触发 pullingDown 的距离
stop: 40, // pullingDown 正在刷新 hold 时的距离 stop: 20, // pullingDown 正在刷新 hold 时的距离
txt: '刷新成功', txt: '刷新成功',
}), }),
}, },
...@@ -188,6 +189,9 @@ export default { ...@@ -188,6 +189,9 @@ export default {
bubbleY: 0, // 气泡y坐标, bubbleY: 0, // 气泡y坐标,
isIos: false, isIos: false,
fullScreen: true, fullScreen: true,
fontSize: Number(window.document.documentElement.style.fontSize.replace('px', '')),
winHeight: window.innerHeight,
winWidth: window.innerWidth,
} }
}, },
computed: { computed: {
...@@ -220,7 +224,7 @@ export default { ...@@ -220,7 +224,7 @@ export default {
this.fullScreen && detectOS() === 'ios' && (this.isIos = true) this.fullScreen && detectOS() === 'ios' && (this.isIos = true)
}, },
async mounted () { async mounted () {
this.pullDownInitTop = parseInt(this.$refs.pulldown && getComputedStyle(this.$refs.pulldown).top) || -100 this.pullDownInitTop = parseInt(this.$refs.pulldown && getComputedStyle(this.$refs.pulldown).top) || -60
await this.$nextTick() await this.$nextTick()
this.initScroll() this.initScroll()
...@@ -232,6 +236,60 @@ export default { ...@@ -232,6 +236,60 @@ export default {
}) })
}, },
methods: { methods: {
getHeaderHeight () {
let vm = this
let $el = vm.$el.previousElementSibling
let headerHeight = 0
do {
if ($el) {
let elHeight = window.getComputedStyle($el).height
let part = /^\d+(\.\d+)?px$/
if (elHeight && part.test(elHeight)) {
headerHeight += Number(elHeight.replace('px', ''))
}
if ($el._prevClass && $el._prevClass.indexOf('h-header') === 0) {
if (detectOS() === 'ios' && vm.winWidth === 375 && vm.winHeight === 812) {
headerHeight += 0.8 * vm.fontSize
} else if (detectOS() === 'ios' && vm.winWidth === 414 && vm.winHeight === 896) {
headerHeight += 0.8 * vm.fontSize
} else if (detectOS() === 'ios') {
headerHeight += 0.4 * vm.fontSize
}
}
$el = $el.previousElementSibling
}
} while ($el)
return headerHeight
},
getNextElementHeight () {
let vm = this
let nextElement = this.$el.nextElementSibling
let nextHeight = 0
do {
if (nextElement) {
let elHeight = window.getComputedStyle(nextElement).height
let part = /^\d+(\.\d+)?px$/
if (elHeight && part.test(elHeight)) {
nextHeight += Number(elHeight.replace('px', ''))
}
if (nextElement._prevClass && nextElement._prevClass.indexOf('h-bottom-tab') === 0) {
let height = nextElement.clientHeight
if (detectOS() === 'ios' && height > Math.ceil(vm.fontSize * 0.88)) {
nextHeight += 0
} else {
if (detectOS() === 'ios' && vm.winWidth === 375 && vm.winHeight === 812) {
nextHeight += vm.fontSize * 0.68
} else if (detectOS() === 'ios' && vm.winWidth === 414 && vm.winHeight === 896) {
nextHeight += vm.fontSize * 0.68
}
}
}
nextElement = nextElement.nextElementSibling
}
} while (nextElement)
return nextHeight
},
// 初始化scroll // 初始化scroll
initScroll () { initScroll () {
let vm = this let vm = this
...@@ -239,7 +297,10 @@ export default { ...@@ -239,7 +297,10 @@ export default {
// 设置scrollContent的最小高,实现高度不足时也有回弹效果 // 设置scrollContent的最小高,实现高度不足时也有回弹效果
if (this.$refs.scrollContent) { if (this.$refs.scrollContent) {
const headerHeight = vm.getHeaderHeight()
// const nextHeight = vm.getNextElementHeight()
this.$refs.scrollContent.style.minHeight = `${this.$refs.scroll.getBoundingClientRect().height + 1}px` this.$refs.scrollContent.style.minHeight = `${this.$refs.scroll.getBoundingClientRect().height + 1}px`
this.$refs.scrollContent.style.paddingTop = `${headerHeight}px`
if (vm.hasFoot.footFlag) { if (vm.hasFoot.footFlag) {
let height = vm.hasFoot.height || 88 let height = vm.hasFoot.height || 88
// this.$refs.scrollContent.style.minHeight = `${this.$refs.scroll.getBoundingClientRect().height - height}px` // this.$refs.scrollContent.style.minHeight = `${this.$refs.scroll.getBoundingClientRect().height - height}px`
...@@ -408,7 +469,8 @@ export default { ...@@ -408,7 +469,8 @@ export default {
width 100% width 100%
overflow hidden !important overflow hidden !important
box-sizing border-box box-sizing border-box
position relative position absolute !important
top 0
height 100% height 100%
&__wrapper { &__wrapper {
...@@ -422,7 +484,7 @@ export default { ...@@ -422,7 +484,7 @@ export default {
text-size-adjust: none; text-size-adjust: none;
-webkit-transform-origin: left top; -webkit-transform-origin: left top;
transform-origin: left top; transform-origin: left top;
padding-bottom: 0.9rem; padding-bottom: 0.4rem;
} }
&__pullup { &__pullup {
...@@ -438,7 +500,7 @@ export default { ...@@ -438,7 +500,7 @@ export default {
&__pulldown { &__pulldown {
position absolute position absolute
left 0 left 0
top -50px; /*no*/ top 0; /*no*/
width 100% width 100%
display flex display flex
justify-content center justify-content center
...@@ -461,20 +523,24 @@ export default { ...@@ -461,20 +523,24 @@ export default {
} }
} }
} }
.has-footer {
.vue-better-scroll__wrapper {
padding-bottom: 1rem;
}
}
.platform-ios{ .platform-ios{
.vue-better-scroll { .has-footer {
&__wrapper { .vue-better-scroll__wrapper {
// padding-bottom: 2.16rem; padding-bottom: 1rem;
} }
} }
} }
// iPhoneX适配 // iPhoneX适配
@media (device-width: 375px) and (device-height: 812px) and (-webkit-min-device-pixel-ratio: 3) { @media (device-width: 375px) and (device-height: 812px) and (-webkit-min-device-pixel-ratio: 3) {
.platform-ios { .platform-ios {
.vue-better-scroll { .has-footer {
&__wrapper { .vue-better-scroll__wrapper {
// padding-bottom: 2.84rem; padding-bottom: 1.8rem;
} }
} }
} }
...@@ -483,9 +549,9 @@ export default { ...@@ -483,9 +549,9 @@ export default {
// iPhoneX Max适配 // iPhoneX Max适配
@media (device-width: 414px) and (device-height: 896px) { @media (device-width: 414px) and (device-height: 896px) {
.platform-ios { .platform-ios {
.vue-better-scroll { .has-footer {
&__wrapper { .vue-better-scroll__wrapper {
// padding-bottom: 2.84rem; padding-bottom: 1.8rem;
} }
} }
} }
......
/**
* @Author think
* @Date 2020-07-30 09:34
*/
<template>
<div :style="{'min-height':minHeight}" :class="{'h-field-disabled':disabled}" class="h-field h-select">
<div v-if="showLeftIcon" class="field-icon field-left-icon" @click="onClickLeftIcon">
<img v-if="!hasLeftIcon" :src="leftIcon">
<slot name="left-icon"/>
</div>
<div v-if="label" :class="{'required': required}" :style="{'flex':proportion[0] }" class="field-title field-label">
<span>{{ label }}</span>
</div>
<div :style="{'flex':proportion[1] }" class="field-value">
<div class="field-body">
<input
v-bind="$attrs"
v-model="codeName" :disabled="disabled" :placeholder="selectPlaceholder" :class="('field-control-'+inputAlign)"
type="text" class="field-control"
readonly
@click="showSelect">
<input v-model="value" type="text" hidden>
<i v-if="showClean" class="field-icon field-right-icon icon ion-close-circled" @click="cleanValue"/>
<!--<slot name="icon"/>-->
<img v-if="!showClean" :src="rightIcon" class="field-right-icon date-field-icon" >
</div>
</div>
</div>
<!--</section>-->
</template>
<script>
import VueSelect from './index'
export default {
name: 'SelectField',
inheritAttrs: false,
props: {
value: {
default: null,
type: Number | String,
},
placeholder: {
type: String,
default: null,
},
clearable: {
type: Boolean,
default: true,
},
dataArray: {
type: Array,
default: () => [],
},
multiple: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
valueKey: {
type: String,
default: 'code',
},
valueName: {
type: String,
default: 'code_name',
},
code: {
type: String,
default: 'code',
},
object: {
type: Object,
default: () => {},
},
label: {
type: String,
default: '',
},
required: {
type: Boolean,
default: false,
},
proportion: {
// name/content 横向面积比例
type: Array,
default: () => [1, 2],
},
itemHeight: {
type: Number,
default: 45,
},
inputAlign: {
type: String,
default: 'right',
},
showIcon: {
type: Boolean,
default: true,
},
leftIcon: {
type: String,
default: null,
},
rightIcon: {
type: String,
default: require('./right-gray@2x.png'),
},
},
data () {
return {
}
},
computed: {
hasLeftIcon () {
return !!this.$slots['left-icon']
},
showLeftIcon () {
return !!(this.leftIcon || this.$slots['left-icon'])
},
codeName () {
let vm = this
let name
if (vm.multiple) {
name = []
if (Array.isArray(vm.value)) {
vm.dataArray.forEach((selectItem, listIndex, listArray) => {
vm.value.forEach((index, item, array) => {
if (selectItem[vm.valueKey] === item) {
name.push(selectItem[vm.valueName])
}
})
})
} else {
console.error('multiple select value must be Array')
}
} else {
vm.dataArray.forEach((selectItem, listIndex, listArray) => {
// eslint-disable-next-line eqeqeq
if (selectItem[vm.valueKey] == vm.value) {
name = selectItem[vm.valueName]
}
})
}
return name
},
showClean () {
let vm = this
if (vm.disabled) {
return false
}
if (vm.clearable && (vm.value !== '' && vm.value !== undefined && vm.value !== null)) {
return true
} else {
return !vm.showIcon
}
},
minHeight () {
if (this.$parent.itemHeight) {
return this.$parent.itemHeight + 'px'
} else {
return this.itemHeight + 'px'
}
},
selectPlaceholder () {
return this.placeholder ? this.placeholder : '请选择' + this.label
},
},
methods: {
selectCall (v1, v2, v3) {
let vm = this
if (!vm.multiple) {
this.$emit('input', v2[vm.code])
this.$emit('onSelect', v1, v2, v3)
} else {
this.$emit('input', v1)
this.$emit('onSelect', v1, v2)
}
},
cleanValue () {
this.$emit('input', null)
this.$emit('clean', null)
},
showSelect () {
let vm = this
if (!vm.disabled) {
let list = []
vm.dataArray.forEach((date, index, array) => {
list.push({
value: date[vm.valueKey],
name: date[vm.valueName],
parent: date.parent,
})
})
VueSelect.show({
list: list,
callBack: vm.selectCall,
code: vm.code,
object: vm.object || {},
multiple: vm.multiple,
})
}
},
},
}
</script>
<style lang="less">
.h-select{
background-color: #fff;
position: relative;
.field-value{
.date-field-icon{
height: 0.25rem;
}
}
}
</style>
/**
* @Author think
* @Date 2020-07-30 09:34
*/
<template>
<section :style="{'min-height':minHeight}" class="h-select">
<section :style="{'min-height':minHeight}" :class="{'vue-1px-b':hasBorder}" class="select-border">
<section :class="{'required':required}" :style="{'flex':proportion[0] }" class="name">{{ label }}</section>
<section :style="{'flex':proportion[1] }" class="select-content">
<input
v-model="codeName" :disabled="disabled" :placeholder="selectPlaceholder" type="text"
readonly
@click="showSelect">
<input v-model="value" type="text" hidden>
<i v-if="showClean" class="icon ion-close-circled" @click="cleanValue"/>
<!--<slot name="icon"/>-->
<img v-if="!showClean" :src="selectIcon" class="icon" >
</section>
</section>
</section>
</template>
<script>
import VueSelect from './index'
export default {
name: 'SelectFiled',
props: {
value: {
default: null,
type: Number | String,
},
placeholder: {
type: String,
default: null,
},
clearable: {
type: Boolean,
default: false,
},
dataArray: {
type: Array,
default: () => [],
},
multiple: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
valueKey: {
type: String,
default: 'code',
},
valueName: {
type: String,
default: 'code_name',
},
code: {
type: String,
default: 'code',
},
object: {
type: Object,
default: () => {},
},
label: {
type: String,
default: '',
},
required: {
type: Boolean,
default: false,
},
proportion: {
// name/content 横向面积比例
type: Array,
default: () => [1, 2],
},
itemHeight: {
type: Number,
default: 45,
},
hasBorder: {
type: Boolean,
default: true,
},
showIcon: {
type: Boolean,
default: true,
},
rightIcon: {
type: String,
default: '',
},
},
data () {
return {
Icon: require('./right-gray@2x.png'),
}
},
computed: {
codeName () {
let vm = this
let name
if (vm.multiple) {
name = []
if (Array.isArray(vm.value)) {
vm.dataArray.forEach((selectItem, listIndex, listArray) => {
vm.value.forEach((index, item, array) => {
if (selectItem[vm.valueKey] === item) {
name.push(selectItem[vm.valueName])
}
})
})
} else {
console.error('multiple select value must be Array')
}
} else {
vm.dataArray.forEach((selectItem, listIndex, listArray) => {
// eslint-disable-next-line eqeqeq
if (selectItem[vm.valueKey] == vm.value) {
name = selectItem[vm.valueName]
}
})
}
return name
},
showClean () {
let vm = this
if (vm.clearable && (vm.value !== '' && vm.value !== undefined && vm.value !== null)) {
return true
} else {
return !vm.showIcon
}
},
minHeight () {
if (this.$parent.itemHeight) {
return this.$parent.itemHeight + 'px'
} else {
return this.itemHeight + 'px'
}
},
selectIcon () {
return this.rightIcon ? this.rightIcon : this.Icon
},
selectPlaceholder () {
return this.placeholder ? this.placeholder : '请选择' + this.label
},
},
methods: {
selectCall (v1, v2, v3) {
let vm = this
if (!vm.multiple) {
this.$emit('input', v2[vm.code])
this.$emit('onSelect', v1, v2, v3)
} else {
this.$emit('input', v1)
this.$emit('onSelect', v1, v2)
}
},
cleanValue () {
this.$emit('input', null)
this.$emit('clean', null)
},
showSelect () {
let vm = this
if (!vm.disabled) {
let list = []
vm.dataArray.forEach((date, index, array) => {
list.push({
value: date[vm.valueKey],
name: date[vm.valueName],
parent: date.parent,
})
})
VueSelect.show({
list: list,
callBack: vm.selectCall,
code: vm.code,
object: vm.object || {},
multiple: vm.multiple,
})
}
},
},
}
</script>
<style lang="less">
.h-select{
width: 100%;
display: flex;
align-items: center;
border: none;
padding: 0 0 0 0.3rem;
background-color: #fff;
.select-border{
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 0.3rem 0 0;
min-height: 45px;
}
.name{
line-height: 0.5rem;
font-size: 14px;
color: #333;
}
.required {
display: flex;
align-items: center;
}
.required::after {
content: '*';
color: #D24E4E;
//height: 0.16rem;
padding-top: 0.08rem;
margin-left: 0.05rem;
}
.select-content{
height: 100%;
width: 100%;
font-size: 14px;
color: #666;
display: flex;
align-items: center;
input{
font-size: 14px;
color: #666;
line-height: 0.4rem;
width: 100%;
text-align: right;
border: none;
}
.icon{
height: 0.25rem;
margin-left: 4px
}
}
}
</style>
...@@ -30,8 +30,9 @@ import HLayout from './HLayout/index' ...@@ -30,8 +30,9 @@ import HLayout from './HLayout/index'
import CurrencyInput from './CurrencyInput/index' import CurrencyInput from './CurrencyInput/index'
import HProgress from './Progress/index' import HProgress from './Progress/index'
import HRange from './Range/index' import HRange from './Range/index'
import SelectFiled from './Select/SelectFiled' import SelectField from './Select/SelectField'
import DateFiled from './DateFiled/index' import DateField from './DateField/index'
import Field from './Field/index'
import errLoadingPic from '../common/picture/errloading.jpg' import errLoadingPic from '../common/picture/errloading.jpg'
...@@ -70,6 +71,7 @@ export default (Vue) => { ...@@ -70,6 +71,7 @@ export default (Vue) => {
Vue.component('currency-input', CurrencyInput) Vue.component('currency-input', CurrencyInput)
Vue.component('h-progress', HProgress) Vue.component('h-progress', HProgress)
Vue.component('h-range', HRange) Vue.component('h-range', HRange)
Vue.component('SelectFiled', SelectFiled) Vue.component('SelectField', SelectField)
Vue.component('DateFiled', DateFiled) Vue.component('DateField', DateField)
Vue.component('h-field', Field)
} }
...@@ -27,8 +27,9 @@ import HLayout from './components/HLayout/index' ...@@ -27,8 +27,9 @@ import HLayout from './components/HLayout/index'
import CurrencyInput from './components/CurrencyInput/index' import CurrencyInput from './components/CurrencyInput/index'
import HProgress from './components/Progress/index' import HProgress from './components/Progress/index'
import HRange from './components/Range/index' import HRange from './components/Range/index'
import SelectFiled from './components/Select/SelectFiled' import SelectField from './components/Select/SelectField'
import DateFiled from './components/DateFiled/index' import DateField from './components/DateField/index'
import Field from './components/Field/index'
import componentInstall from './components/component' import componentInstall from './components/component'
// compontenPlugins // compontenPlugins
...@@ -73,8 +74,9 @@ export { ...@@ -73,8 +74,9 @@ export {
CurrencyInput, CurrencyInput,
HProgress, HProgress,
HRange, HRange,
SelectFiled, SelectField,
DateFiled, DateField,
Field,
ActionSheetPlugin, ActionSheetPlugin,
ShowPicturePlugin, ShowPicturePlugin,
SelectPlugin, SelectPlugin,
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment