功能组件的子事件处理程序中的“ this”上下文

时间:2018-11-12 14:39:09

标签: vue.js vuejs2

我正在尝试为子组件/功能组件的元素创建自定义事件处理程序。问题是,当使用render()函数创建子组件时,我无法访问它们的this上下文。

假设我们具有以下功能组件:

const Aggregate = {
    functional: true,
    props: {
        value: Object // to work with v-model
    },
    render: function(createElement, context){
        const template = []
        const inputHandler = function(value, prop){
            const data = Object.assign({}, context.props.value, { [prop]: value })
            console.log(context.props.value)
            console.log(data)
            this.$emit('input', data)
        }
        for (const prop of Object.keys(context.props.value)){
            const child = createElement('input', {
                props: {
                    value: context.props[prop]
                },
                on: {
                    input: function(event){
                        // 'this' is not binded here - it is undefined,
                        // hence the inputHandler() function is
                        // rising an error
                        inputHandler.apply(this, [event.target.value, prop])
                    }
                }
            })
            template.push(child)
        }
        return template
    }
}

以这种方式创建事件处理程序时,是否可以访问vnode的this上下文?

P.S。用例信息:我想实现一个组件,该组件可以自动为资源生成<input>元素,并通过v-model指令使用双向绑定。我还想在需要<table>包装的<td>中使用它,因此使组件起作用。

1 个答案:

答案 0 :(得分:2)

功能组件没有“ this”,因为它们没有Vue实例。这使它们轻巧。

这也意味着从事件中发出事件比较困难,因为您需要自己实现Vue的逻辑。

缺少实例并不意味着您无法进行事件,而是需要手动解析context.listeners并手动调用事件处理程序。对于v-model,您需要调用input侦听器:

const Aggregate = {
    functional: true,
    props: {
        value: Object // to work with v-model
    },
    render: function(createElement, context){
        const template = []
        const inputHandler = function(value, prop, handler){
            const data = Object.assign({}, context.props.value, { [prop]: value })
            console.log(context.props.value)
            console.log(data)
            // Call handler directly instead of using this.$emit
            handler(data)
        }
        for (const prop of Object.keys(context.props.value)){
        console.log(context.props.value, prop)
            const child = createElement('input', {
                // Small bug fixes in the following section:
                domProps: {
                    value: context.props.value[prop]
                },
                // End bug fixes
                on: {
                    input: function(event){
                        // pass `context.listeners.input` instead of binding here
                        inputHandler(event.target.value, prop, context.listeners.input)
                    }
                }
            })
            template.push(child)
        }
        return template
    }
}


new Vue({
  el: "#app",
  components: {
  	Aggregate
  },
  data: {
    test: {
    	key1: "val1",
    	key2: "val2",
      
    }
  },
})
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <aggregate  v-model="test"></aggregate>
  <pre>{{ test }}</pre>
  <button @click="test = {...test, ping: 'pong'}">Add key</button>
</div>

相关问题