WebApp【公共组件库】@前端(For Git Submodule)
Tevin
2021-03-31 3cafdf134729197e22a53f79dd25c45db2062fa3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
 * CFormItem - 表单套装组件,单项包囊器
 * @author Tevin
 * @tutorial rules see https://github.com/yiminghe/async-validator#type
 */
 
<template>
    <view class="c-form-item">
        <slot :itemRes="itemRes" />
    </view>
</template>
 
<script>
import Schema from 'async-validator';
import { validateMsgs } from './validateMsgs.js';
 
export default {
    name: 'CFormItem',
    props: {
        // 表单数据资源(表单组件内部机制专用)
        formRes: Object,
        // 表单项字段键名
        name: String,
        // 表单项中文名
        label: String,
        // 表单项验证规则之是否必填
        required: Boolean,
        // 表单项验证规则之复合规则
        //   例如:[{type:'string', min: 2, max: 100}]
        //   常用项:
        //     type        string           类型,常见有 string、number、boolean、array、object、url、email
        //     len         number           string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度
        //     max         number           必须设置 type:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度
        //     min         number           必须设置 type:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度
        //     pattern     RegExp           正则表达式匹配
        //     required    boolean          是否为必选字段
        //     transform   (value) => any   将字段值转换成目标值后进行校验
        //     message     string           错误信息,不设置时会通过模板自动生成
        rules: Array,
        // 表单是否禁用
        disabled: Boolean,
    },
    data() {
        return {
            error: false,
        };
    },
    computed: {
        itemRes() {
            return {
                formData: this.formRes.formData,
                name: this.name,
                label: this.label,
                required: this.isRequired,
                disabled: this.disabled,
                error: this.error,
                onChange: evt => this.onChange(evt),
            };
        },
        isRequired() {
            if (this.required) {
                return true;
            } else {
                if (!this.rules || this.rules.length === 0) {
                    return false;
                } else if (this.rules.length > 0) {
                    for (let rule of this.rules) {
                        if (rule.required) {
                            return true;
                        }
                    }
                    return false;
                }
            }
        },
    },
    methods: {
        onChange(evt) {
            // 当类型为 object 时,必须为简单 object
            if (Object.prototype.toString.call(evt) === '[object Object]') {
                const hasOwn = Object.prototype.hasOwnProperty;
                if (
                    evt.constructor &&
                    !hasOwn.call(evt, 'constructor') &&
                    !hasOwn.call(evt.constructor.prototype, 'isPrototypeOf')
                ) {
                    throw new Error(
                        '错误的表单项 onChange 参数类型!(At: ' + this.name + ')'
                    );
                }
            }
            // 未改变值不触发
            if (this.formRes.formData[this.name] === evt) {
                return;
            }
            this.formRes.$handleChange({
                [this.name]: evt,
            });
        },
    },
    mounted() {
        this.$nextTick(() => {
            // 未设置验证
            if (!this.required && !this.rules) {
                this.formRes.$regItemValidator(this.name, validateType => {
                    this.error = false;
                    return Promise.resolve({
                        name: this.name,
                        passed: true,
                    });
                });
            } else {
                // 验证规则
                const descriptor = this.rules || [];
                if (this.required) {
                    descriptor.unshift({
                        required: true,
                    });
                }
                const validator = new Schema({
                    [this.name]: descriptor,
                });
                // 汉化通用验证消息
                validator.messages(validateMsgs);
                // 注册验证
                let errTimer = null;
                this.formRes.$regItemValidator(this.name, validateType => {
                    return validator
                        .validate({
                            [this.name]: this.formRes.formData[this.name],
                        })
                        .then(
                            res => {
                                this.error = false;
                                return {
                                    name: this.name,
                                    passed: true,
                                };
                            },
                            ({ errors, fields }) => {
                                if (validateType !== 'msgOnly') {
                                    this.error = true;
                                    clearTimeout(errTimer);
                                    errTimer = setTimeout(() => {
                                        this.error = false;
                                    }, 5000);
                                }
                                return {
                                    name: this.name,
                                    passed: false,
                                    msg: errors[0].message.replace(
                                        this.name,
                                        this.label || this.name
                                    ),
                                };
                            }
                        );
                });
            }
        });
    },
    beforeDestroy() {
        this.formRes.$regItemValidator(this.name, null);
    },
};
</script>