Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
言程序plus
uni-starter
提交
9f767823
U
uni-starter
项目概览
言程序plus
/
uni-starter
与 Fork 源项目一致
Fork自
DCloud / uni-starter
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-starter
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
9f767823
编写于
9月 02, 2022
作者:
DCloud_JSON
提交者:
study夏羽
10月 25, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
使用旧版uni-ui组件
上级
7861566d
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
1169 addition
and
1072 deletion
+1169
-1072
uni_modules/uni-data-checkbox/changelog.md
uni_modules/uni-data-checkbox/changelog.md
+0
-2
uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js
...ni-data-checkbox/components/uni-data-checkbox/clientdb.js
+316
-0
uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
...eckbox/components/uni-data-checkbox/uni-data-checkbox.vue
+24
-24
uni_modules/uni-data-checkbox/package.json
uni_modules/uni-data-checkbox/package.json
+1
-1
uni_modules/uni-easyinput/changelog.md
uni_modules/uni-easyinput/changelog.md
+0
-10
uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
.../uni-easyinput/components/uni-easyinput/uni-easyinput.vue
+96
-228
uni_modules/uni-easyinput/package.json
uni_modules/uni-easyinput/package.json
+1
-1
uni_modules/uni-forms/changelog.md
uni_modules/uni-forms/changelog.md
+0
-30
uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
...es/uni-forms/components/uni-forms-item/uni-forms-item.vue
+454
-576
uni_modules/uni-forms/components/uni-forms/uni-forms.vue
uni_modules/uni-forms/components/uni-forms/uni-forms.vue
+269
-194
uni_modules/uni-forms/package.json
uni_modules/uni-forms/package.json
+8
-6
未找到文件。
uni_modules/uni-data-checkbox/changelog.md
浏览文件 @
9f767823
## 1.0.2(2022-06-30)
-
优化 在 uni-forms 中的依赖注入方式
## 1.0.1(2022-02-07)
-
修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
## 1.0.0(2021-11-19)
...
...
uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js
0 → 100644
浏览文件 @
9f767823
const
events
=
{
load
:
'
load
'
,
error
:
'
error
'
}
const
pageMode
=
{
add
:
'
add
'
,
replace
:
'
replace
'
}
const
attrs
=
[
'
pageCurrent
'
,
'
pageSize
'
,
'
collection
'
,
'
action
'
,
'
field
'
,
'
getcount
'
,
'
orderby
'
,
'
where
'
]
export
default
{
data
()
{
return
{
loading
:
false
,
listData
:
this
.
getone
?
{}
:
[],
paginationInternal
:
{
current
:
this
.
pageCurrent
,
size
:
this
.
pageSize
,
count
:
0
},
errorMessage
:
''
}
},
created
()
{
let
db
=
null
;
let
dbCmd
=
null
;
if
(
this
.
collection
){
this
.
db
=
uniCloud
.
database
();
this
.
dbCmd
=
this
.
db
.
command
;
}
this
.
_isEnded
=
false
this
.
$watch
(()
=>
{
var
al
=
[]
attrs
.
forEach
(
key
=>
{
al
.
push
(
this
[
key
])
})
return
al
},
(
newValue
,
oldValue
)
=>
{
this
.
paginationInternal
.
pageSize
=
this
.
pageSize
let
needReset
=
false
for
(
let
i
=
2
;
i
<
newValue
.
length
;
i
++
)
{
if
(
newValue
[
i
]
!=
oldValue
[
i
])
{
needReset
=
true
break
}
}
if
(
needReset
)
{
this
.
clear
()
this
.
reset
()
}
if
(
newValue
[
0
]
!=
oldValue
[
0
])
{
this
.
paginationInternal
.
current
=
this
.
pageCurrent
}
this
.
_execLoadData
()
})
// #ifdef H5
if
(
process
.
env
.
NODE_ENV
===
'
development
'
)
{
this
.
_debugDataList
=
[]
if
(
!
window
.
unidev
)
{
window
.
unidev
=
{
clientDB
:
{
data
:
[]
}
}
}
unidev
.
clientDB
.
data
.
push
(
this
.
_debugDataList
)
}
// #endif
// #ifdef MP-TOUTIAO
let
changeName
let
events
=
this
.
$scope
.
dataset
.
eventOpts
for
(
var
i
=
0
;
i
<
events
.
length
;
i
++
)
{
let
event
=
events
[
i
]
if
(
event
[
0
].
includes
(
'
^load
'
))
{
changeName
=
event
[
1
][
0
][
0
]
}
}
if
(
changeName
)
{
let
parent
=
this
.
$parent
let
maxDepth
=
16
this
.
_changeDataFunction
=
null
while
(
parent
&&
maxDepth
>
0
)
{
let
fun
=
parent
[
changeName
]
if
(
fun
&&
typeof
fun
===
'
function
'
)
{
this
.
_changeDataFunction
=
fun
maxDepth
=
0
break
}
parent
=
parent
.
$parent
maxDepth
--
;
}
}
// #endif
// if (!this.manual) {
// this.loadData()
// }
},
// #ifdef H5
beforeDestroy
()
{
if
(
process
.
env
.
NODE_ENV
===
'
development
'
&&
window
.
unidev
)
{
var
cd
=
this
.
_debugDataList
var
dl
=
unidev
.
clientDB
.
data
for
(
var
i
=
dl
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
dl
[
i
]
===
cd
)
{
dl
.
splice
(
i
,
1
)
break
}
}
}
},
// #endif
methods
:
{
loadData
(
args1
,
args2
)
{
let
callback
=
null
if
(
typeof
args1
===
'
object
'
)
{
if
(
args1
.
clear
)
{
this
.
clear
()
this
.
reset
()
}
if
(
args1
.
current
!==
undefined
)
{
this
.
paginationInternal
.
current
=
args1
.
current
}
if
(
typeof
args2
===
'
function
'
)
{
callback
=
args2
}
}
else
if
(
typeof
args1
===
'
function
'
)
{
callback
=
args1
}
this
.
_execLoadData
(
callback
)
},
loadMore
()
{
if
(
this
.
_isEnded
)
{
return
}
this
.
_execLoadData
()
},
refresh
()
{
this
.
clear
()
this
.
_execLoadData
()
},
clear
()
{
this
.
_isEnded
=
false
this
.
listData
=
[]
},
reset
()
{
this
.
paginationInternal
.
current
=
1
},
remove
(
id
,
{
action
,
callback
,
confirmTitle
,
confirmContent
}
=
{})
{
if
(
!
id
||
!
id
.
length
)
{
return
}
uni
.
showModal
({
title
:
confirmTitle
||
'
提示
'
,
content
:
confirmContent
||
'
是否删除该数据
'
,
showCancel
:
true
,
success
:
(
res
)
=>
{
if
(
!
res
.
confirm
)
{
return
}
this
.
_execRemove
(
id
,
action
,
callback
)
}
})
},
_execLoadData
(
callback
)
{
if
(
this
.
loading
)
{
return
}
this
.
loading
=
true
this
.
errorMessage
=
''
this
.
_getExec
().
then
((
res
)
=>
{
this
.
loading
=
false
const
{
data
,
count
}
=
res
.
result
this
.
_isEnded
=
data
.
length
<
this
.
pageSize
callback
&&
callback
(
data
,
this
.
_isEnded
)
this
.
_dispatchEvent
(
events
.
load
,
data
)
if
(
this
.
getone
)
{
this
.
listData
=
data
.
length
?
data
[
0
]
:
undefined
}
else
if
(
this
.
pageData
===
pageMode
.
add
)
{
this
.
listData
.
push
(...
data
)
if
(
this
.
listData
.
length
)
{
this
.
paginationInternal
.
current
++
}
}
else
if
(
this
.
pageData
===
pageMode
.
replace
)
{
this
.
listData
=
data
this
.
paginationInternal
.
count
=
count
}
// #ifdef H5
if
(
process
.
env
.
NODE_ENV
===
'
development
'
)
{
this
.
_debugDataList
.
length
=
0
this
.
_debugDataList
.
push
(...
JSON
.
parse
(
JSON
.
stringify
(
this
.
listData
)))
}
// #endif
}).
catch
((
err
)
=>
{
this
.
loading
=
false
this
.
errorMessage
=
err
callback
&&
callback
()
this
.
$emit
(
events
.
error
,
err
)
})
},
_getExec
()
{
let
exec
=
this
.
db
if
(
this
.
action
)
{
exec
=
exec
.
action
(
this
.
action
)
}
exec
=
exec
.
collection
(
this
.
collection
)
if
(
!
(
!
this
.
where
||
!
Object
.
keys
(
this
.
where
).
length
))
{
exec
=
exec
.
where
(
this
.
where
)
}
if
(
this
.
field
)
{
exec
=
exec
.
field
(
this
.
field
)
}
if
(
this
.
orderby
)
{
exec
=
exec
.
orderBy
(
this
.
orderby
)
}
const
{
current
,
size
}
=
this
.
paginationInternal
exec
=
exec
.
skip
(
size
*
(
current
-
1
)).
limit
(
size
).
get
({
getCount
:
this
.
getcount
})
return
exec
},
_execRemove
(
id
,
action
,
callback
)
{
if
(
!
this
.
collection
||
!
id
)
{
return
}
const
ids
=
Array
.
isArray
(
id
)
?
id
:
[
id
]
if
(
!
ids
.
length
)
{
return
}
uni
.
showLoading
({
mask
:
true
})
let
exec
=
this
.
db
if
(
action
)
{
exec
=
exec
.
action
(
action
)
}
exec
.
collection
(
this
.
collection
).
where
({
_id
:
dbCmd
.
in
(
ids
)
}).
remove
().
then
((
res
)
=>
{
callback
&&
callback
(
res
.
result
)
if
(
this
.
pageData
===
pageMode
.
replace
)
{
this
.
refresh
()
}
else
{
this
.
removeData
(
ids
)
}
}).
catch
((
err
)
=>
{
uni
.
showModal
({
content
:
err
.
message
,
showCancel
:
false
})
}).
finally
(()
=>
{
uni
.
hideLoading
()
})
},
removeData
(
ids
)
{
let
il
=
ids
.
slice
(
0
)
let
dl
=
this
.
listData
for
(
let
i
=
dl
.
length
-
1
;
i
>=
0
;
i
--
)
{
let
index
=
il
.
indexOf
(
dl
[
i
].
_id
)
if
(
index
>=
0
)
{
dl
.
splice
(
i
,
1
)
il
.
splice
(
index
,
1
)
}
}
},
_dispatchEvent
(
type
,
data
)
{
if
(
this
.
_changeDataFunction
)
{
this
.
_changeDataFunction
(
data
,
this
.
_isEnded
)
}
else
{
this
.
$emit
(
type
,
data
,
this
.
_isEnded
)
}
}
}
}
uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
浏览文件 @
9f767823
...
...
@@ -155,17 +155,17 @@
value
(
newVal
)
{
this
.
dataList
=
this
.
getDataList
(
newVal
)
// fix by mehaotian is_reset 在 uni-forms 中定义
//
if(!this.is_reset){
//
this.is_reset = false
//
this.formItem && this.formItem.setValue(newVal)
//
}
if
(
!
this
.
is_reset
){
this
.
is_reset
=
false
this
.
formItem
&&
this
.
formItem
.
setValue
(
newVal
)
}
},
modelValue
(
newVal
)
{
this
.
dataList
=
this
.
getDataList
(
newVal
);
//
if(!this.is_reset){
//
this.is_reset = false
//
this.formItem && this.formItem.setValue(newVal)
//
}
if
(
!
this
.
is_reset
){
this
.
is_reset
=
false
this
.
formItem
&&
this
.
formItem
.
setValue
(
newVal
)
}
}
},
data
()
{
...
...
@@ -193,22 +193,22 @@
}
},
created
()
{
//
this.form = this.getForm('uniForms')
//
this.formItem = this.getForm('uniFormsItem')
this
.
form
=
this
.
getForm
(
'
uniForms
'
)
this
.
formItem
=
this
.
getForm
(
'
uniFormsItem
'
)
// this.formItem && this.formItem.setValue(this.value)
//
if (this.formItem) {
//
this.isTop = 6
//
if (this.formItem.name) {
//
// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
//
if(!this.is_reset){
//
this.is_reset = false
//
this.formItem.setValue(this.dataValue)
//
}
//
this.rename = this.formItem.name
//
this.form.inputChildrens.push(this)
//
}
//
}
if
(
this
.
formItem
)
{
this
.
isTop
=
6
if
(
this
.
formItem
.
name
)
{
// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
if
(
!
this
.
is_reset
){
this
.
is_reset
=
false
this
.
formItem
.
setValue
(
this
.
dataValue
)
}
this
.
rename
=
this
.
formItem
.
name
this
.
form
.
inputChildrens
.
push
(
this
)
}
}
if
(
this
.
localdata
&&
this
.
localdata
.
length
!==
0
)
{
this
.
isLocal
=
true
...
...
@@ -273,7 +273,7 @@
}
}
}
//
this.formItem && this.formItem.setValue(detail.value)
this
.
formItem
&&
this
.
formItem
.
setValue
(
detail
.
value
)
// TODO 兼容 vue2
this
.
$emit
(
'
input
'
,
detail
.
value
);
// // TOTO 兼容 vue3
...
...
@@ -375,7 +375,7 @@
selectedArr
.
push
(
item
[
this
.
map
.
value
])
}
})
return
this
.
dataValue
.
length
>
0
?
this
.
dataValue
:
selectedArr
return
this
.
dataValue
&&
this
.
dataValue
.
length
>
0
?
this
.
dataValue
:
selectedArr
},
/**
...
...
uni_modules/uni-data-checkbox/package.json
浏览文件 @
9f767823
{
"id"
:
"uni-data-checkbox"
,
"displayName"
:
"uni-data-checkbox 数据选择器"
,
"version"
:
"1.0.
2
"
,
"version"
:
"1.0.
1
"
,
"description"
:
"通过数据驱动的单选框和复选框"
,
"keywords"
:
[
"uni-ui"
,
...
...
uni_modules/uni-easyinput/changelog.md
浏览文件 @
9f767823
## 1.1.0(2022-06-30)
-
新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
-
新增 clear 事件,点击右侧叉号图标触发
-
新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
-
优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
-
## 1.0.5(2022-06-07)
-
优化 clearable 显示策略
## 1.0.4(2022-06-07)
-
优化 clearable 显示策略
## 1.0.3(2022-05-20)
-
修复 关闭图标某些情况下无法取消的bug
## 1.0.2(2022-04-12)
...
...
uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
浏览文件 @
9f767823
<
template
>
<view
class=
"uni-easyinput"
:class=
"
{'uni-easyinput-error':msg}" :style="boxStyle">
<view
class=
"uni-easyinput__content"
:class=
"inputContentClass"
:style=
"inputContentStyle"
>
<uni-icons
v-if=
"prefixIcon"
class=
"content-clear-icon"
:type=
"prefixIcon"
color=
"#c0c4cc"
@
click=
"onClickIcon('prefix')"
size=
"22"
></uni-icons>
<textarea
v-if=
"type === 'textarea'"
class=
"uni-easyinput__content-textarea"
:class=
"
{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" :disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused"
:autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm">
</textarea>
<input
v-else
:type=
"type === 'password'?'text':type"
class=
"uni-easyinput__content-input"
:style=
"inputStyle"
:name=
"name"
:value=
"val"
:password=
"!showPassword && type === 'password'"
:placeholder=
"placeholder"
:placeholderStyle=
"placeholderStyle"
placeholder-class=
"uni-easyinput__placeholder-class"
:disabled=
"disabled"
:maxlength=
"inputMaxlength"
:focus=
"focused"
:confirmType=
"confirmType"
@
focus=
"_Focus"
@
blur=
"_Blur"
@
input=
"onInput"
@
confirm=
"onConfirm"
/>
<template
v-if=
"type === 'password' && passwordIcon"
>
<!-- 开启密码时显示小眼睛 -->
<uni-icons
v-if=
"isVal"
class=
"content-clear-icon"
:class=
"
{'is-textarea-icon':type==='textarea'}"
:type="showPassword?'eye-slash-filled':'eye-filled'" :size="22"
:color="focusShow?'#2979ff':'#c0c4cc'" @click="onEyes">
</uni-icons>
<view
class=
"uni-easyinput"
:class=
"
{'uni-easyinput-error':msg}" :style="{color:inputBorder
&&
msg?'#e43d33':styles.color}">
<view
class=
"uni-easyinput__content"
:class=
"
{'is-input-border':inputBorder ,'is-input-error-border':inputBorder
&&
msg,'is-textarea':type==='textarea','is-disabled':disabled}"
:style="{'border-color':inputBorder
&&
msg?'#dd524d':styles.borderColor,'background-color':disabled?styles.disableColor:''}">
<uni-icons
v-if=
"prefixIcon"
class=
"content-clear-icon"
:type=
"prefixIcon"
color=
"#c0c4cc"
@
click=
"onClickIcon('prefix')"
></uni-icons>
<textarea
v-if=
"type === 'textarea'"
class=
"uni-easyinput__content-textarea"
:class=
"
{'input-padding':inputBorder}"
:name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class"
:maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" @input="onInput" @blur="onBlur" @focus="onFocus"
@confirm="onConfirm">
</textarea>
<input
v-else
:type=
"type === 'password'?'text':type"
class=
"uni-easyinput__content-input"
:style=
"
{
'padding-right':type === 'password' ||clearable || prefixIcon?'':'10px',
'padding-left':prefixIcon?'':'10px'
}"
:name="name" :value="val" :password="!showPassword
&&
type === 'password'" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" @focus="onFocus"
@blur="onBlur" @input="onInput" @confirm="onConfirm" />
<template
v-if=
"type === 'password' && passwordIcon"
>
<uni-icons
v-if=
"val"
class=
"content-clear-icon"
:class=
"
{'is-textarea-icon':type==='textarea'}" :type="showPassword?'eye-slash-filled':'eye-filled'"
:size="18" color="#c0c4cc" @click="onEyes">
</uni-icons>
</
template
>
<
template
v-else-if=
"suffixIcon"
>
<uni-icons
v-if=
"suffixIcon"
class=
"content-clear-icon"
:type=
"suffixIcon"
color=
"#c0c4cc"
@
click=
"onClickIcon('suffix')"
size=
"22"
></uni-icons>
<uni-icons
v-if=
"suffixIcon"
class=
"content-clear-icon"
:type=
"suffixIcon"
color=
"#c0c4cc"
@
click=
"onClickIcon('suffix')"
></uni-icons>
</
template
>
<
template
v-else
>
<uni-icons
v-if=
"clearable && isVal && !disabled && type !== 'textarea'"
class=
"content-clear-icon"
:class=
"
{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
:color="msg?'#dd524d':(focusShow?'#2979ff':'#c0c4cc')" @click="onClear">
</uni-icons>
<uni-icons
class=
"content-clear-icon"
:class=
"
{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
v-if="clearable
&&
val
&&
!disabled" color="#c0c4cc" @click="onClear">
</uni-icons>
</
template
>
<slot
name=
"right"
></slot>
</view>
...
...
@@ -36,6 +31,10 @@
</template>
<
script
>
// import {
// debounce,
// throttle
// } from './common.js'
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
...
...
@@ -49,7 +48,7 @@
* @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
* @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认
tru
e)
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认
fals
e)
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点(默认false)
...
...
@@ -77,44 +76,13 @@
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
function
obj2strClass
(
obj
)
{
let
classess
=
''
for
(
let
key
in
obj
)
{
const
val
=
obj
[
key
]
if
(
val
)
{
classess
+=
`
${
key
}
`
}
}
return
classess
}
function
obj2strStyle
(
obj
)
{
let
style
=
''
for
(
let
key
in
obj
)
{
const
val
=
obj
[
key
]
style
+=
`
${
key
}
:
${
val
}
;`
}
return
style
}
export
default
{
export
default
{
name
:
'
uni-easyinput
'
,
emits
:
[
'
click
'
,
'
iconClick
'
,
'
update:modelValue
'
,
'
input
'
,
'
focus
'
,
'
blur
'
,
'
confirm
'
,
'
clear
'
,
'
eyes
'
,
'
change
'
],
model
:
{
prop
:
'
modelValue
'
,
event
:
'
update:modelValue
'
},
options
:
{
virtualHost
:
true
},
inject
:
{
form
:
{
from
:
'
uniForm
'
,
default
:
null
},
formItem
:
{
from
:
'
uniFormItem
'
,
default
:
null
},
emits
:[
'
click
'
,
'
iconClick
'
,
'
update:modelValue
'
,
'
input
'
,
'
focus
'
,
'
blur
'
,
'
confirm
'
],
model
:{
prop
:
'
modelValue
'
,
event
:
'
update:modelValue
'
},
props
:
{
name
:
String
,
...
...
@@ -132,10 +100,7 @@
type
:
Boolean
,
default
:
false
},
placeholder
:
{
type
:
String
,
default
:
'
'
},
placeholder
:
String
,
placeholderStyle
:
String
,
focus
:
{
type
:
Boolean
,
...
...
@@ -155,7 +120,7 @@
},
clearSize
:
{
type
:
[
Number
,
String
],
default
:
24
default
:
15
},
inputBorder
:
{
type
:
Boolean
,
...
...
@@ -173,7 +138,7 @@
type
:
[
Boolean
,
String
],
default
:
true
},
passwordIcon
:
{
passwordIcon
:{
type
:
Boolean
,
default
:
true
},
...
...
@@ -187,105 +152,79 @@
}
}
},
errorMessage
:
{
type
:
[
String
,
Boolean
],
default
:
''
errorMessage
:{
type
:
[
String
,
Boolean
],
default
:
''
}
},
data
()
{
return
{
focused
:
false
,
errMsg
:
''
,
val
:
''
,
showMsg
:
''
,
border
:
false
,
isFirstBorder
:
false
,
showClearIcon
:
false
,
showPassword
:
false
,
focusShow
:
false
,
localMsg
:
''
showPassword
:
false
};
},
computed
:
{
// 输入框内是否有值
isVal
()
{
const
val
=
this
.
val
// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
if
(
val
||
val
===
0
)
{
return
true
}
return
false
},
msg
()
{
// console.log('computed', this.form, this.formItem);
// if (this.form) {
// return this.errorMessage || this.formItem.errMsg;
// }
// TODO 处理头条 formItem 中 errMsg 不更新的问题
return
this
.
localMsg
||
this
.
errorMessage
return
this
.
errorMessage
||
this
.
errMsg
;
},
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
inputMaxlength
()
{
return
Number
(
this
.
maxlength
);
},
// 处理外层样式的style
boxStyle
()
{
return
`color:
${
this
.
inputBorder
&&
this
.
msg
?
'
#e43d33
'
:
this
.
styles
.
color
}
;`
},
// input 内容的类和样式处理
inputContentClass
()
{
return
obj2strClass
({
'
is-input-border
'
:
this
.
inputBorder
,
'
is-input-error-border
'
:
this
.
inputBorder
&&
this
.
msg
,
'
is-textarea
'
:
this
.
type
===
'
textarea
'
,
'
is-disabled
'
:
this
.
disabled
})
},
inputContentStyle
()
{
const
focusColor
=
this
.
focusShow
?
'
#2979ff
'
:
this
.
styles
.
borderColor
const
borderColor
=
this
.
inputBorder
&&
this
.
msg
?
'
#dd524d
'
:
focusColor
return
obj2strStyle
({
'
border-color
'
:
borderColor
||
'
#e5e5e5
'
,
'
background-color
'
:
this
.
disabled
?
this
.
styles
.
disableColor
:
'
#fff
'
})
},
// input右侧样式
inputStyle
()
{
const
paddingRight
=
this
.
type
===
'
password
'
||
this
.
clearable
||
this
.
prefixIcon
?
''
:
'
10px
'
return
obj2strStyle
({
'
padding-right
'
:
paddingRight
,
'
padding-left
'
:
this
.
prefixIcon
?
''
:
'
10px
'
})
}
},
watch
:
{
value
(
newVal
)
{
if
(
this
.
errMsg
)
this
.
errMsg
=
''
this
.
val
=
newVal
// fix by mehaotian is_reset 在 uni-forms 中定义
if
(
this
.
form
&&
this
.
formItem
&&!
this
.
is_reset
)
{
this
.
is_reset
=
false
this
.
formItem
.
setValue
(
newVal
)
}
},
modelValue
(
newVal
)
{
if
(
this
.
errMsg
)
this
.
errMsg
=
''
this
.
val
=
newVal
if
(
this
.
form
&&
this
.
formItem
&&!
this
.
is_reset
)
{
this
.
is_reset
=
false
this
.
formItem
.
setValue
(
newVal
)
}
},
focus
(
newVal
)
{
this
.
$nextTick
(()
=>
{
this
.
focused
=
this
.
focus
this
.
focusShow
=
this
.
focus
})
}
},
created
()
{
this
.
init
()
// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
if
(
!
this
.
value
&&
this
.
value
!==
0
){
this
.
val
=
this
.
modelValue
}
if
(
!
this
.
modelValue
&&
this
.
modelValue
!==
0
){
this
.
val
=
this
.
value
}
this
.
form
=
this
.
getForm
(
'
uniForms
'
)
this
.
formItem
=
this
.
getForm
(
'
uniFormsItem
'
)
if
(
this
.
form
&&
this
.
formItem
)
{
this
.
$watch
(
'
formItem.errMsg
'
,
(
newVal
)
=>
{
this
.
localMsg
=
newVal
})
if
(
this
.
formItem
.
name
)
{
if
(
!
this
.
is_reset
){
this
.
is_reset
=
false
this
.
formItem
.
setValue
(
this
.
val
)
}
this
.
rename
=
this
.
formItem
.
name
this
.
form
.
inputChildrens
.
push
(
this
)
}
}
},
mounted
()
{
this
.
$nextTick
(()
=>
{
this
.
focused
=
this
.
focus
this
.
focusShow
=
this
.
focus
})
},
methods
:
{
...
...
@@ -293,35 +232,28 @@
* 初始化变量值
*/
init
()
{
if
(
this
.
value
||
this
.
value
===
0
)
{
this
.
val
=
this
.
value
}
else
if
(
this
.
modelValue
||
this
.
modelValue
===
0
)
{
this
.
val
=
this
.
modelValue
}
else
{
this
.
val
=
null
}
},
/**
* 点击图标时触发
* @param {Object} type
*/
},
onClickIcon
(
type
)
{
this
.
$emit
(
'
iconClick
'
,
type
)
},
/**
*
显示隐藏内容,密码框时生效
*
获取父元素实例
*/
getForm
(
name
=
'
uniForms
'
)
{
let
parent
=
this
.
$parent
;
let
parentName
=
parent
.
$options
.
name
;
while
(
parentName
!==
name
)
{
parent
=
parent
.
$parent
;
if
(
!
parent
)
return
false
;
parentName
=
parent
.
$options
.
name
;
}
return
parent
;
},
onEyes
()
{
this
.
showPassword
=
!
this
.
showPassword
this
.
$emit
(
'
eyes
'
,
this
.
showPassword
)
},
/**
* 输入时触发
* @param {Object} event
*/
onInput
(
event
)
{
let
value
=
event
.
detail
.
value
;
// 判断是否去除空格
...
...
@@ -338,79 +270,30 @@
// TODO 兼容 vue2
this
.
$emit
(
'
input
'
,
value
);
// TODO 兼容 vue3
this
.
$emit
(
'
update:modelValue
'
,
value
)
this
.
$emit
(
'
update:modelValue
'
,
value
)
},
/**
* 外部调用方法
* 获取焦点时触发
* @param {Object} event
*/
onFocus
()
{
this
.
$nextTick
(()
=>
{
this
.
focused
=
true
})
this
.
$emit
(
'
focus
'
,
null
);
},
_Focus
(
event
)
{
this
.
focusShow
=
true
onFocus
(
event
)
{
this
.
$emit
(
'
focus
'
,
event
);
},
/**
* 外部调用方法
* 失去焦点时触发
* @param {Object} event
*/
onBlur
()
{
this
.
focused
=
false
this
.
$emit
(
'
focus
'
,
null
);
},
_Blur
(
event
)
{
onBlur
(
event
)
{
let
value
=
event
.
detail
.
value
;
this
.
focusShow
=
false
this
.
$emit
(
'
blur
'
,
event
);
// 根据类型返回值,在event中获取的值理论上讲都是string
this
.
$emit
(
'
change
'
,
this
.
val
)
// 失去焦点时参与表单校验
if
(
this
.
form
&&
this
.
formItem
)
{
const
{
validateTrigger
}
=
this
.
form
if
(
validateTrigger
===
'
blur
'
)
{
this
.
formItem
.
onFieldChange
()
}
}
},
/**
* 按下键盘的发送键
* @param {Object} e
*/
onConfirm
(
e
)
{
this
.
$emit
(
'
confirm
'
,
this
.
val
);
this
.
$emit
(
'
change
'
,
this
.
val
)
this
.
$emit
(
'
confirm
'
,
e
.
detail
.
value
);
},
/**
* 清理内容
* @param {Object} event
*/
onClear
(
event
)
{
this
.
val
=
''
;
// TODO 兼容 vue2
this
.
$emit
(
'
input
'
,
''
);
// TODO 兼容 vue2
// TODO 兼容 vue3
this
.
$emit
(
'
update:modelValue
'
,
''
)
// 点击叉号触发
this
.
$emit
(
'
clear
'
)
this
.
$emit
(
'
update:modelValue
'
,
''
)
},
fieldClick
()
{
this
.
$emit
(
'
click
'
);
},
/**
* 去除空格
*/
trimStr
(
str
,
pos
=
'
both
'
)
{
if
(
pos
===
'
both
'
)
{
return
str
.
trim
();
...
...
@@ -433,10 +316,9 @@
};
</
script
>
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
$uni-error
:
#e43d33
;
$uni-border-1
:
#DCDFE6
!
default
;
.uni-easyinput
{
/* #ifndef APP-NVUE */
width
:
100%
;
...
...
@@ -454,14 +336,10 @@
width
:
100%
;
display
:
flex
;
box-sizing
:
border-box
;
//
min-height: 36px;
min-height
:
36px
;
/* #endif */
flex-direction
:
row
;
align-items
:
center
;
// 处理border动画刚开始显示黑色的问题
border-color
:
#fff
;
transition-property
:
border-color
;
transition-duration
:
0
.3s
;
}
.uni-easyinput__content-input
{
...
...
@@ -473,16 +351,12 @@
flex
:
1
;
line-height
:
1
;
font-size
:
14px
;
height
:
35px
;
// min-height: 36px;
}
.uni-easyinput__placeholder-class
{
color
:
#999
;
font-size
:
12px
;
//
font-weight: 200;
font-weight
:
200
;
}
.is-textarea
{
align-items
:
flex-start
;
}
...
...
@@ -497,10 +371,9 @@
flex
:
1
;
line-height
:
1
.5
;
font-size
:
14px
;
margin
:
6px
;
margin-left
:
0
;
padding-top
:
6px
;
padding-bottom
:
10px
;
height
:
80px
;
min-height
:
80px
;
/* #ifndef APP-NVUE */
min-height
:
80px
;
width
:
auto
;
...
...
@@ -530,9 +403,6 @@
align-items
:
center
;
border
:
1px
solid
$uni-border-1
;
border-radius
:
4px
;
/* #ifdef MP-ALIPAY */
overflow
:
hidden
;
/* #endif */
}
.uni-error-message
{
...
...
@@ -553,10 +423,8 @@
.is-input-error-border
{
border-color
:
$uni-error
;
.uni-easyinput__placeholder-class
{
color
:
mix
(
#fff
,
$uni-error
,
50%
);
;
color
:
mix
(
#fff
,
$uni-error
,
50%
);;
}
}
...
...
@@ -582,12 +450,12 @@
}
.is-disabled
{
border-color
:
red
;
background-color
:
#F7F6F6
;
color
:
#D5D5D5
;
.uni-easyinput__placeholder-class
{
color
:
#D5D5D5
;
font-size
:
12px
;
}
}
</
style
>
</
style
>
uni_modules/uni-easyinput/package.json
浏览文件 @
9f767823
{
"id"
:
"uni-easyinput"
,
"displayName"
:
"uni-easyinput 增强输入框"
,
"version"
:
"1.
1.0
"
,
"version"
:
"1.
0.3
"
,
"description"
:
"Easyinput 组件是对原生input组件的增强"
,
"keywords"
:
[
"uni-ui"
,
...
...
uni_modules/uni-forms/changelog.md
浏览文件 @
9f767823
## 1.4.8(2022-08-23)
-
优化 根据 rules 自动添加 required 的问题
## 1.4.7(2022-08-22)
-
修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:
[
https://ask.dcloud.net.cn/question/151540
](
https://ask.dcloud.net.cn/question/151540
)
## 1.4.6(2022-07-13)
-
修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug
## 1.4.5(2022-07-05)
-
新增 更多表单示例
-
优化 子表单组件过期提示的问题
-
优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式
## 1.4.4(2022-07-04)
-
更新 删除组件日志
## 1.4.3(2022-07-04)
-
修复 由 1.4.0 引发的 label 插槽不生效的bug
## 1.4.2(2022-07-04)
-
修复 子组件找不到 setValue 报错的bug
## 1.4.1(2022-07-04)
-
修复 uni-data-picker 在 uni-forms-item 中报错的bug
-
修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.4.0(2022-06-30)
-
【重要】组件逻辑重构,部分用法用旧版本不兼容,请注意兼容问题
-
【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力
-
新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃
-
新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效
-
新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法
-
新增 子表单的 setRules 方法,配合自定义校验函数使用
-
新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则
-
优化 动态表单校验方式,废弃拼接name的方式
## 1.3.3(2022-06-22)
-
修复 表单校验顺序无序问题
## 1.3.2(2021-12-09)
-
## 1.3.1(2021-11-19)
...
...
uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
浏览文件 @
9f767823
<
template
>
<view
class=
"uni-forms-item"
:class=
"['is-direction-' + localLabelPos ,border?'uni-forms-item--border':'' ,border && isFirstBorder?'is-first-border':'']"
>
<slot
name=
"label"
>
<view
class=
"uni-forms-item__label"
:class=
"
{'no-label':!label
&&
!isRequired}"
:style="{width:localLabelWidth,justifyContent: localLabelAlign}">
<text
v-if=
"isRequired"
class=
"is-required"
>
*
</text>
<text>
{{
label
}}
</text>
<view
class=
"uni-forms-item"
:class=
"
{ 'uni-forms-item--border': border, 'is-first-border': border
&&
isFirstBorder, 'uni-forms-item-error': msg }">
<view
class=
"uni-forms-item__box"
>
<view
class=
"uni-forms-item__inner"
:class=
"['is-direction-' + labelPos]"
>
<view
class=
"uni-forms-item__label"
:style=
"
{ width: labelWid , justifyContent: justifyContent }">
<slot
name=
"label"
>
<text
v-if=
"required"
class=
"is-required"
>
*
</text>
<uni-icons
v-if=
"leftIcon"
class=
"label-icon"
size=
"16"
:type=
"leftIcon"
:color=
"iconColor"
/>
<text
class=
"label-text"
>
{{
label
}}
</text>
<view
v-if=
"label"
class=
"label-seat"
></view>
</slot>
</view>
<view
class=
"uni-forms-item__content"
:class=
"
{ 'is-input-error-border': msg }">
<slot></slot></view>
</view>
</slot>
<!-- #ifndef APP-NVUE -->
<view
class=
"uni-forms-item__content"
>
<slot></slot>
<view
class=
"uni-forms-item__error"
:class=
"
{'msg--active':msg}">
<text>
{{
msg
}}
</text>
<view
v-if=
"msg"
class=
"uni-error-message"
:class=
"
{ 'uni-error-msg--boeder': border }"
:style="{
paddingLeft: labelLeft
}"
>
<text
class=
"uni-error-message-text"
>
{{
showMsg
===
'
undertext
'
?
msg
:
''
}}
</text>
</view>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view
class=
"uni-forms-item__nuve-content"
>
<view
class=
"uni-forms-item__content"
>
<slot></slot>
</view>
<view
class=
"uni-forms-item__error"
:class=
"
{'msg--active':msg}">
<text
class=
"error-text"
>
{{
msg
}}
</text>
</view>
</view>
<!-- #endif -->
</view>
</
template
>
<
script
>
/**
* uni-fomrs-item 表单子组件
* @description uni-fomrs-item 表单子组件,提供了基础布局已经校验能力
* @tutorial https://ext.dcloud.net.cn/plugin?id=2773
* @property {Boolean} required 是否必填,左边显示红色"*"号
* @property {String } label 输入框左边的文字提示
* @property {Number } labelWidth label的宽度,单位px(默认65)
* @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left)
* @value left label 左侧显示
* @value center label 居中
* @value right label 右侧对齐
* @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
* @property {String } name 表单域的属性名,在使用校验规则时必填
* @property {String } leftIcon 【1.4.0废弃】label左边的图标,限 uni-ui 的图标名称
* @property {String } iconColor 【1.4.0废弃】左边通过icon配置的图标的颜色(默认#606266)
* @property {String} validateTrigger = [bind|submit|blur] 【1.4.0废弃】校验触发器方式 默认 submit
* @value bind 发生变化时触发
* @value submit 提交时触发
* @value blur 失去焦点触发
* @property {String } labelPosition = [top|left] 【1.4.0废弃】label的文字的位置(默认left)
* @value top 顶部显示 label
* @value left 左侧显示 label
*/
export
default
{
name
:
'
uniFormsItem
'
,
options
:
{
virtualHost
:
true
/**
* Field 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
* @tutorial https://ext.dcloud.net.cn/plugin?id=21001
* @property {Boolean} required 是否必填,左边显示红色"*"号(默认false)
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit 可选
* @value bind 发生变化时触发
* @value submit 提交时触发
* @property {String } leftIcon label左边的图标,限 uni-ui 的图标名称
* @property {String } iconColor 左边通过icon配置的图标的颜色(默认#606266)
* @property {String } label 输入框左边的文字提示
* @property {Number } labelWidth label的宽度,单位px(默认65)
* @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left)
* @value left label 左侧显示
* @value center label 居中
* @value right label 右侧对齐
* @property {String } labelPosition = [top|left] label的文字的位置(默认left)
* @value top 顶部显示 label
* @value left 左侧显示 label
* @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
* @property {String } name 表单域的属性名,在使用校验规则时必填
*/
export
default
{
name
:
'
uniFormsItem
'
,
props
:
{
// 自定义内容
custom
:
{
type
:
Boolean
,
default
:
false
},
provide
()
{
return
{
uniFormItem
:
this
}
// 是否显示报错信息
showMessage
:
{
type
:
Boolean
,
default
:
true
},
inject
:
{
form
:
{
from
:
'
uniForm
'
,
default
:
null
},
name
:
String
,
required
:
Boolean
,
validateTrigger
:
{
type
:
String
,
default
:
''
},
props
:
{
// 表单校验规则
rules
:
{
type
:
Array
,
default
()
{
return
null
;
}
},
// 表单域的属性名,在使用校验规则时必填
name
:
{
type
:
[
String
,
Array
],
default
:
''
},
required
:
{
type
:
Boolean
,
default
:
false
},
label
:
{
type
:
String
,
default
:
''
},
// label的宽度 ,默认 80
labelWidth
:
{
type
:
[
String
,
Number
],
default
:
''
},
// label 居中方式,默认 left 取值 left/center/right
labelAlign
:
{
type
:
String
,
default
:
''
},
// 强制显示错误信息
errorMessage
:
{
type
:
[
String
,
Boolean
],
default
:
''
},
// 1.4.0 弃用,统一使用 form 的校验时机
// validateTrigger: {
// type: String,
// default: ''
// },
// 1.4.0 弃用,统一使用 form 的label 位置
// labelPosition: {
// type: String,
// default: ''
// },
// 1.4.0 以下属性已经废弃,请使用 #label 插槽代替
leftIcon
:
String
,
iconColor
:
{
type
:
String
,
default
:
'
#606266
'
},
leftIcon
:
String
,
iconColor
:
{
type
:
String
,
default
:
'
#606266
'
},
data
()
{
return
{
errMsg
:
''
,
isRequired
:
false
,
userRules
:
null
,
localLabelAlign
:
'
left
'
,
localLabelWidth
:
'
65px
'
,
localLabelPos
:
'
left
'
,
border
:
false
,
isFirstBorder
:
false
,
};
label
:
String
,
// 左边标题的宽度单位px
labelWidth
:
{
type
:
[
Number
,
String
],
default
:
''
},
computed
:
{
// 处理错误信息
msg
()
{
return
this
.
errorMessage
||
this
.
errMsg
;
}
// 对齐方式,left|center|right
labelAlign
:
{
type
:
String
,
default
:
''
},
watch
:
{
// 规则发生变化通知子组件更新
'
form.formRules
'
(
val
)
{
// TODO 处理头条vue3 watch不生效的问题
// #ifndef MP-TOUTIAO
this
.
init
()
// #endif
},
'
form.labelWidth
'
(
val
)
{
// 宽度
this
.
localLabelWidth
=
this
.
_labelWidthUnit
(
val
)
},
'
form.labelPosition
'
(
val
)
{
// 标签位置
this
.
localLabelPos
=
this
.
_labelPosition
()
},
'
form.labelAlign
'
(
val
)
{
}
// lable的位置,可选为 left-左边,top-上边
labelPosition
:
{
type
:
String
,
default
:
''
},
created
()
{
this
.
init
(
true
)
if
(
this
.
name
&&
this
.
form
)
{
// TODO 处理头条vue3 watch不生效的问题
// #ifdef MP-TOUTIAO
this
.
$watch
(
'
form.formRules
'
,
()
=>
{
this
.
init
()
})
// #endif
// 监听变化
this
.
$watch
(
()
=>
{
const
val
=
this
.
form
.
_getDataValue
(
this
.
name
,
this
.
form
.
localData
)
return
val
},
(
value
,
oldVal
)
=>
{
const
isEqual
=
this
.
form
.
_isEqual
(
value
,
oldVal
)
// 简单判断前后值的变化,只有发生变化才会发生校验
// TODO 如果 oldVal = undefined ,那么大概率是源数据里没有值导致 ,这个情况不哦校验 ,可能不严谨 ,需要在做观察
// fix by mehaotian 暂时取消 && oldVal !== undefined ,如果formData 中不存在,可能会不校验
if
(
!
isEqual
)
{
const
val
=
this
.
itemSetValue
(
value
)
this
.
onFieldChange
(
val
,
false
)
}
},
{
immediate
:
false
}
);
errorMessage
:
{
type
:
[
String
,
Boolean
],
default
:
''
},
// 表单校验规则
rules
:
{
type
:
Array
,
default
()
{
return
[];
}
}
},
data
()
{
return
{
errorTop
:
false
,
errorBottom
:
false
,
labelMarginBottom
:
''
,
errorWidth
:
''
,
errMsg
:
''
,
val
:
''
,
labelPos
:
''
,
labelWid
:
''
,
labelAli
:
''
,
showMsg
:
'
undertext
'
,
border
:
false
,
isFirstBorder
:
false
,
isArray
:
false
,
arrayField
:
''
};
},
computed
:
{
msg
()
{
return
this
.
errorMessage
||
this
.
errMsg
;
},
// #ifndef VUE3
destroyed
()
{
if
(
this
.
__isUnmounted
)
return
this
.
unInit
()
fieldStyle
()
{
let
style
=
{};
if
(
this
.
labelPos
==
'
top
'
)
{
style
.
padding
=
'
0 0
'
;
this
.
labelMarginBottom
=
'
6px
'
;
}
if
(
this
.
labelPos
==
'
left
'
&&
this
.
msg
!==
false
&&
this
.
msg
!=
''
)
{
style
.
paddingBottom
=
'
0px
'
;
this
.
errorBottom
=
true
;
this
.
errorTop
=
false
;
}
else
if
(
this
.
labelPos
==
'
top
'
&&
this
.
msg
!==
false
&&
this
.
msg
!=
''
)
{
this
.
errorBottom
=
false
;
this
.
errorTop
=
true
;
}
else
{
// style.paddingBottom = ''
this
.
errorTop
=
false
;
this
.
errorBottom
=
false
;
}
return
style
;
},
// #endif
// #ifdef VUE3
unmounted
()
{
this
.
__isUnmounted
=
true
this
.
unInit
()
// uni不支持在computed中写style.justifyContent = 'center'的形式,故用此方法
justifyContent
()
{
if
(
this
.
labelAli
===
'
left
'
)
return
'
flex-start
'
;
if
(
this
.
labelAli
===
'
center
'
)
return
'
center
'
;
if
(
this
.
labelAli
===
'
right
'
)
return
'
flex-end
'
;
},
// #endif
methods
:
{
/**
* 外部调用方法
* 设置规则 ,主要用于小程序自定义检验规则
* @param {Array} rules 规则源数据
*/
setRules
(
rules
=
null
)
{
this
.
userRules
=
rules
this
.
init
(
false
)
},
// 兼容老版本表单组件
setValue
()
{
// console.log('setValue 方法已经弃用,请使用最新版本的 uni-forms 表单组件以及其他关联组件。');
},
/**
* 外部调用方法
* 校验数据
* @param {any} value 需要校验的数据
* @param {boolean} 是否立即校验
* @return {Array|null} 校验内容
*/
async
onFieldChange
(
value
,
formtrigger
=
true
)
{
const
{
formData
,
localData
,
errShowType
,
validateCheck
,
validateTrigger
,
_isRequiredField
,
_realName
}
=
this
.
form
const
name
=
_realName
(
this
.
name
)
if
(
!
value
)
{
value
=
this
.
form
.
formData
[
name
]
labelLeft
(){
return
(
this
.
labelPos
===
'
left
'
?
parseInt
(
this
.
labelWid
)
:
0
)
+
'
px
'
}
},
watch
:
{
validateTrigger
(
trigger
)
{
this
.
formTrigger
=
trigger
;
}
},
created
()
{
this
.
form
=
this
.
getForm
();
this
.
group
=
this
.
getForm
(
'
uniGroup
'
);
this
.
formRules
=
[];
this
.
formTrigger
=
this
.
validateTrigger
;
// 处理 name,是否数组
if
(
this
.
name
&&
this
.
name
.
indexOf
(
'
[
'
)
!==
-
1
&&
this
.
name
.
indexOf
(
'
]
'
)
!==
-
1
)
{
this
.
isArray
=
true
;
this
.
arrayField
=
this
.
name
// fix by mehaotian 修改不修改的情况,动态值不检验的问题
this
.
form
.
formData
[
this
.
name
]
=
this
.
form
.
_getValue
(
this
.
name
,
''
)
}
},
mounted
()
{
if
(
this
.
form
)
{
this
.
form
.
childrens
.
push
(
this
);
}
this
.
init
();
},
// #ifndef VUE3
destroyed
()
{
if
(
this
.
__isUnmounted
)
return
this
.
unInit
()
},
// #endif
// #ifdef VUE3
unmounted
(){
this
.
__isUnmounted
=
true
this
.
unInit
()
},
// #endif
methods
:
{
init
()
{
if
(
this
.
form
)
{
let
{
formRules
,
validator
,
formData
,
value
,
labelPosition
,
labelWidth
,
labelAlign
,
errShowType
}
=
this
.
form
;
this
.
labelPos
=
this
.
labelPosition
?
this
.
labelPosition
:
labelPosition
;
if
(
this
.
label
){
this
.
labelWid
=
(
this
.
labelWidth
?
this
.
labelWidth
:
(
labelWidth
||
70
))
}
else
{
this
.
labelWid
=
(
this
.
labelWidth
?
this
.
labelWidth
:
(
labelWidth
||
'
auto
'
))
}
// fixd by mehaotian 不在校验前清空信息,解决闪屏的问题
// this.errMsg = '';
// fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题
const
ruleLen
=
this
.
itemRules
.
rules
&&
this
.
itemRules
.
rules
.
length
if
(
!
this
.
validator
||
!
ruleLen
||
ruleLen
===
0
)
return
;
// 检验时机
// let trigger = this.isTrigger(this.itemRules.validateTrigger, this.validateTrigger, validateTrigger);
const
isRequiredField
=
_isRequiredField
(
this
.
itemRules
.
rules
||
[]);
let
result
=
null
;
// 只有等于 bind 时 ,才能开启时实校验
if
(
validateTrigger
===
'
bind
'
||
formtrigger
)
{
// 校验当前表单项
result
=
await
this
.
validator
.
validateUpdate
({
[
name
]:
value
},
formData
);
// 判断是否必填,非必填,不填不校验,填写才校验 ,暂时只处理 undefined 和空的情况
if
(
!
isRequiredField
&&
(
value
===
undefined
||
value
===
''
))
{
result
=
null
;
}
// 判断错误信息显示类型
if
(
result
&&
result
.
errorMessage
)
{
if
(
errShowType
===
'
undertext
'
)
{
// 获取错误信息
this
.
errMsg
=
!
result
?
''
:
result
.
errorMessage
;
}
if
(
errShowType
===
'
toast
'
)
{
uni
.
showToast
({
title
:
result
.
errorMessage
||
'
校验错误
'
,
icon
:
'
none
'
});
}
if
(
errShowType
===
'
modal
'
)
{
uni
.
showModal
({
title
:
'
提示
'
,
content
:
result
.
errorMessage
||
'
校验错误
'
});
}
}
else
{
this
.
errMsg
=
''
}
// 通知 form 组件更新事件
validateCheck
(
result
?
result
:
null
)
}
else
{
this
.
errMsg
=
''
if
(
this
.
labelWid
&&
this
.
labelWid
!==
'
auto
'
)
{
this
.
labelWid
+=
'
px
'
}
return
result
?
result
:
null
;
},
/**
* 初始组件数据
*/
init
(
type
=
false
)
{
const
{
validator
,
formRules
,
childrens
,
formData
,
localData
,
_realName
,
labelWidth
,
_getDataValue
,
_setDataValue
}
=
this
.
form
||
{}
// 对齐方式
this
.
localLabelAlign
=
this
.
_justifyContent
()
// 宽度
this
.
localLabelWidth
=
this
.
_labelWidthUnit
(
labelWidth
)
// 标签位置
this
.
localLabelPos
=
this
.
_labelPosition
()
this
.
isRequired
=
this
.
required
// 将需要校验的子组件加入form 队列
this
.
form
&&
type
&&
childrens
.
push
(
this
)
this
.
labelAli
=
this
.
labelAlign
?
this
.
labelAlign
:
labelAlign
;
if
(
!
validator
||
!
formRules
)
return
// 判断第一个 item
if
(
!
this
.
form
.
isFirstBorder
)
{
this
.
form
.
isFirstBorder
=
true
;
...
...
@@ -333,299 +221,289 @@
this
.
isFirstBorder
=
true
;
}
}
this
.
border
=
this
.
form
.
border
;
// 获取子域的真实名称
const
name
=
_realName
(
this
.
name
)
const
itemRule
=
this
.
userRules
||
this
.
rules
if
(
typeof
formRules
===
'
object
'
&&
itemRule
)
{
// 子规则替换父规则
formRules
[
name
]
=
{
rules
:
itemRule
this
.
showMsg
=
errShowType
;
let
name
=
this
.
isArray
?
this
.
arrayField
:
this
.
name
;
if
(
!
name
)
return
if
(
formRules
&&
this
.
rules
.
length
>
0
)
{
if
(
!
formRules
[
name
])
{
formRules
[
name
]
=
{
rules
:
this
.
rules
}
}
validator
.
updateSchema
(
formRules
);
}
// 注册校验规则
const
itemRules
=
formRules
[
name
]
||
{}
this
.
itemRules
=
itemRules
// 注册校验函数
this
.
validator
=
validator
// 默认值赋予
this
.
itemSetValue
(
_getDataValue
(
this
.
name
,
localData
))
this
.
isRequired
=
this
.
_isRequired
()
},
unInit
()
{
if
(
this
.
form
)
{
const
{
childrens
,
formData
,
_realName
}
=
this
.
form
childrens
.
forEach
((
item
,
index
)
=>
{
if
(
item
===
this
)
{
this
.
form
.
childrens
.
splice
(
index
,
1
)
delete
formData
[
_realName
(
item
.
name
)]
}
})
}
},
// 设置item 的值
itemSetValue
(
value
)
{
const
name
=
this
.
form
.
_realName
(
this
.
name
)
const
rules
=
this
.
itemRules
.
rules
||
[]
const
val
=
this
.
form
.
_getValue
(
name
,
value
,
rules
)
this
.
form
.
_setDataValue
(
name
,
this
.
form
.
formData
,
val
)
return
val
},
/**
* 移除该表单项的校验结果
*/
clearValidate
()
{
this
.
errMsg
=
''
;
},
// 是否显示星号
_isRequired
()
{
// TODO 不根据规则显示 星号,考虑后续兼容
// if (this.form) {
// if (this.form._isRequiredField(this.itemRules.rules || []) && this.required) {
// return true
// }
// return false
// }
return
this
.
required
},
// 处理对齐方式
_justifyContent
()
{
if
(
this
.
form
)
{
const
{
labelAlign
}
=
this
.
form
let
labelAli
=
this
.
labelAlign
?
this
.
labelAlign
:
labelAlign
;
if
(
labelAli
===
'
left
'
)
return
'
flex-start
'
;
if
(
labelAli
===
'
center
'
)
return
'
center
'
;
if
(
labelAli
===
'
right
'
)
return
'
flex-end
'
;
}
return
'
flex-start
'
;
},
// 处理 label宽度单位 ,继承父元素的值
_labelWidthUnit
(
labelWidth
)
{
// if (this.form) {
// const {
// labelWidth
// } = this.form
return
this
.
num2px
(
this
.
labelWidth
?
this
.
labelWidth
:
(
labelWidth
||
(
this
.
label
?
65
:
'
auto
'
)))
// }
// return '65px'
},
// 处理 label 位置
_labelPosition
()
{
if
(
this
.
form
)
return
this
.
form
.
labelPosition
||
'
left
'
return
'
left
'
},
/**
* 触发时机
* @param {Object} rule 当前规则内时机
* @param {Object} itemRlue 当前组件时机
* @param {Object} parentRule 父组件时机
*/
isTrigger
(
rule
,
itemRlue
,
parentRule
)
{
// bind submit
if
(
rule
===
'
submit
'
||
!
rule
)
{
if
(
rule
===
undefined
)
{
if
(
itemRlue
!==
'
bind
'
)
{
if
(
!
itemRlue
)
{
return
parentRule
===
''
?
'
bind
'
:
'
submit
'
;
}
return
'
submit
'
;
}
return
'
bind
'
;
this
.
formRules
=
formRules
[
name
]
||
{};
this
.
validator
=
validator
;
}
else
{
this
.
labelPos
=
this
.
labelPosition
||
'
left
'
;
this
.
labelWid
=
this
.
labelWidth
||
65
;
this
.
labelAli
=
this
.
labelAlign
||
'
left
'
;
}
},
unInit
(){
if
(
this
.
form
)
{
this
.
form
.
childrens
.
forEach
((
item
,
index
)
=>
{
if
(
item
===
this
)
{
this
.
form
.
childrens
.
splice
(
index
,
1
)
delete
this
.
form
.
formData
[
item
.
name
]
}
return
'
submit
'
;
}
return
'
bind
'
;
},
num2px
(
num
)
{
if
(
typeof
num
===
'
number
'
)
{
return
`
${
num
}
px`
}
return
num
})
}
}
};
</
script
>
<
style
lang=
"scss"
>
.uni-forms-item
{
position
:
relative
;
display
:
flex
;
/* #ifdef APP-NVUE */
// 在 nvue 中,使用 margin-bottom error 信息会被隐藏
padding-bottom
:
22px
;
/* #endif */
/* #ifndef APP-NVUE */
margin-bottom
:
22px
;
/* #endif */
flex-direction
:
row
;
&
__label
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
text-align
:
left
;
font-size
:
14px
;
color
:
#606266
;
height
:
36px
;
padding
:
0
12px
0
0
;
/* #ifndef APP-NVUE */
vertical-align
:
middle
;
flex-shrink
:
0
;
/* #endif */
/* #ifndef APP-NVUE */
box-sizing
:
border-box
;
/* #endif */
&
.no-label
{
padding
:
0
;
},
/**
* 获取父元素实例
*/
getForm
(
name
=
'
uniForms
'
)
{
let
parent
=
this
.
$parent
;
let
parentName
=
parent
.
$options
.
name
;
while
(
parentName
!==
name
)
{
parent
=
parent
.
$parent
;
if
(
!
parent
)
return
false
;
parentName
=
parent
.
$options
.
name
;
}
}
&
__content
{
/* #ifndef MP-TOUTIAO */
// display: flex;
// align-items: center;
/* #endif */
position
:
relative
;
font-size
:
14px
;
flex
:
1
;
/* #ifndef APP-NVUE */
box-sizing
:
border-box
;
/* #endif */
flex-direction
:
row
;
return
parent
;
},
/* #ifndef APP || H5 || MP-WEIXIN || APP-NVUE */
// TODO 因为小程序平台会多一层标签节点 ,所以需要在多余节点继承当前样式
&
>
uni-easyinput
,
&
>
uni-data-picker
{
width
:
100%
;
/**
* 移除该表单项的校验结果
*/
clearValidate
()
{
this
.
errMsg
=
''
;
},
/**
* 子组件调用,如 easyinput
* @param {Object} value
*/
setValue
(
value
)
{
let
name
=
this
.
isArray
?
this
.
arrayField
:
this
.
name
;
if
(
name
)
{
if
(
this
.
errMsg
)
this
.
errMsg
=
''
;
// 给组件赋值
this
.
form
.
formData
[
name
]
=
this
.
form
.
_getValue
(
name
,
value
);
if
(
!
this
.
formRules
||
(
typeof
this
.
formRules
&&
JSON
.
stringify
(
this
.
formRules
)
===
'
{}
'
))
return
;
this
.
triggerCheck
(
this
.
form
.
_getValue
(
this
.
name
,
value
));
}
},
/* #endif */
}
&
.uni-forms-item__nuve-content
{
display
:
flex
;
flex-direction
:
column
;
flex
:
1
;
}
&
__error
{
color
:
#f56c6c
;
font-size
:
12px
;
line-height
:
1
;
padding-top
:
4px
;
position
:
absolute
;
/* #ifndef APP-NVUE */
top
:
100%
;
left
:
0
;
transition
:
transform
0
.3s
;
transform
:
translateY
(
-100%
);
/* #endif */
/* #ifdef APP-NVUE */
bottom
:
5px
;
/* #endif */
opacity
:
0
;
.error-text
{
// 只有 nvue 下这个样式才生效
color
:
#f56c6c
;
font-size
:
12px
;
/**
* 校验规则
* @param {Object} value
*/
async
triggerCheck
(
value
,
formTrigger
)
{
let
promise
=
null
;
this
.
errMsg
=
''
;
// fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题
if
(
!
this
.
validator
||
Object
.
keys
(
this
.
formRules
).
length
===
0
)
return
;
const
isNoField
=
this
.
isRequired
(
this
.
formRules
.
rules
||
[]);
let
isTrigger
=
this
.
isTrigger
(
this
.
formRules
.
validateTrigger
,
this
.
validateTrigger
,
this
.
form
.
validateTrigger
);
let
result
=
null
;
if
(
!!
isTrigger
||
formTrigger
)
{
let
name
=
this
.
isArray
?
this
.
arrayField
:
this
.
name
;
result
=
await
this
.
validator
.
validateUpdate
(
{
[
name
]:
value
},
this
.
form
.
formData
);
}
&
.msg--active
{
opacity
:
1
;
transform
:
translateY
(
0%
);
// 判断是否必填,非必填,不填不校验,填写才校验
if
(
!
isNoField
&&
(
value
===
undefined
||
value
===
''
))
{
result
=
null
;
}
}
// 位置修饰样式
&
.is-direction-left
{
flex-direction
:
row
;
}
&
.is-direction-top
{
flex-direction
:
column
;
.uni-forms-item__label
{
padding
:
0
0
8px
;
line-height
:
1
.5715
;
text-align
:
left
;
/* #ifndef APP-NVUE */
white-space
:
initial
;
/* #endif */
const
inputComp
=
this
.
form
.
inputChildrens
.
find
(
child
=>
child
.
rename
===
this
.
name
);
if
((
isTrigger
||
formTrigger
)
&&
result
&&
result
.
errorMessage
)
{
if
(
inputComp
)
{
inputComp
.
errMsg
=
result
.
errorMessage
;
}
if
(
this
.
form
.
errShowType
===
'
toast
'
)
{
uni
.
showToast
({
title
:
result
.
errorMessage
||
'
校验错误
'
,
icon
:
'
none
'
});
}
if
(
this
.
form
.
errShowType
===
'
modal
'
)
{
uni
.
showModal
({
title
:
'
提示
'
,
content
:
result
.
errorMessage
||
'
校验错误
'
});
}
}
else
{
if
(
inputComp
)
{
inputComp
.
errMsg
=
''
;
}
}
}
.is-required
{
// color: $uni-color-error;
color
:
#dd524d
;
font-weight
:
bold
;
}
}
.uni-forms-item--border
{
margin-bottom
:
0
;
padding
:
10px
0
;
// padding-bottom: 0;
border-top
:
1px
#eee
solid
;
/* #ifndef APP-NVUE */
.uni-forms-item__content
{
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
flex-start
;
.uni-forms-item__error
{
position
:
relative
;
top
:
5px
;
left
:
0
;
padding-top
:
0
;
this
.
errMsg
=
!
result
?
''
:
result
.
errorMessage
;
// 触发validate事件
this
.
form
.
validateCheck
(
result
?
result
:
null
);
// typeof callback === 'function' && callback(result ? result : null);
// if (promise) return promise
return
result
?
result
:
null
;
},
/**
* 触发时机
* @param {Object} event
*/
isTrigger
(
rule
,
itemRlue
,
parentRule
)
{
let
rl
=
true
;
// bind submit
if
(
rule
===
'
submit
'
||
!
rule
)
{
if
(
rule
===
undefined
)
{
if
(
itemRlue
!==
'
bind
'
)
{
if
(
!
itemRlue
)
{
return
parentRule
===
'
bind
'
?
true
:
false
;
}
return
false
;
}
return
true
;
}
return
false
;
}
return
true
;
},
// 是否有必填字段
isRequired
(
rules
)
{
let
isNoField
=
false
;
for
(
let
i
=
0
;
i
<
rules
.
length
;
i
++
)
{
const
ruleData
=
rules
[
i
];
if
(
ruleData
.
required
)
{
isNoField
=
true
;
break
;
}
}
return
isNoField
;
}
/* #endif */
/* #ifdef APP-NVUE */
display
:
flex
;
flex-direction
:
column
;
.uni-forms-item__error
{
position
:
relative
;
top
:
0px
;
left
:
0
;
padding-top
:
0
;
margin-top
:
5px
;
}
/* #endif */
}
};
</
script
>
.is-first-border
{
/* #ifndef APP-NVUE */
border
:
none
;
/* #endif */
/* #ifdef APP-NVUE */
border-width
:
0
;
/* #endif */
<
style
lang=
"scss"
>
.uni-forms-item
{
position
:
relative
;
padding
:
0px
;
text-align
:
left
;
color
:
#333
;
font-size
:
14px
;
// margin-bottom: 22px;
}
.uni-forms-item__box
{
position
:
relative
;
}
.uni-forms-item__inner
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
// flex-direction: row;
// align-items: center;
padding-bottom
:
22px
;
// margin-bottom: 22px;
}
.is-direction-left
{
flex-direction
:
row
;
}
.is-direction-top
{
flex-direction
:
column
;
}
.uni-forms-item__label
{
/* #ifndef APP-NVUE */
display
:
flex
;
flex-shrink
:
0
;
box-sizing
:
border-box
;
/* #endif */
flex-direction
:
row
;
align-items
:
center
;
width
:
65px
;
// line-height: 2;
// margin-top: 3px;
padding
:
5px
0
;
height
:
36px
;
// margin-right: 5px;
.label-text
{
font-size
:
13px
;
color
:
#666666
;
}
.label-seat
{
margin-right
:
5px
;
}
}
.uni-forms-item__content
{
/* #ifndef APP-NVUE */
width
:
100%
;
box-sizing
:
border-box
;
min-height
:
36px
;
/* #endif */
flex
:
1
;
}
.label-icon
{
margin-right
:
5px
;
margin-top
:
-1px
;
}
// 必填
.is-required
{
// color: $uni-color-error;
color
:
#dd524d
;
font-weight
:
bold
;
}
.uni-error-message
{
position
:
absolute
;
bottom
:
0px
;
left
:
0
;
text-align
:
left
;
}
.uni-error-message-text
{
line-height
:
22px
;
color
:
#dd524d
;
font-size
:
12px
;
}
.uni-error-msg--boeder
{
position
:
relative
;
bottom
:
0
;
line-height
:
22px
;
}
.is-input-error-border
{
border-color
:
#dd524d
;
}
.uni-forms-item--border
{
margin-bottom
:
0
;
padding
:
10px
0
;
// padding-bottom: 0;
border-top
:
1px
#eee
solid
;
.uni-forms-item__inner
{
padding
:
0
;
}
}
.uni-forms-item-error
{
// padding-bottom: 0;
}
.is-first-border
{
/* #ifndef APP-NVUE */
border
:
none
;
/* #endif */
/* #ifdef APP-NVUE */
border-width
:
0
;
/* #endif */
}
.uni-forms--no-padding
{
padding
:
0
;
}
</
style
>
uni_modules/uni-forms/components/uni-forms/uni-forms.vue
浏览文件 @
9f767823
<
template
>
<view
class=
"uni-forms"
>
<form>
<view
class=
"uni-forms"
:class=
"
{ 'uni-forms--top': !border }"
>
<form
@
submit.stop=
"submitForm"
@
reset=
"resetForm"
>
<slot></slot>
</form>
</view>
</
template
>
<
script
>
import
Validator
from
'
./validate.js
'
;
import
{
deepCopy
,
getValue
,
isRequiredField
,
setDataValue
,
getDataValue
,
realName
,
isRealName
,
rawData
,
isEqual
}
from
'
./utils.js
'
// #ifndef VUE3
// 后续会慢慢废弃这个方法
import
Vue
from
'
vue
'
;
Vue
.
prototype
.
binddata
=
function
(
name
,
value
,
formName
)
{
if
(
formName
)
{
...
...
@@ -40,15 +26,18 @@
}
};
// #endif
import
Validator
from
'
./validate.js
'
;
/**
* Forms 表单
* @description 由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据
* @tutorial https://ext.dcloud.net.cn/plugin?id=2773
* @property {Object} rules 表单校验规则
* @property {String} validateTrigger = [bind|submit
|blur
] 校验触发器方式 默认 submit
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit
* @value bind 发生变化时触发
* @value submit 提交时触发
* @value blur 失去焦点时触发
* @property {String} labelPosition = [top|left] label 位置 默认 left
* @value top 顶部显示 label
* @value left 左侧显示 label
...
...
@@ -62,34 +51,25 @@
* @value toast 错误信息toast显示
* @value modal 错误信息modal显示
* @event {Function} submit 提交时触发
* @event {Function} validate 校验结果发生变化触发
*/
export
default
{
name
:
'
uniForms
'
,
emits
:
[
'
validate
'
,
'
submit
'
],
options
:
{
virtualHost
:
true
},
components
:
{},
emits
:[
'
input
'
,
'
reset
'
,
'
validate
'
,
'
submit
'
],
props
:
{
// 即将弃用
value
:
{
type
:
Object
,
default
()
{
return
null
;
return
{}
;
}
},
//
vue3
替换 value 属性
// 替换 value 属性
modelValue
:
{
type
:
Object
,
default
()
{
return
null
;
}
},
// 1.4.0 开始将不支持 v-model ,且废弃 value 和 modelValue
model
:
{
type
:
Object
,
default
()
{
return
null
;
return
{};
}
},
// 表单校验规则
...
...
@@ -99,68 +79,58 @@
return
{};
}
},
//校验错误信息提示方式 默认 undertext 取值 [undertext|toast|modal]
errShowType
:
{
type
:
String
,
default
:
'
undertext
'
},
// 校验触发器方式 默认 bind 取值 [bind|submit]
// 校验触发器方式,默认 关闭
validateTrigger
:
{
type
:
String
,
default
:
'
submit
'
default
:
''
},
// label 位置,
默认 left 取值
top/left
// label 位置,
可选值
top/left
labelPosition
:
{
type
:
String
,
default
:
'
left
'
},
// label 宽度
// label 宽度
,单位 px
labelWidth
:
{
type
:
[
String
,
Number
],
default
:
''
},
// label 居中方式,
默认 left 取
值 left/center/right
// label 居中方式,
可选
值 left/center/right
labelAlign
:
{
type
:
String
,
default
:
'
left
'
},
errShowType
:
{
type
:
String
,
default
:
'
undertext
'
},
border
:
{
type
:
Boolean
,
default
:
false
}
},
provide
()
{
return
{
uniForm
:
this
}
},
data
()
{
return
{
// 表单本地值的记录,不应该与传如的值进行关联
formData
:
{},
formRules
:
{}
formData
:
{}
};
},
computed
:
{
// 计算数据源变化的
localData
(
)
{
const
localVal
=
this
.
model
||
this
.
modelValue
||
this
.
value
if
(
localVal
)
{
return
deepCopy
(
localVal
)
dataValue
()
{
if
(
JSON
.
stringify
(
this
.
modelValue
)
===
'
{}
'
)
{
return
this
.
value
}
else
{
return
this
.
modelValue
}
return
{}
}
},
watch
:
{
// 监听数据变化 ,暂时不使用,需要单独赋值
// localData: {},
// 监听规则变化
rules
:
{
handler
:
function
(
val
,
oldVal
)
{
this
.
setRules
(
val
)
},
deep
:
true
,
immediate
:
true
rules
(
newVal
)
{
// 如果规则发生变化,要初始化组件
this
.
init
(
newVal
);
},
labelPosition
()
{
this
.
childrens
.
forEach
(
vm
=>
{
vm
.
init
()
})
}
},
created
()
{
...
...
@@ -186,132 +156,137 @@
}
// #endif
// 子组件实例数组
this
.
childrens
=
[]
// TODO 兼容旧版 uni-data-picker ,新版本中无效,只是避免报错
this
.
inputChildrens
=
[]
this
.
setRules
(
this
.
rules
)
// 存放watch 监听数组
this
.
unwatchs
=
[];
// 存放子组件数组
this
.
childrens
=
[];
// 存放 easyInput 组件
this
.
inputChildrens
=
[];
// 存放 dataCheckbox 组件
this
.
checkboxChildrens
=
[];
// 存放规则
this
.
formRules
=
[];
this
.
init
(
this
.
rules
);
},
// mounted() {
// this.init(this.rules)
// },
methods
:
{
/**
* 外部调用方法
* 设置规则 ,主要用于小程序自定义检验规则
* @param {Array} rules 规则源数据
*/
setRules
(
rules
)
{
// TODO 有可能子组件合并规则的时机比这个要早,所以需要合并对象 ,而不是直接赋值,可能会被覆盖
this
.
formRules
=
Object
.
assign
({},
this
.
formRules
,
rules
)
// 初始化校验函数
this
.
validator
=
new
Validator
(
rules
);
init
(
formRules
)
{
// 判断是否有规则
if
(
Object
.
keys
(
formRules
).
length
===
0
)
{
this
.
formData
=
this
.
dataValue
return
};
this
.
formRules
=
formRules
;
this
.
validator
=
new
Validator
(
formRules
);
this
.
registerWatch
();
},
// 监听 watch
registerWatch
()
{
// 取消监听,避免多次调用 init 重复执行 $watch
this
.
unwatchs
.
forEach
(
v
=>
v
());
this
.
childrens
.
forEach
((
v
)
=>
{
v
.
init
()
})
// watch 每个属性 ,需要知道具体那个属性发变化
Object
.
keys
(
this
.
dataValue
).
forEach
(
key
=>
{
let
watch
=
this
.
$watch
(
'
dataValue.
'
+
key
,
value
=>
{
if
(
!
value
)
return
// 如果是对象 ,则平铺内容
if
(
value
.
toString
()
===
'
[object Object]
'
)
{
for
(
let
i
in
value
)
{
let
name
=
`
${
key
}
[
${
i
}
]`
;
this
.
formData
[
name
]
=
this
.
_getValue
(
name
,
value
[
i
]);
}
}
else
{
this
.
formData
[
key
]
=
this
.
_getValue
(
key
,
value
);
}
},
{
deep
:
true
,
immediate
:
true
}
);
this
.
unwatchs
.
push
(
watch
);
});
},
/**
* 外部调用方法
* 设置数据,用于设置表单数据,公开给用户使用 , 不支持在动态表单中使用
* @param {Object} key
* @param {Object} value
* 公开给用户使用
* 设置校验规则
* @param {Object} formRules
*/
setValue
(
key
,
value
)
{
let
example
=
this
.
childrens
.
find
(
child
=>
child
.
name
===
key
);
if
(
!
example
)
return
null
;
this
.
formData
[
key
]
=
getValue
(
key
,
value
,
(
this
.
formRules
[
key
]
&&
this
.
formRules
[
key
].
rules
)
||
[])
return
example
.
onFieldChange
(
this
.
formData
[
key
]);
setRules
(
formRules
)
{
this
.
init
(
formRules
);
},
/**
* 外部调用方法
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
* @param {Array} keepitem 保留不参与校验的字段
* @param {type} callback 方法回调
* 公开给用户使用
* 设置自定义表单组件 value 值
* @param {String} name 字段名称
* @param {String} value 字段值
*/
validate
(
keepitem
,
callback
)
{
return
this
.
checkAll
(
this
.
formData
,
keepitem
,
callback
);
setValue
(
name
,
value
,
callback
)
{
let
example
=
this
.
childrens
.
find
(
child
=>
child
.
name
===
name
);
if
(
!
example
)
return
null
;
value
=
this
.
_getValue
(
example
.
name
,
value
);
this
.
formData
[
name
]
=
value
;
example
.
val
=
value
;
return
example
.
triggerCheck
(
value
,
callback
);
},
/**
* 外部调用方法
* 部分表单校验
* @param {Array|String} props 需要校验的字段
* @param {Function} 回调函数
* 表单重置
* @param {Object} event
*/
validateField
(
props
=
[],
callback
)
{
props
=
[].
concat
(
props
);
let
invalidFields
=
{};
resetForm
(
event
)
{
this
.
childrens
.
forEach
(
item
=>
{
const
name
=
realName
(
item
.
name
)
if
(
props
.
indexOf
(
name
)
!==
-
1
)
{
invalidFields
=
Object
.
assign
({},
invalidFields
,
{
[
name
]:
this
.
formData
[
name
]
});
item
.
errMsg
=
''
;
const
inputComp
=
this
.
inputChildrens
.
find
(
child
=>
child
.
rename
===
item
.
name
);
if
(
inputComp
)
{
inputComp
.
errMsg
=
''
;
// fix by mehaotian 不触发其他组件的 setValue
inputComp
.
is_reset
=
true
inputComp
.
$emit
(
'
input
'
,
inputComp
.
multiple
?
[]
:
''
);
inputComp
.
$emit
(
'
update:modelValue
'
,
inputComp
.
multiple
?
[]
:
''
);
}
});
return
this
.
checkAll
(
invalidFields
,
[],
callback
);
},
/**
* 外部调用方法
* 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
* @param {Array|String} props 需要移除校验的字段 ,不填为所有
*/
clearValidate
(
props
=
[])
{
props
=
[].
concat
(
props
);
this
.
childrens
.
forEach
(
item
=>
{
if
(
props
.
length
===
0
)
{
item
.
errMsg
=
''
;
}
else
{
const
name
=
realName
(
item
.
name
)
if
(
props
.
indexOf
(
name
)
!==
-
1
)
{
item
.
errMsg
=
''
;
}
if
(
item
.
name
)
{
this
.
formData
[
item
.
name
]
=
this
.
_getValue
(
item
.
name
,
''
);
}
});
this
.
$emit
(
'
reset
'
,
event
);
},
/**
* 外部调用方法 ,即将废弃
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
* @param {Array} keepitem 保留不参与校验的字段
* @param {type} callback 方法回调
* 触发表单校验,通过 @validate 获取
* @param {Object} validate
*/
submit
(
keepitem
,
callback
,
type
)
{
for
(
let
i
in
this
.
dataValue
)
{
const
itemData
=
this
.
childrens
.
find
(
v
=>
v
.
name
===
i
);
if
(
itemData
)
{
if
(
this
.
formData
[
i
]
===
undefined
)
{
this
.
formData
[
i
]
=
this
.
_getValue
(
i
,
this
.
dataValue
[
i
]);
}
}
}
if
(
!
type
)
{
console
.
warn
(
'
submit 方法即将废弃,请使用validate方法代替!
'
);
}
return
this
.
checkAll
(
this
.
formData
,
keepitem
,
callback
,
'
submit
'
);
validateCheck
(
validate
)
{
if
(
validate
===
null
)
validate
=
null
;
this
.
$emit
(
'
validate
'
,
validate
);
},
// 校验所有
async
checkAll
(
invalidFields
,
keepitem
,
callback
,
type
)
{
// 不存在校验规则 ,则停止校验流程
if
(
!
this
.
validator
)
return
/**
* 校验所有或者部分表单
*/
async
validateAll
(
invalidFields
,
type
,
keepitem
,
callback
)
{
let
childrens
=
[]
// 处理参与校验的item实例
for
(
let
i
in
invalidFields
)
{
const
item
=
this
.
childrens
.
find
(
v
=>
realName
(
v
.
name
)
===
i
)
const
item
=
this
.
childrens
.
find
(
v
=>
v
.
name
===
i
)
if
(
item
)
{
childrens
.
push
(
item
)
}
}
// 如果validate第一个参数是funciont ,那就走回调
if
(
!
callback
&&
typeof
keepitem
===
'
function
'
)
{
callback
=
keepitem
;
}
let
promise
;
// 如果不存在回调,那么使用 Promise 方式返回
if
(
!
callback
&&
typeof
callback
!==
'
function
'
&&
Promise
)
{
promise
=
new
Promise
((
resolve
,
reject
)
=>
{
callback
=
function
(
valid
,
invalidFields
)
{
...
...
@@ -321,39 +296,47 @@
}
let
results
=
[];
// 避免引用错乱 ,建议拷贝对象处理
let
tempFormData
=
JSON
.
parse
(
JSON
.
stringify
(
invalidFields
))
// 所有子组件参与校验,使用 for 可以使用 awiat
for
(
let
i
in
childrens
)
{
const
child
=
childrens
[
i
]
let
name
=
realName
(
child
.
name
);
const
result
=
await
child
.
onFieldChange
(
tempFormData
[
name
]);
if
(
result
)
{
results
.
push
(
result
);
// toast ,modal 只需要执行第一次就可以
if
(
this
.
errShowType
===
'
toast
'
||
this
.
errShowType
===
'
modal
'
)
break
;
let
newFormData
=
{};
if
(
this
.
validator
)
{
for
(
let
key
in
childrens
)
{
const
child
=
childrens
[
key
];
let
name
=
child
.
isArray
?
child
.
arrayField
:
child
.
name
;
if
(
child
.
isArray
)
{
if
(
child
.
name
.
indexOf
(
'
[
'
)
!==
-
1
&&
child
.
name
.
indexOf
(
'
]
'
)
!==
-
1
)
{
const
fieldData
=
child
.
name
.
split
(
'
[
'
);
const
fieldName
=
fieldData
[
0
];
const
fieldValue
=
fieldData
[
1
].
replace
(
'
]
'
,
''
);
if
(
!
newFormData
[
fieldName
])
{
newFormData
[
fieldName
]
=
{};
}
newFormData
[
fieldName
][
fieldValue
]
=
this
.
_getValue
(
name
,
invalidFields
[
name
]);
}
}
else
{
newFormData
[
name
]
=
this
.
_getValue
(
name
,
invalidFields
[
name
]);
}
const
result
=
await
child
.
triggerCheck
(
invalidFields
[
name
],
true
);
if
(
result
)
{
results
.
push
(
result
);
if
(
this
.
errShowType
===
'
toast
'
||
this
.
errShowType
===
'
modal
'
)
break
;
}
}
}
else
{
newFormData
=
invalidFields
}
if
(
Array
.
isArray
(
results
))
{
if
(
results
.
length
===
0
)
results
=
null
;
}
if
(
Array
.
isArray
(
keepitem
))
{
keepitem
.
forEach
(
v
=>
{
let
vName
=
realName
(
v
);
let
value
=
getDataValue
(
v
,
this
.
localData
)
if
(
value
!==
undefined
)
{
tempFormData
[
vName
]
=
value
}
newFormData
[
v
]
=
this
.
dataValue
[
v
];
});
}
// TODO submit 即将废弃
if
(
type
===
'
submit
'
)
{
this
.
$emit
(
'
submit
'
,
{
detail
:
{
value
:
temp
FormData
,
value
:
new
FormData
,
errors
:
results
}
});
...
...
@@ -361,37 +344,129 @@
this
.
$emit
(
'
validate
'
,
results
);
}
// const resetFormData = rawData(tempFormData, this.localData, this.name)
let
resetFormData
=
{}
resetFormData
=
rawData
(
tempFormData
,
this
.
name
)
callback
&&
typeof
callback
===
'
function
'
&&
callback
(
results
,
resetFormData
);
callback
&&
typeof
callback
===
'
function
'
&&
callback
(
results
,
newFormData
);
if
(
promise
&&
callback
)
{
return
promise
;
}
else
{
return
null
;
}
},
submitForm
()
{},
/**
* 外部调用方法
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
*/
submit
(
keepitem
,
callback
,
type
)
{
for
(
let
i
in
this
.
dataValue
)
{
const
itemData
=
this
.
childrens
.
find
(
v
=>
v
.
name
===
i
);
if
(
itemData
)
{
if
(
this
.
formData
[
i
]
===
undefined
)
{
this
.
formData
[
i
]
=
this
.
_getValue
(
i
,
this
.
dataValue
[
i
]);
}
}
}
if
(
!
type
)
{
console
.
warn
(
'
submit 方法即将废弃,请使用validate方法代替!
'
);
}
return
this
.
validateAll
(
this
.
formData
,
'
submit
'
,
keepitem
,
callback
);
},
/**
* 外部调用方法
* 校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
*/
validate
(
keepitem
,
callback
)
{
return
this
.
submit
(
keepitem
,
callback
,
true
);
},
/**
* 返回validate事件
* @param {Object} result
* 部分表单校验
* @param {Object} props
* @param {Object} cb
*/
validateField
(
props
,
callback
)
{
props
=
[].
concat
(
props
);
let
invalidFields
=
{};
this
.
childrens
.
forEach
(
item
=>
{
if
(
props
.
indexOf
(
item
.
name
)
!==
-
1
)
{
invalidFields
=
Object
.
assign
({},
invalidFields
,
{
[
item
.
name
]:
this
.
formData
[
item
.
name
]
});
}
});
return
this
.
validateAll
(
invalidFields
,
'
submit
'
,
[],
callback
);
},
/**
* 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
*/
validateCheck
(
result
)
{
this
.
$emit
(
'
validate
'
,
result
);
resetFields
(
)
{
this
.
resetForm
(
);
},
_getValue
:
getValue
,
_isRequiredField
:
isRequiredField
,
_setDataValue
:
setDataValue
,
_getDataValue
:
getDataValue
,
_realName
:
realName
,
_isRealName
:
isRealName
,
_isEqual
:
isEqual
/**
* 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
*/
clearValidate
(
props
)
{
props
=
[].
concat
(
props
);
this
.
childrens
.
forEach
(
item
=>
{
const
inputComp
=
this
.
inputChildrens
.
find
(
child
=>
child
.
rename
===
item
.
name
);
if
(
props
.
length
===
0
)
{
item
.
errMsg
=
''
;
if
(
inputComp
)
{
inputComp
.
errMsg
=
''
;
}
}
else
{
if
(
props
.
indexOf
(
item
.
name
)
!==
-
1
)
{
item
.
errMsg
=
''
;
if
(
inputComp
)
{
inputComp
.
errMsg
=
''
;
}
}
}
});
},
/**
* 把 value 转换成指定的类型
* @param {Object} key
* @param {Object} value
*/
_getValue
(
key
,
value
)
{
const
rules
=
(
this
.
formRules
[
key
]
&&
this
.
formRules
[
key
].
rules
)
||
[];
const
isRuleNum
=
rules
.
find
(
val
=>
val
.
format
&&
this
.
type_filter
(
val
.
format
));
const
isRuleBool
=
rules
.
find
(
val
=>
(
val
.
format
&&
val
.
format
===
'
boolean
'
)
||
val
.
format
===
'
bool
'
);
// 输入值为 number
if
(
isRuleNum
)
{
value
=
isNaN
(
value
)
?
value
:
value
===
''
||
value
===
null
?
null
:
Number
(
value
);
}
// 简单判断真假值
if
(
isRuleBool
)
{
value
=
!
value
?
false
:
true
;
}
return
value
;
},
/**
* 过滤数字类型
* @param {Object} format
*/
type_filter
(
format
)
{
return
format
===
'
int
'
||
format
===
'
double
'
||
format
===
'
number
'
||
format
===
'
timestamp
'
;
}
}
};
</
script
>
<
style
lang=
"scss"
>
.uni-forms
{}
</
style
>
<
style
lang=
"scss"
>
.uni-forms
{
// overflow: hidden;
// padding: 10px 15px;
}
.uni-forms--top
{
// padding: 10px 15px;
// padding-top: 22px;
}
</
style
>
uni_modules/uni-forms/package.json
浏览文件 @
9f767823
{
"id"
:
"uni-forms"
,
"displayName"
:
"uni-forms 表单"
,
"version"
:
"1.
4.8
"
,
"version"
:
"1.
3.2
"
,
"description"
:
"由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据"
,
"keywords"
:
[
"uni-ui"
,
...
...
@@ -17,7 +17,11 @@
"directories"
:
{
"example"
:
"../../temps/example_temps"
},
"dcloudext"
:
{
"dcloudext"
:
{
"category"
:
[
"前端组件"
,
"通用组件"
],
"sale"
:
{
"regular"
:
{
"price"
:
"0.00"
...
...
@@ -34,8 +38,7 @@
"data"
:
"无"
,
"permissions"
:
"无"
},
"npmurl"
:
"https://www.npmjs.com/package/@dcloudio/uni-ui"
,
"type"
:
"component-vue"
"npmurl"
:
"https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules"
:
{
"dependencies"
:
[
...
...
@@ -71,8 +74,7 @@
"阿里"
:
"y"
,
"百度"
:
"y"
,
"字节跳动"
:
"y"
,
"QQ"
:
"y"
,
"京东"
:
"u"
"QQ"
:
"y"
},
"快应用"
:
{
"华为"
:
"u"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录