【问题标题】:'this' context in functional component's child event handler功能组件的子事件处理程序中的“this”上下文
【发布时间】:2019-04-15 07:25:13
【问题描述】:

我正在尝试为功能组件的子组件/元素创建自定义事件处理程序。问题是当使用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 上下文?

附:用例信息:我想实现一个为资源自动生成<input> 元素并通过v-model 指令使用双向绑定的组件。我还想在<table> 中使用它,其中需要在<td> 中进行包装,因此我使组件功能化。

【问题讨论】:

    标签: vue.js vuejs2


    【解决方案1】:

    功能组件没有“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>

    【讨论】:

    • 感谢您的快速回复。您提供的修复程序完成了这项工作。无论如何,根据文档,context.listeners一个包含父注册事件侦听器的对象。正如我正确理解的那样,在我们的例子中,父元素是&lt;div id="app"&gt; 元素,它没有在代码中分配任何事件侦听器。那么它是如何工作的呢?
    • context.listeners&lt;aggregate&gt; 的听众。 Vue 更改了v-model="test" to :value="test" @input="test = $event" 你的听众比包含:{ input: Function } (在控制台中打印出上下文,你可以看到里面还有什么)
    猜你喜欢
    • 1970-01-01
    • 2011-07-26
    • 2020-09-18
    • 2017-06-14
    • 2015-06-26
    • 2017-09-09
    • 2016-08-13
    • 2023-03-24
    • 2013-06-26
    相关资源
    最近更新 更多