parent
6b1f3cd4b2
commit
ecb196dd0d
@ -0,0 +1,167 @@ |
||||
<template> |
||||
<view> |
||||
<slot name="formItem" v-if="$slots.formItem"></slot> |
||||
<view v-else class="evan-form-item-container" :class="'evan-form-item-container--'+mLabelPosition" :style="{borderWidth:border?'1rpx':0}"> |
||||
<view v-if="label" class="evan-form-item-container__label" :class="{showAsteriskRect:hasRequiredAsterisk,isRequired:showRequiredAsterisk}" |
||||
:style="mLabelStyle">{{label}}</view> |
||||
<view class="evan-form-item-container__main" :style="mContentStyle"> |
||||
<slot></slot> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: 'EvanFormItem', |
||||
props: { |
||||
labelStyle: Object, |
||||
label: String, |
||||
contentStyle: { |
||||
type: Object, |
||||
default: () => { |
||||
return {} |
||||
} |
||||
}, |
||||
prop: String, |
||||
border: { |
||||
type: Boolean, |
||||
default: true |
||||
}, |
||||
labelPosition: { |
||||
validator: function(value) { |
||||
if (!value) { |
||||
return true |
||||
} |
||||
return ['top', 'left'].indexOf(value) !== -1 |
||||
}, |
||||
default: '' |
||||
}, |
||||
required: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
message: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
rules: { |
||||
type: [Object, Array], |
||||
default: null |
||||
} |
||||
}, |
||||
inject: ['evanForm'], |
||||
computed: { |
||||
mLabelStyle() { |
||||
const parent = this.getParent() |
||||
let labelStyle = Object.assign({}, (parent.labelStyle || {}), (this.labelStyle || {})) |
||||
let arr = Object.keys(labelStyle).map((key) => `${key}:${labelStyle[key]}`) |
||||
return arr.join(';') |
||||
}, |
||||
mContentStyle() { |
||||
let contentStyle = Object.assign({}, this.contentStyle || {}) |
||||
let arr = Object.keys(contentStyle).map((key) => `${key}:${contentStyle[key]}`) |
||||
return arr.join(';') |
||||
}, |
||||
mLabelPosition() { |
||||
if (this.labelPosition) { |
||||
return this.labelPosition |
||||
} |
||||
const parent = this.getParent() |
||||
if (parent) { |
||||
return parent.labelPosition |
||||
} |
||||
return 'left' |
||||
}, |
||||
// 整个表单是否有*号 |
||||
hasRequiredAsterisk() { |
||||
const parent = this.getParent() |
||||
if (parent) { |
||||
return parent.hasRequiredAsterisk |
||||
} |
||||
return false |
||||
}, |
||||
// 当前formItem是否显示*号 |
||||
showRequiredAsterisk() { |
||||
const parent = this.getParent() |
||||
if (parent && parent.hideRequiredAsterisk) { |
||||
return false |
||||
} |
||||
const rules = this.getRules() |
||||
if (rules && rules.length > 0) { |
||||
if (rules.find((rule) => rule.required === true)) { |
||||
return true |
||||
} |
||||
} |
||||
return this.required |
||||
} |
||||
}, |
||||
methods: { |
||||
// 获取EvanForm组件 |
||||
getParent() { |
||||
return this.evanForm |
||||
}, |
||||
getRules() { |
||||
let form = this.getParent() |
||||
const formRules = form.mRules && form.mRules[this.prop] ? form.mRules[this.prop] : []; |
||||
const selfRules = this.rules |
||||
const requiredRules = this.required ? { |
||||
required: true, |
||||
message: this.message || `${this.label}必填` |
||||
} : [] |
||||
return [].concat(selfRules || formRules || []).concat(requiredRules) |
||||
} |
||||
}, |
||||
created() { |
||||
this.evanForm.$emit('evan.form.addField', this) |
||||
}, |
||||
beforeDestroy() { |
||||
this.evanForm.$emit('evan.form.removeField', this) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.evan-form-item-container { |
||||
border-bottom: 1rpx solid #eee; |
||||
|
||||
&__label { |
||||
font-size: 28rpx; |
||||
color: #666; |
||||
line-height: 40rpx; |
||||
padding: 25rpx 0; |
||||
display: inline-block; |
||||
|
||||
&.showAsteriskRect::before { |
||||
content: ''; |
||||
color: #F56C6C; |
||||
width: 20rpx; |
||||
display: inline-block; |
||||
} |
||||
|
||||
&.isRequired::before { |
||||
content: '*'; |
||||
} |
||||
} |
||||
|
||||
&__main { |
||||
flex: 1; |
||||
min-height: 90rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
&--left { |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: flex-start; |
||||
} |
||||
|
||||
&--top { |
||||
.evan-form-item-container__label { |
||||
padding-bottom: 10rpx; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,168 @@ |
||||
<template> |
||||
<view class="evan-form-container"> |
||||
<slot></slot> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import utils from './utils.js' |
||||
export default { |
||||
name: 'EvanForm', |
||||
props: { |
||||
labelStyle: { |
||||
type: Object, |
||||
default: () => { |
||||
return {} |
||||
} |
||||
}, |
||||
model: Object, |
||||
hideRequiredAsterisk: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
showMessage: { |
||||
type: Boolean, |
||||
default: true |
||||
}, |
||||
labelPosition: { |
||||
validator: function(value) { |
||||
return ['top', 'left'].indexOf(value) !== -1 |
||||
}, |
||||
default: 'left' |
||||
}, |
||||
rules: { |
||||
type: Object, |
||||
default: () => { |
||||
return {} |
||||
} |
||||
} |
||||
}, |
||||
provide() { |
||||
return { |
||||
evanForm: this |
||||
} |
||||
}, |
||||
computed: { |
||||
// 整个form是否有*号,为了保证label对齐,而不是和*号对齐 |
||||
hasRequiredAsterisk() { |
||||
if (this.hideRequiredAsterisk) { |
||||
return false |
||||
} |
||||
if (this.mRules) { |
||||
const values = Object.values(this.mRules) |
||||
if (values && values.length > 0) { |
||||
for (let i = 0; i < values.length; i++) { |
||||
const value = values[i] |
||||
if (Array.isArray(value) && value.length > 0) { |
||||
const requiredItem = value.find((v) => v.required === true) |
||||
if (requiredItem) { |
||||
return true |
||||
} |
||||
} else { |
||||
if (value && value.required) { |
||||
return true |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return this.childHasRequired |
||||
} |
||||
}, |
||||
watch: { |
||||
rules: { |
||||
immediate: true, |
||||
deep: true, |
||||
handler(value) { |
||||
this.mRules = value || {} |
||||
} |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
mRules: {}, |
||||
fields: [], |
||||
childHasRequired: false |
||||
} |
||||
}, |
||||
methods: { |
||||
setRules(rules) { |
||||
this.mRules = rules || {} |
||||
}, |
||||
async validate(callback) { |
||||
const rules = this.getRules() |
||||
if (typeof callback === 'function') { |
||||
utils.validate(this.model, rules, callback, { |
||||
showMessage: this.showMessage |
||||
}) |
||||
} else { |
||||
return await utils.validate(this.model, rules, callback, { |
||||
showMessage: this.showMessage |
||||
}) |
||||
} |
||||
}, |
||||
async validateField(props, callback) { |
||||
const rules = this.getRules() |
||||
if (typeof callback === 'function') { |
||||
utils.validateField(this.model, rules, props, callback, { |
||||
showMessage: this.showMessage |
||||
}) |
||||
} else { |
||||
return await utils.validateField(this.model, rules, props, callback, { |
||||
showMessage: this.showMessage |
||||
}) |
||||
} |
||||
}, |
||||
getRules() { |
||||
const rules = {} |
||||
this.fields.forEach((field) => { |
||||
if (field.prop) { |
||||
const requiredRules = field.required ? { |
||||
required: true, |
||||
message: field.message || `${field.label}必填` |
||||
} : [] |
||||
const formRules = this.mRules && this.mRules[field.prop] ? this.mRules[field.prop] : [] |
||||
rules[field.prop] = [].concat(field.rules || formRules || []).concat(requiredRules) |
||||
} |
||||
}) |
||||
return rules |
||||
} |
||||
}, |
||||
created() { |
||||
this.$on('evan.form.addField', (field) => { |
||||
// 小程序中直接push field报错 |
||||
if (field.prop) { |
||||
this.fields.push({ |
||||
rules: field.rules, |
||||
prop: field.prop, |
||||
required: field.required, |
||||
label: field.label, |
||||
message: field.message, |
||||
_uid: field._uid |
||||
}) |
||||
if (!this.childHasRequired) { |
||||
if (field.required) { |
||||
this.childHasRequired = field.required |
||||
return |
||||
} |
||||
if (field.rules) { |
||||
const fieldRules = [].concat(field.rules) |
||||
fieldRules.forEach((item) => { |
||||
if (item.required) { |
||||
this.childHasRequired = true |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
this.$on('evan.form.removeField', (field) => { |
||||
this.fields.splice(this.fields.findIndex((item) => item._uid === field._uid), 1) |
||||
}) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.evan-form-container {} |
||||
</style> |
@ -0,0 +1,148 @@ |
||||
import AsyncValidator from 'async-validator' |
||||
const utils = { |
||||
validate: (model, rules, callback, options) => { |
||||
const initOptions = { |
||||
showMessage: true |
||||
} |
||||
options = Object.assign({}, initOptions, options || {}) |
||||
let promise = null; |
||||
if (typeof callback !== 'function') { |
||||
promise = new Promise((resolve, reject) => { |
||||
callback = function(valid) { |
||||
valid ? resolve(valid) : reject(valid) |
||||
} |
||||
}) |
||||
} |
||||
// 如果需要验证的fields为空,调用验证时立刻返回callback
|
||||
if (!rules || (Array.isArray(rules) && rules.length === 0) || (typeof rules === 'object' && Object.keys(rules).length === |
||||
0)) { |
||||
callback(true, null); |
||||
if(promise){ |
||||
return promise |
||||
} |
||||
return |
||||
} |
||||
let errors = [] |
||||
const props = Object.keys(rules) |
||||
let count = 0 |
||||
for (let i in props) { |
||||
const prop = props[i] |
||||
const value = utils.getValueByProp(model, prop) |
||||
utils.validateItem(rules, prop, value, (err) => { |
||||
if (err && err.length > 0) { |
||||
errors = errors.concat(err) |
||||
} |
||||
// 处理异步校验,等所有校验都结束时再callback
|
||||
count++ |
||||
if (count === props.length) { |
||||
if (errors.length > 0) { |
||||
if (options.showMessage) { |
||||
utils.showToast(errors[0].message) |
||||
} |
||||
callback(false, errors) |
||||
} else { |
||||
callback(true, null) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
if (promise) { |
||||
return promise |
||||
} |
||||
}, |
||||
validateField: (model, rules, props, callback, options) => { |
||||
const initOptions = { |
||||
showMessage: true |
||||
} |
||||
options = Object.assign({}, initOptions, options || {}) |
||||
let promise = null; |
||||
if (typeof callback !== 'function') { |
||||
promise = new Promise((resolve, reject) => { |
||||
callback = function(valid) { |
||||
valid ? resolve(valid) : reject(valid) |
||||
} |
||||
}) |
||||
} |
||||
props = [].concat(props) |
||||
if (props.length === 0) { |
||||
return |
||||
} |
||||
let errors = [] |
||||
let count = 0 |
||||
for (let i in props) { |
||||
const prop = props[i] |
||||
const value = utils.getValueByProp(model, prop) |
||||
utils.validateItem(rules, prop, value, (err) => { |
||||
if (err && err.length > 0) { |
||||
errors = errors.concat(err) |
||||
} |
||||
// 处理异步校验,等所有校验都结束时再callback
|
||||
count++ |
||||
if (count === props.length) { |
||||
if (errors.length > 0) { |
||||
if (options.showMessage) { |
||||
utils.showToast(errors[0].message) |
||||
} |
||||
callback(false, errors) |
||||
} else { |
||||
callback(true, null) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
if (promise) { |
||||
return promise |
||||
} |
||||
}, |
||||
validateItem(rules, prop, value, callback) { |
||||
if (!rules || JSON.stringify(rules) === '{}') { |
||||
if (callback instanceof Function) { |
||||
callback(); |
||||
} |
||||
return true; |
||||
} |
||||
const propRules = [].concat(rules[prop] || []); |
||||
propRules.forEach((rule) => { |
||||
if (rule.pattern) { |
||||
rule.pattern = new RegExp(rule.pattern) |
||||
} |
||||
}) |
||||
const descriptor = { |
||||
[prop]: propRules |
||||
}; |
||||
const validator = new AsyncValidator(descriptor); |
||||
const model = { |
||||
[prop]: value |
||||
}; |
||||
validator.validate(model, { |
||||
firstFields: true |
||||
}, (errors) => { |
||||
callback(errors); |
||||
}); |
||||
}, |
||||
getValueByProp: (obj, prop) => { |
||||
let tempObj = obj; |
||||
prop = prop.replace(/\[(\w+)\]/g, '.$1').replace(/^\./, ''); |
||||
let keyArr = prop.split('.'); |
||||
let i = 0; |
||||
for (let len = keyArr.length; i < len - 1; ++i) { |
||||
if (!tempObj) break; |
||||
let key = keyArr[i]; |
||||
if (key in tempObj) { |
||||
tempObj = tempObj[key]; |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
return tempObj ? (typeof tempObj[keyArr[i]] === 'string' ? tempObj[keyArr[i]].trim() : tempObj[keyArr[i]]) : |
||||
null |
||||
}, |
||||
showToast: (message) => { |
||||
uni.showToast({ |
||||
title: message, |
||||
icon: 'none' |
||||
}) |
||||
} |
||||
} |
||||
|
||||
export default utils |
@ -0,0 +1,36 @@ |
||||
<template> |
||||
<view> |
||||
<view style="width: 100%; height: 100%; position: absolute; left: 0; tab-size: 0"> |
||||
<map id="maps" ref="maps" :markers="markers" style="width: 100%; height: 100%" @tap="tapMap"></map> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
maps: '1', |
||||
markers: [] |
||||
} |
||||
}, |
||||
methods: { |
||||
tapMap(e) { |
||||
var that = this; |
||||
var id = e.currentTarget.id; |
||||
debugger |
||||
var maps = uni.createMapContext(id, that).$getAppMap(); |
||||
maps.onclick = function (point) { |
||||
console.log(point); |
||||
// point.iconPath = '/static/btn_loc0.png'; |
||||
that.markers = that.markers.concat(point); |
||||
uni.showToast({ |
||||
title: '添加成功', |
||||
icon: 'none' |
||||
}); |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
<style scoped lang="scss"></style> |
Loading…
Reference in new issue