用设计模式、this巧妙整理vue中的methods

2,234 阅读6分钟

vue组件中,methods中只能定义函数,有时在开发过程中,一个组件的功能会比较多,导致定义了一堆的函数。这种情况下,methods里堆放了多个函数,占空间不说,调试时找起某个函数也不容易。今天介绍一个技巧来整理methods中的函数,让你的代码思路清晰,整洁清爽。

归类整理

思路就是把罗列堆集的多个函数进行分组,将业务相关的函数集中在一起统一输出。函数其实也是个对象,在js里一切皆是对象。那我就可以定义一个对象,返回这一套业务相关函数就可以了。

本文的例子是一个图片播放功能,就是把一堆图片按照一定顺序播放,有播放、暂停、上一张、下一张、第一张、最后一张这些功能。每个功能都对应一个方法,常规写法就是这样:

methods: {
          first(){
           //dosomthing
          },
          pre(){
            //dosomthing
          },
          play(){
            //dosomthing
          },
          next(){
            //dosomthing
          },
          end(){
            //dosomthing
          },
          stop(){
            //dosomthing
          }
  		}

现在稍微修改一下,看下面的代码,todo函数把这些业务相关的方法全收进去了,前面这些函数都作为一个对象的属性返回。这样处理后,把todo收起来,一下子就节省了一大片空间,有没有很屌(丝)?

  methods: {
    todo() {
        return {
          first(){
           //dosomthing
          },
          pre(){
            //dosomthing
          },
          play(){
            //dosomthing
          },
          next(){
            //dosomthing
          },
          end(){
            //dosomthing
          },
          stop(){
            //dosomthing
          }
        }
    }
  }

命令模式

从设计模式角度来看有点像策略模式,其实又不是,准确说应该是命令模式,因为每个方法做的事情不一样。不过这套函数相互之间会有些关系。比如我点了播放功能,那在播放的时候我点下一张或者最后一张等,就要先停住,再根据当前图片索引走到所需要的那一步。具体逻辑你如果有兴趣,可以自己写一个图片播放功能体会下。

调用方式

在ui层的用法是这样的

<span class="btn">
    <img id="first" src="@/assets/img/1.png" @click="todo().first()" />
    <img id="pre" src="@/assets/img/2.png" @click="todo().pre()" />
    <img id="play" src="@/assets/img/3.png" @click="todo().play()" />
    <img id="next" src="@/assets/img/2-2.png" @click="todo().next()" />
    <img id="end" src="@/assets/img/1-2.png" @click="todo().end()" />
</span>

在ui层调用时要注意的一点:todo这个函数是暴露在methods接口下的,所以要调用到todo方法内返回的函数集对象,就要先调用todo(),得到函数集对象后,才能调用到相应的函数。

作用域和this问题

注意了,问题来了! 如果在next方法中想要调用stop方法,怎么实现呢?这里有多个要点要注意。

看代码,在next方法里像这样"that.stop()"调用stop()方法,是无效的。因为这个that就是前面定义的todo函数内的this,而这个this指向的是组件对象。说白了此时that只能调用到todo,是无法直接调用stop。

methods: {
    todo() {
        var that = this
        return {
          first(){
           //dosomthing
          },
          pre(){
            //dosomthing
          },
          play(){
            //dosomthing
          },
          next(){
            //dosomthing
            //如何调用stop
            that.stop();//undefined
          },
          end(){
            //dosomthing
          },
          stop(){
            //dosomthing
            console.log('stop')
          }
        }
    }
  }

如果你还没有看明白怎么回事,接下来就让我来解释几个概念,帮助你理解。

1、函数作用域

js(es6)中作用域有函数作用域、全局作用域以及块级作用域,这里只讲函数作用域。在函数内部定义的变量,其作用域范围是此函数内部。如果在函数内部用到的变量不在当前函数内定义,它就会顺着作用域链向上查找,直到全局作用域,如果在上级作用域中找到了就会正常执行。这个例子中,在todo中定义的变量,其内部对象都可以调用到,但是todo函数之外的其他函数无法调用,这个都比较熟悉了。如果你有印象的话,我们在vue组件中经常用到this,这个this大部分情况下是指向组件本身的,但有时又不是,下面要分析到。

2、函数的this指向

this在js中非常实用,经常用到,但是你可能经常搞不明白this到底是指向了谁,要真正弄明白怎么用的可能得花点功夫,这里讲几个例子来说明一下。

默认情况下的this指向

在函数里,this默认指向的是全局对象window,但是这个this的指向经常会发生变化,这取决你怎么用它。在上面的例子中可以这样调用,见代码,在todo函数下定义一个that变量,此变量指向的是todo中的this,按前面说的这个this默认指向全局,在此就是当前组件,那that.todo().stop()就可以正常执行了。

methods: {
    todo() {
        var that = this
        return {
          first(){
           //dosomthing
          },
          pre(){
            //dosomthing
          },
          play(){
            //dosomthing
          },
          next(){
            //dosomthing
            //如何调用stop
             that.todo().stop();//stop
          },
          end(){
            //dosomthing
          },
          stop(){
            //dosomthing
            console.log('stop')
          }
        }
    }
  }
todo().netxt();

对象调用其内部方法后的this指向

还有一个情况,在这个例子中,todo函数执行后得到一个对象,然后 在todo().next()这行代码的意思是一个对象调用其内部的一个方法,此时next函数内部的 this就是指向了todo()这个对象本身,就是todo方法中return出来的那个对象,所以前面提到的在next中调用todo()中的其他方法,就可以直接这样用this调用,见代码。你可以调试代码仔细体会下。

methods: {
    todo() {
        var that = this
        return {
          first(){
           //dosomthing
          },
          pre(){
            //dosomthing
          },
          play(){
            //dosomthing
          },
          next(){
            //dosomthing
            //如何调用stop
             that.todo().stop();//stop
            this.stop();//stop
          },
          end(){
            //dosomthing
          },
          stop(){
            //dosomthing
            console.log('stop')
          }
        }
    }
  }
todo().netxt();

3、箭头函数

箭头函数的特殊之处在于,它里面的this会往上查找它的外部函数,外部函数的this指向哪儿它就指哪儿。不过箭头函数在这里用不起来,因为这个例子中不存在嵌套函数:todo里面是个对象,对象里面是一堆并列函数集。我们可以用这个例子来说明下,把this指向讲清楚。

var test = {
    name: 'jw',
    todo() {
        console.log(this.name);//jw
        function dowhat(){
            console.log(this);//Window
        }
        dowhat();
        var dothis = ()=>{
            console.log(this)//{name: "jw", todo: ƒ}
        }
        dothis();
    }
}
test.todo();

执行这段代码,你会发现普通函数dowhat中的this指向了window,这是前面说过的,普通函数中的this默认指向当前全局对象,这是js中的一个著名的坑,记住就行了;dothis中的this是在箭头函数中,指向的是test对象本身,就跟todo函数中的this是一样的,就是前面讲的,箭头函数中的this指向的是其父函数中的this,而这个this指向了test对象,是因为test对象调用了其内部todo方法。你可以这么理解,this就是一个见钱眼开的主,而且天生反骨,谁能指挥它的领导(函数),它就认它领导的领导为亲爸。 这个总结很精辟吧!品一品。

好了,今天的vue开发技巧就分享到这里了,这显然是挂羊头卖狗肉,狗肉就是作用域、this指向,希望对你有用,欢迎点赞分享,谢谢鼓励!