RaySaii/old_blog

rxjs在特定场景下的妙用

Closed this issue · 0 comments

一个简单的vue的表单注册页面,如何结合异步验证。
上代码:

<script>
    import {
        Observable
    } from 'rxjs/Observable'
    import fromPromise from 'rxjs/add/observable/fromPromise'
    import {
        mapMutations
    } from 'vuex'
    import Tip from './tip.vue'

    function checkUsed(name) {
        return Observable.fromPromise(new Promise(resolve => {
            setTimeout(() => {
                if (name === 'signed') {
                    resolve({
                        "used": true
                    });
                } else {
                    resolve({
                        "used": false
                    })
                }
            }, 1000)
        }))
    };
    export default {
        name: 'sign',
        components: {
            Tip
        },
        data() {
            return {
                time: '',
                name: '',
                password: '',
                checkPass: '',
                pending: false,
                errors: {
                    name: '',
                    password: '',
                    checkPass: ''
                },
                messages: {
                    name: {
                        required: '不能为空',
                        length: '4-18位',
                        used: '已被使用'
                    },
                    password: {
                        required: '不能为空',
                        pattern: '8-16位字母与数字组合'
                    },
                    checkPass: {
                        required: '请确认密码',
                        match: '两次输入不一致'
                    }
                }
            }
        },
        subscriptions() {
            this.$watchAsObservable('name')
                .pluck('newValue')
                .debounceTime(500)
                .distinctUntilChanged()
                .do(val => {
                    this.errors.name = '';
                    let len = val.length;
                    if (len === 0) {
                        this.errors.name = this.messages.name.required;
                        return
                    };
                    if (len <= 3 || len >= 19) {
                        this.errors.name = this.messages.name.length;
                        return
                    }
                })
                .filter(val => val.length > 3 && val.length < 19)
                .do(() => this.pending = true)
                .switchMap(checkUsed)
                .do(() => this.pending = false)
                .subscribe(res => {
                    if (res.used === true) {
                        this.errors.name = this.messages.name.used
                    }
                })
        },
        computed: {
            vaild() {
                for (var field in this.errors) {
                    if (!this.name || !this.password || !this.checkPass || this.errors[field] !== '') {
                        return false
                    }
                }
                return true
            }
        },
        watch: {
            password: function(val) {
                this.errors.password = '';
                if (val.length === 0) {
                    this.errors.password = this.messages.password.required;
                    return
                }
                var re = new RegExp("^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$");
                if (!re.test(val)) {
                    this.errors.password = this.messages.password.pattern;
                }
                if (val !== this.checkPass) {
                    this.errors.checkPass = this.messages.checkPass.match;
                }
            },
            checkPass: function(val) {
                this.errors.checkPass = '';
                if (val.length === 0) {
                    this.errors.checkPass = this.messages.checkPass.required;
                    return
                }
                if (val !== this.password) {
                    this.errors.checkPass = this.messages.checkPass.match;
                    return
                }
            },
        },

        created() {

        },
        mounted() {

        },
        methods: {
            submit() {
                console.log(this.name, this.password);
                this.$store.commit('sign', {
                    'name': this.name,
                    'password': this.password
                })
                this.time = true;
                setTimeout(() => {
                    this.$router.push('login')
                }, 2000)
            }
        }
    }
</script>

这是注册界面的代码。

validation1
将name的值变化视作流
validation2
间隔超过0.5s视作一次变化
validation3
与上一个值不同才发送请求

subscriptions() {
            this.$watchAsObservable('name')
                .pluck('newValue')
                .debounceTime(500)
                .distinctUntilChanged()
                .do(val => {
                    this.errors.name = '';
                    let len = val.length;
                    if (len === 0) {
                        this.errors.name = this.messages.name.required;
                        return
                    };
                    if (len <= 3 || len >= 19) {
                        this.errors.name = this.messages.name.length;
                        return
                    }
                })
                .filter(val => val.length > 3 && val.length < 19)
                .do(() => this.pending = true)
                .switchMap(checkUsed)
                .do(() => this.pending = false)
                .subscribe(res => {
                    if (res.used === true) {
                        this.errors.name = this.messages.name.used
                    }
                })
        },

这是用户输入与验证的部分。利用vue-rx提供的功能,将name变为可观察对象。

  • filter是过滤name值的长度。
  • debounceTime功能是用户抬手0.5秒后看做一次输入
  • distinctUntilChanged直到值改变再向下传值。
  • do是做一些流之外的功能的操作符。
  • switchMap是将符合规则的值,向服务器发送进行验证,可以将请求序列化,比如最近的一次请求如果有返回,那么就不去管其他请求。
  • subscribe订阅这个可观察对象(指的是请求的返回结果)。这里要注意的是,要将请求的返回结果包装为一个observable即可观察对象。
function checkUsed(name) {
        return Observable.fromPromise(new Promise(resolve => {
            setTimeout(() => {
                if (name === 'signed') {
                    resolve({
                        "used": true
                    });
                } else {
                    resolve({
                        "used": false
                    })
                }
            }, 1000)
        }))
    };

vue中网络请求如果要使用rxjs,都要将请求结果变为observable