Skip to content

Commit 21a2855

Browse files
committed
基本完成form表单组件
1 parent c33b937 commit 21a2855

File tree

8 files changed

+295
-30
lines changed

8 files changed

+295
-30
lines changed

pages.json

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
"easycom": {
33
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
44
},
5-
// "condition": { //模式配置,仅开发期间生效
6-
// "current": 0, //当前激活的模式(list 的索引项)
7-
// "list": [{
8-
// "name": "test", //模式名称
9-
// "path": "pages/componentsC/grid/index", //启动页面,必选
10-
// "query": "id=1&name=2" //启动参数,在页面的-+onLoad函数里面得到
11-
// }]
12-
// },
5+
"condition": { //模式配置,仅开发期间生效
6+
"current": 0, //当前激活的模式(list 的索引项)
7+
"list": [{
8+
"name": "test", //模式名称
9+
"path": "pages/componentsA/form/index", //启动页面,必选
10+
"query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到
11+
}]
12+
},
1313
"pages": [
1414
// 演示-组件
1515
{
@@ -450,6 +450,13 @@
450450
{
451451
"root": "pages/componentsA",
452452
"pages": [
453+
// form-表单
454+
{
455+
"path": "form/index",
456+
"style": {
457+
"navigationBarTitleText": "form-表单"
458+
}
459+
},
453460
// slider-滑动选择器
454461
{
455462
"path": "slider/index",

pages/componentsA/field/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
:required="required"
2222
:icon="icon2"
2323
>
24-
<u-button v-if="showBtn" slot="button" size="mini" type="success">发送验证码</u-button>
24+
<u-button v-if="showBtn" slot="right" size="mini" type="success">发送验证码</u-button>
2525
</u-field>
2626
</u-cell-group>
2727
</view>

pages/componentsA/form/index.vue

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<view class="">
3+
<u-form :model="model" :rules="rules">
4+
<u-form-item :label="label" prop="name">
5+
<u-input v-model="model.name" />
6+
</u-form-item>
7+
</u-form>
8+
</view>
9+
</template>
10+
11+
<script>
12+
export default {
13+
data() {
14+
return {
15+
model: {
16+
name: ''
17+
},
18+
rules: {
19+
name: [
20+
{ required: true, message: '请输入活动名称', trigger: 'change' },
21+
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'change' }
22+
]
23+
},
24+
label: 'name'
25+
};
26+
},
27+
computed: {
28+
current() {
29+
return this.show ? 0 : 1;
30+
}
31+
},
32+
methods: {
33+
showChange(index) {
34+
this.show = !index;
35+
},
36+
titleChange(index) {
37+
this.showTitle = !index;
38+
this.show = true;
39+
},
40+
contentChange(index) {
41+
this.contentSlot = !index;
42+
this.content = !index;
43+
this.show = true;
44+
},
45+
asyncChange(index) {
46+
this.show = true;
47+
this.asyncClose = !index;
48+
},
49+
confirm() {
50+
setTimeout(() => {
51+
this.show = false;
52+
}, 2000)
53+
}
54+
}
55+
};
56+
</script>
57+
58+
<style scoped lang="scss">
59+
60+
</style>
Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,132 @@
11
<template>
22
<view class="u-form-item">
3-
<slot />
3+
<view>{{label}}</view>
4+
<view class="">
5+
<slot />
6+
<view :class="isRequired?'ai-form-item-label-required':''" class="ai-form-item-message" v-if="validateState==='error'">{{validateMessage}}</view>
7+
</view>
48
</view>
59
</template>
610

711
<script>
8-
export default {
9-
data() {
10-
return {
11-
12+
import Emitter from '../../libs/util/emitter.js';
13+
import schema from '../../libs/util/async-validator';
14+
export default {
15+
name: 'u-form-item',
16+
mixins: [Emitter],
17+
inject: ['uForm'],
18+
props: {
19+
// input的label提示语
20+
label: {
21+
type: String,
22+
default: ''
23+
},
24+
// 绑定的值
25+
prop: {
26+
type: String,
27+
default: ''
28+
}
29+
},
30+
data() {
31+
return {
32+
initialValue: '', // 存储的默认值
33+
isRequired: false, // 是否必填
34+
validateState: '', // 是否校验成功
35+
validateMessage: '' // 校验失败的提示语
36+
};
37+
},
38+
computed: {
39+
fieldValue() {
40+
return this.uForm.model[this.prop];
41+
}
42+
},
43+
methods: {
44+
// 判断是否需要required校验
45+
setRules() {
46+
let that = this;
47+
// 从父组件u-form拿到当前u-form-item需要验证 的规则
48+
let rules = this.getRules();
49+
if (rules.length) {
50+
this.isRequired = rules.some(rule => {
51+
// 如果有必填项,就返回,没有的话,就是undefined
52+
return rule.required;
53+
});
1254
}
55+
56+
// blur事件
57+
this.$on('on-form-blur', that.onFieldBlur);
58+
// change事件
59+
this.$on('on-form-change', that.onFieldChange);
1360
},
14-
methods: {
15-
61+
62+
// 从u-form的rules属性中,取出当前u-form-item的校验规则
63+
getRules() {
64+
// 父组件的所有规则
65+
let rules = this.uForm.rules;
66+
rules = rules ? rules[this.prop] : [];
67+
// 保证返回的是一个数组形式
68+
return [].concat(rules || []);
69+
},
70+
71+
// blur事件时进行表单校验
72+
onFieldBlur() {
73+
this.validation('blur');
74+
},
75+
76+
// change事件进行表单校验
77+
onFieldChange() {
78+
this.validation('change');
79+
},
80+
81+
// 过滤出符合要求的rule规则
82+
getFilteredRule(trigger) {
83+
let rules = this.getRules();
84+
// 历遍判断规则是否有对应的事件,比如blur,change触发等的事件
85+
return rules.filter(res => !res.trigger || trigger.indexOf(trigger) !== -1);
86+
},
87+
88+
// 校验数据
89+
validation(trigger, callback = () => {}) {
90+
// blur和change是否有当前方式的校验规则
91+
let rules = this.getFilteredRule(trigger);
92+
// 判断是否有验证规则
93+
if (!rules || rules.length === 0) return;
94+
// 设置当前的装填,标识为校验中
95+
this.validateState = 'validating';
96+
// 调用async-validator的方法
97+
let validator = new schema({ [this.prop]: rules });
98+
validator.validate({ [this.prop]: this.fieldValue }, { firstFields: true }, (errors, fields) => {
99+
// 记录状态和报错信息
100+
this.validateState = !errors ? 'success' : 'error';
101+
this.validateMessage = errors ? errors[0].message : '';
102+
// 调用回调方法
103+
callback(this.validateMessage);
104+
});
105+
},
106+
107+
// 清空当前的u-form-item
108+
resetField() {
109+
this.uForm.model[this.prop] = this.initialValue;
16110
}
111+
},
112+
113+
// 组件创建完成时,将当前实例保存到u-form中
114+
mounted() {
115+
// 如果没有传入prop,就不进行校验
116+
if (!this.prop) return;
117+
// 发出事件,让父组件将本实例加入到管理数组中
118+
this.dispatch('u-form', 'on-form-item-add', this);
119+
// 设置初始值
120+
this.initialValue = this.fieldValue;
121+
// 添加表单校验
122+
this.setRules();
123+
},
124+
125+
// 组件销毁前,将实例从 Form 的缓存中移除
126+
beforeDestroy() {
127+
this.dispatch('u-form', 'on-form-item-remove', this);
17128
}
129+
};
18130
</script>
19131

20-
<style>
21-
</style>
132+
<style></style>

uview-ui/components/u-form/u-form.vue

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ export default {
1010
model: {
1111
type: Object,
1212
default() {
13-
return {}
13+
return {};
1414
}
1515
},
1616
// 验证规则
1717
rules: {
1818
type: Object,
1919
default() {
20-
return {}
20+
return {};
2121
}
2222
}
2323
},
@@ -28,28 +28,58 @@ export default {
2828
},
2929
data() {
3030
return {
31-
// 存储当前form下的所有u-form的示例
32-
fields: []
31+
3332
};
3433
},
3534
created() {
35+
// 存储当前form下的所有u-form-item的实例
36+
// 不能定义在data中,否则微信小程序会造成循环引用而报错
37+
this.fields = [];
3638
// 存当前实例
37-
let that =this;
39+
let that = this;
3840
// 监听on-form-item-add事件,将子组件添加到fields中
39-
this.$on('on-form-item-add',item=>{
41+
this.$on('on-form-item-add', item => {
4042
if (item) {
4143
that.fields.push(item);
4244
}
4345
});
4446
// 删除当前有的实例
45-
this.$on('on-form-item-remove',item=>{
47+
this.$on('on-form-item-remove', item => {
4648
// 如果当前没有prop的话表示当前不要进行删除(因为没有注入)
4749
if (item.prop) {
4850
that.fields.splice(that.fields.indexOf(item), 1);
4951
}
50-
})
52+
});
5153
},
52-
methods: {}
54+
methods: {
55+
// 清空所有u-form-item组件的内容,本质上是调用了u-form-item组件中的resetField()方法
56+
resetFields() {
57+
this.fields.map(field => {
58+
field.resetField();
59+
})
60+
},
61+
// 校验全部数据
62+
validate(callback) {
63+
return new Promise(resolve => {
64+
// 对所有的u-form-item进行校验
65+
let valid = true; // 默认通过
66+
let count = 0; // 用于标记是否检查完毕
67+
this.fields.map(field => {
68+
// 调用每一个u-form-item实例的validation的校验方法
69+
field.validation('', error => {
70+
// 如果任意一个u-form-item校验不通过,就意味着整个表单不通过
71+
if(error) valid = false;
72+
// 当历遍了所有的u-form-item时,调用promise的then方法
73+
if(++count === this.fields.length) {
74+
resolve(valid); // 进入promise的then方法
75+
// 调用回调方法
76+
if(typeof callback == 'function') callback(valid);
77+
}
78+
})
79+
})
80+
})
81+
}
82+
}
5383
};
5484
</script>
5585

uview-ui/components/u-icon/u-icon.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<view class="u-icon" :class="[labelPos == 'bottom' ? 'u-flex-col u-row-center' : 'u-flex u-col-center']">
3-
<text class="u-icon__icon" :class="customClass" :style="[iconStyle]" @tap.stop="click" :hover-class="hoverClass" @touchstart.stop="touchstart"></text>
3+
<text class="u-icon__icon" :class="customClass" :style="[iconStyle]" @tap.stop.prevent="click" :hover-class="hoverClass" @touchstart.stop.prevent="touchstart"></text>
44
<text v-if="label" class="u-icon__label" :style="{
55
color: labelColor,
66
fontSize: labelSize + 'rpx',
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<input type="text" @input="handleInput" @blur="handleBlur" :value="defaultValue" />
3+
</template>
4+
5+
<script>
6+
import Emitter from '../../libs/util/emitter.js';
7+
export default {
8+
name: 'u-input',
9+
mixins: [Emitter],
10+
props: {
11+
value: {
12+
type: String,
13+
default: '1234'
14+
}
15+
},
16+
data() {
17+
return {
18+
defaultValue: this.value
19+
};
20+
},
21+
watch: {
22+
value(val) {
23+
this.defaultValue = val;
24+
}
25+
},
26+
methods: {
27+
/**
28+
* change 事件
29+
* @param event
30+
*/
31+
handleInput(event) {
32+
// 当前model 赋值
33+
this.defaultValue = event.detail.value;
34+
// vue 原生的方法 return 出去
35+
this.$emit('input', event.detail.value);
36+
// 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上
37+
// 尚未更新到u-form-item,导致获取的值为空,从而校验混论
38+
this.$nextTick(() => {
39+
// 将当前的值发送到 u-form-item 进行校验
40+
this.dispatch('u-form-item', 'on-form-change', event.detail.value);
41+
})
42+
},
43+
/**
44+
* blur 事件
45+
* @param event
46+
*/
47+
handleBlur(event) {
48+
// vue 原生的方法 return 出去
49+
this.$emit('blur', event.detail.value);
50+
this.$nextTick(() => {
51+
// 将当前的值发送到 u-form-item 进行校验
52+
this.dispatch('u-form-item', 'on-form-blur', event.detail.value);
53+
})
54+
}
55+
}
56+
};
57+
</script>

0 commit comments

Comments
 (0)