当前位置:首页 > Vue watcher oldValue和newValue始终一样,watcher监听一个对象的具体属性

Vue watcher oldValue和newValue始终一样,watcher监听一个对象的具体属性

发布于 2018-08-28 阅读 183 次 Javascript Vue

背景

写这篇文章源于我做的一个项目中需要实时监听一组输入框的合法与否。如下图所示:

如图这是一个图文列表,当切换左侧列表的时候后右侧需要显示对应的可编辑状态,产品的要求是,初始化的时候不能显示错误提示,在输入的时候在进行判断,添加一条新的图文的时候也需要进行判断,但是新添加的也不能显示错误信息,需要输入的时候实时显示。

我本来的解决方法是,

这些图文存在一个数组article里面,用watcher检测article里面的数据是否合法,然后实时显示错误信息,但是遇到一个问题,就是当监听整个article的时候只要里面一个属性发生变化,就会全部执行,这样没有过输入过的输入框的错误信息也被显示出来,这样显的和突兀。

而且在这个过程中我发现一个问题就是newValue 和 oldValue始终是一样的,查阅了相关资料才发现,

相关资料见 链接

解决新旧值始终相同的办法

我所用的办法其实就是克隆一个新的对象
每次在watcher里面将新值克隆一份存在vue的data之中

watch:{
    articles:{
        handler:function(newValue, oldValue){
            this.oldValue = JSON.parse(JSON.stringify(newValue));
            //也可以采用其他方式,注意如果对象中有Date对象需要单独处理,则不可用上面这种方式
        },
        deep:true
    }
}

配合计算属性watcher监听对象属性

所以就想到了要拆开检测,watcher是不能直接监听对象某个属性的变化的,我们需要借助计算属性配合;
相关代码:

computed:{
    curTitle(){
        return this.curArticles.title;
    }
},
watch:{
    curTitle(newValue, oldValue){
        if(newValue == ''){
            this.error.title = '必填项不能为空';
        }else{
            this.error.title = '';
        }
    }
}

采用这种方式后我仍然遇到了问题,因为我监听的是四个属性,但是点击添加一条新图文的时候时要避免watcher的,所以仍然需要做一定的处理,想必你也想到了,对,就是加一个开关,这里涉及的是四个属性分别watcher,所以一个开关变量用true,false显然不行了,所以我用的是数字。废话不多说,直接上完整代码片段:

data:{
//列表
    articles: [
        {
            "title":"",
            "description":"",
            "url":"",
            "picurl":""
        }
    ],
//编辑的图文信息
    curArticles:{
        "title":"",
        "description":"",
        "url":"",
        "picurl":""
    },
//错误提示
    error:{
        "title":"",
        "description":"",
        "url":"",
        "picurl":""
    },
//用来判断是否刚新添加
    added: 0
},
computed:{
    curTitle(){
    //将新的title更新到article
        this.articles[this.cur].title = this.curArticles.title;
        return this.curArticles.title;
    },
    curDescription(){
    //将新的description更新到article
        this.articles[this.cur].description = this.curArticles.description;
        return this.curArticles.description;
    },
    curPicurl(){
        this.articles[this.cur].picurl = this.curArticles.picurl;
        return this.curArticles.picurl;
    },
    curUrl(){
        this.articles[this.cur].url = this.curArticles.url;
        return this.curArticles.url;
    }
},
watch:{
    curTitle(newValue, oldValue){
        if(this.added>0){
            this.added--;
            return;
        }
        if(newValue == ''){
            this.error.title = '必填项不能为空';
        }else{
            this.error.title = '';
        }
    },
    curDescription(newValue, oldValue){
        if(this.added>0){
            this.added--;
            return;
        }
        if(newValue == ''){
            this.error.description = '必填项不能为空';
        }else{
            this.error.description = '';
        }
    },
    curPicurl(newValue, oldValue){
        if(this.added>0){
            this.added--;
            return;
        }
        if(newValue == ''){
            this.error.picurl = '必填项不能为空';
        }else{
            this.error.picurl = '';
        }
    },
    curUrl(newValue,oldValue){
        if(this.added>0){
            this.added--;
            return;
        }
        var reg = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]');
        if(newValue == ''){
            this.error.url = '必填项不能为空';
        }else if(!reg.test(newValue.trim())){
            this.error.url = 'URL地址错误';
        }else{
            this.error.url = '';
        }
    }
},
mounted(){
    //在这里做一些初始化的工作,初始化articles和curArticles
}