【问题标题】:Is it possible to nest methods in Vue.js in order to group related methods?是否可以在 Vue.js 中嵌套方法以对相关方法进行分组?
【发布时间】:2016-07-06 15:47:48
【问题描述】:

我想将我的一些 Vue.js 方法组合到一种“子方法”类中,但我似乎只能拥有单级方法。

例如,如果我想要一组纯粹处理按钮操作的方法:

new Vue({

    el: '#app',

    data: { },

    methods: {

        buttonHandlers: {

            handler1: function() {
                dosomething;
            },

            handler2: function() {
                dosomething;
            }

        }

    }

});

我希望能够使用类似的东西:

<button v-on:click="buttonHandlers.handler1">Click Me</button>

但什么也没发生。

已经尝试通过添加括号来强制函数运行:

<button v-on:click="buttonHandlers.handler1()">Click Me</button>

但我收到此控制台错误:

未捕获的 TypeError:scope.buttonHandlers.handler1 不是函数

我设置了一个小的https://jsfiddle.net/ozx9oc4c/ 来说明我的意思。

如果有人知道在 Vue.js 的父方法下对函数进行逻辑分组的方法,而不是没有真正结构的单级方法的页面和页面,我将不胜感激。

【问题讨论】:

  • 如果你有一页又一页的方法,你很可能应该构建更小的组件。您的按钮很可能应该是它自己的组件。
  • @ceejayoz 完全同意 - 在这种情况下,我实际上正在处理一个多步骤表单,并且很多方法都与验证、步骤进展、字段操作等有关,所以我会如果可能,喜欢将它们保留在单个 Vue 实例中,但分组为逻辑类;我给出的这个按钮示例是我能想到的最快的相关示例。
  • 奇怪的是,2020 年 Vue 团队现在如何尝试将相关选项(方法/计算)组合在一起(组合 API),但不接受让您将相关方法组合在一起的东西

标签: javascript methods vue.js namespaces nested


【解决方案1】:

其实有一个非常简单的技巧:在created钩子中定义你的嵌套方法:

created() {
  this.on = {
    test: () => {console.log(this)}
  }
  this.on.test();
}

注意:有两件事,A)在这种情况下,您必须使用箭头函数,B)如果您觉得这很“骇人听闻”,可能是因为 created 的混乱生命周期钩子,你总是可以委托给一个方法,比如说this.namespaceMethods(),例如:

created() {
  this.namespaceMethods();
  // call namespaced methods
  this.foo.bar();
  this.foobar.baz();
  // etc.
},
methods: {
  this.namespaceMethods() {
    this.foo = {
      bar: () => {console.log("foobar")}
    },
    this.foobar = {
      baz: () => {console.log("foobarbaz")}
    }
  },
  // etc
}

【讨论】:

  • 老实说,我不喜欢它,我使用了一个箭头函数来返回 methods() 中的对象,但仍然觉得很奇怪,所以我将它作为对象撞到了 computed(),我是半自在。仍然感觉有点hacky。 idk,我猜我更喜欢返回对象的函数。我并没有说它丑陋或错误,只是对我个人来说感觉很糟糕。我无意冒犯:)
【解决方案2】:

我使用这种模式:

模板:

<ExampleComponent
  :test="hello"
  @close="(arg) => example('close')(arg)"
  @play="(arg) => example('next')(arg)"
  @stop="(arg) => example('back')(arg)"/>

脚本:

...
methods: {
  test () {
    this.info('open')('test');
  },
  info (arg) {
    console.table({omg: [arg, '!']});
  },
  example (arg) {
    let self = this;
    const methods = {
      open (arg) {self.info(arg);},
      close (arg) { return self.example('play')(arg)},
      play (arg) {console.log(self, this)},
      stop () {console.error('Lo1')},
    };
    if (!Object.keys(methods).includes(arg)) return () => false;
    return methods[arg];
  },
}
...

第二种情况:

脚本:

const fabric = (arg, foo, context) => {
  const methods = foo(context);
  if (!Object.keys(methods).includes(arg)) return () => false;
  return methods[arg];
};

export default {
  ...
  methods: {
    test () {
      this.info('open')('test');
    },
    info (arg) {
      console.table({omg: [arg, '!']});
    },
    example (arg) {
      return fabric(arg, (cnx)=>({
        open (arg) {cnx.info(arg);},
        close (arg) { return cnx.example('play')(arg)},
        play (arg) {console.log(cnx, this)},
        stop () {console.error('Lo1')},
      }), this);
    },
  }
  ...
}

另外,我认为这不是一个好习惯,但它很有效,让我的工作更轻松。

【讨论】:

    【解决方案3】:

    我在编写 Vue mixin 时遇到了同样的问题(需要命名空间)。这个答案没有直接解决你的情况,但它可以提供线索。

    这就是我定义 mixin 的方式。

    export default {
       created () {
        // How to call the "nested" method
        this.dummy('init')
    
        // Pass arguments
        this.dummy('greet', {'name': 'John'})
       },
    
       // Namespaced methods
       methods: {
         dummy (name, conf) {
           // you can access reactive data via `that` reference,
           // from inside your functions
           const that = this
    
           return {
             'init': function (conf) {
                console.log('dummy plugin init OK')
             },
             'greet': function (conf) {
                console.log('hello, ' + conf['name'])
             }
           }[name](conf)
         }
       }
     }
    

    PS:官方解决方案,Evan You said no

    【讨论】:

      【解决方案4】:

      我最接近的做法是将父级声明为一个函数,并返回一个带有一组方法的对象。

      例子:

      new Vue({
      
        el: '#app',
      
        data: {},
      
        methods: {
      
          buttonHandlers: function() {
            var self = this; // so you can access the Vue instance below.
      
            return {
      
              handler1: function() {
                dosomething;
                self.doSomething();
              },
      
              handler2: function() {
                dosomething;
              },
      
            },
      
          }
      
        }
      
      });
      

      你可以像这样调用方法:

      <button @click="buttonHandlers().handler1()">Click Me</button>
      

      【讨论】:

      • 我一直在使用这个答案,但我最近发现你可以使用现代语法来避免var self = this。您现在可以编写像handler1(){} 这样的子函数,它将this 上下文保持在该函数范围内。 而且 通常你不想再使用var 而是使用constlet 来避免奇怪的变量作用域。
      • 我不能再编辑我的消息了,但我的意思是handler1: () =&gt; {}箭头函数捕获this
      • 我无法让它在 Google Chrome 91 上运行。我的分组箭头函数类似于 grouping_func: () =&gt; ({ method1: () =&gt; {}, ... }) 但在方法 1 中它指向 grouping_func 对象。
      【解决方案5】:

      如果我有这个问题,我会使用 click handler() 将请求委托给其他方法。 例如:

      new Vue({
      
          el: '#app',
      
          data: { },
      
          methods: {
      
              handler1: function() {
                   console.log("handler 1 called");
              },
      
              handler2: function() {
                  console.log("handler 2 called");
              },
      
              buttonHandler:function(callback){
                  callback();
              }
      
      
          }
      
      });
      

      并使用html作为

      <button v-on:click="buttonHandler(handler1)">Click Me</button>
      
      <button v-on:click="buttonHandler(handler2)">Click Me</button>
      

      代码仅供演示。 在现实生活中,我将在模板中传递一个数字或字符串参数,并使用 switch case 来确定处理程序。

      【讨论】:

      • 不幸的是,这个解决方案仍然让我处于相同的位置,我最终在我的 methods 对象的顶层有 3 个函数 - 层次结构中没有逻辑组织。
      • 嗯,你能详细说明你的用例吗?还有你在谈论多少种方法和逻辑分区?哦,请在您的帖子中添加信息,而不是在此处的 cmets 中
      猜你喜欢
      • 2017-06-15
      • 1970-01-01
      • 2022-01-09
      • 2021-12-04
      • 1970-01-01
      • 2016-04-09
      • 1970-01-01
      • 1970-01-01
      • 2018-08-07
      相关资源
      最近更新 更多