我正在尝试为子组件/功能组件的元素创建自定义事件处理程序。问题是,当使用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>
中使用它,因此使组件起作用。
答案 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>