通过闭包函数在父组件中向自定义事件传参

54次阅读

共计 2388 个字符,预计需要花费 6 分钟才能阅读完成。

前言

用 vue 进行开发的过程中,我们常常会用到父子组件通信来支持我们的一些应用场景。在子组件中通过触发自定义事件,并向上层组件传递一定的参数(暂且称为事件参数),但有时候我们也想要在父组件向监听函数传入一定的参数(暂且称为自定义参数)。

比如在同一页面内需要重复使用相同的组件,并且具有事件传参时,我们希望能够传入自定义参数对两个组件进行区别。而这时候就起了冲突,如果传入了自定义参数,那事件无法正确绑定,参数将无法接收到。似乎碰到了一个鱼和熊掌不可兼得的情况。

举例

父组件: page.vue

<template>
  <div>
    <c-component @event_name="eventHandler"/>
    <c-component @event_name="eventHandler"/>
    <c-component @event_name="eventHandler"/>
  </div>
</template>

<script>
  import Component from '...'
  export default {
    name: 'page',
    component: {'c-component': Component},
    data: function() {
      return {params: [1, 2, 3]
      }
    },
    methods: {eventHandler(params) {console.log(params)
      }
    }
  }
</script>

子组件: Component.vue

<template>
  <div>
    ...
  </div>
</template>

<script>
  export default {
    name: 'component',
    created() {this.$emit('event_name', 4)
    }
  }
</script>

情况 1:正常情况下我们都希望接收到子组件传入的参数,eventHandler 将正确地打印出 4,但却无法区分是哪个组件触发的事件;

@event_name="eventHandler" // 4
@event_name="eventHandler" // 4
@event_name="eventHandler" // 4

情况 2:而如果分别传入了参数,eventHandler 方法分别打印的是 123,但在父组件页面渲染时就已经执行,而不是事件发生时。

@event_name="eventHandler(params[0])" //1
@event_name="eventHandler(params[1])" //2
@event_name="eventHandler(params[2])" //3

浅析

为什么上面两种情况分别有不同的结果?我们需要先弄明白这些代码究竟是在干什么,两种情况分别是什么流程。
给事件传入 eventHandler 和 eventHandler() 有什么区别?
当我们在控制台环境,或者 Node 环境定义好一个函数(如 eventHandler)之后,直接输入 eventHandler 并回车执行,你得到的反馈是一个函数定义。

let eventHandler = function(){return 'something'}
evnetHandler
/* 输出:ƒ (){return 'something'}
*/

而输入 eventHandler() 表示我们需要执行这个函数,并获得到这个函数的返回值。

evnetHandler() // 输出:"something"

这个非常简单的道理换个地方有时候却会让人迷惑。

解决方案

通过返回一个闭包函数,闭包函数可以访问到定义时所在上下文的变量,即这里接收的自定义参数 paramsComstumed,也可以被传入到所需要的地方进行接收事件参数 paramsEvent。

以前了解到闭包函数的时候还在想,这个闭包函数到底有什么用。当它作为返回值时,闭包函数就开始大放异彩了。

eventHandler(paramsComstumed) {
  return paramsEvent => {console.log(paramsComstumed, paramsEvent)
  }
}

其他应用

我们通过闭包函数找到了同时接收 vue 父子组件参数的办法,但同时这种手段并不局限于这种应用场景。目前想到的类似的应用:

给 vuex 中的 getters 传参

//store.js:
export default new Vuex.Store({
  state: {param: 1},
  getters: {
    getStateParam: state => {
      return paramReceived => {console.log(state.param, paramReceived)
      }
    }
  }
})

//page.vue:
created() {console.log(this.$store.getters.getStateParam(2)) // 将输出 1 2
}

给 computed 传参

<template>
  <div id="app">
    <div>{{computer(1)}}</div> <!-- 标题 1 -->
    <div>{{computer(2)}}</div> <!-- 标题 2 -->
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {title: '标题'}
  },
  computed: {computer() {
      return param => {return this.title + param}
    }
  }
}
</script>

在模块语法上的应用

//functions.js
let func = function (param1){return function (param2) {console.log(param1, param2)
  }
}
module.exports = func(1)

//process.js
let func = require('./test.js')
func(2) // 将输出 1 2

正文完
 0