如何在 Vue 中显示包裹的 <input>?
How to expose wrapped <input> in Vue?
我正在尝试在 Vue 中创建一个可重复使用的样式输入字段。为了让它有样式(例如里面有一个图标)我需要把它包装在另一个 html-element.
让我们调用下面的例子StyledInput
<div class="hasIcon">
<input />
<i class="someIcon"></i>
<div>
如果我想使用 StyledInput
它可能看起来像这样:
<styled-input @keyup.enter="doSomething">
</styled-input>
但这行不通,因为事件侦听器附加到 <div>
而不是 <input>
。
一种解决方法是从输入字段发出所有按键事件:
<div class="hasIcon">
<input @keyup="$emit('keyup', $event) />
<i class="someIcon"></i>
<div>
但这不会很好地扩展,因为每次开发人员使用未映射的道具或事件时都必须重写它。
有没有办法只让内部元素暴露给使用它的人?
我不确定是否有 Vue
方法来实现这一点,因为据我所知,没有办法动态绑定 vue 事件,但是可以使用香草 javascript 通过将所有事件作为道具传递然后使用 addEventListener()
映射它们以添加您的自定义事件:
Vue.component('my-input', {
template: "#my-input",
props: ['events'],
mounted() {
// get the input element
let input = document.getElementById('styled-input');
// map events
this.events.forEach((event) => {
let key = Object.keys(event);
input.addEventListener(key, event[key]);
});
}
})
然后你就可以像这样把所有事件作为道具传递:
<my-input :events="events"></my-input>
查看模型:
var app = new Vue({
el: "#app",
data: {
events: [{
focus: () => {
console.log('focus')
}
}, {
keyup: (e) => {
console.log(e.which)
}
}]
}
})
这是 JSFiddle:https://jsfiddle.net/h1dnk40v/
当然,这意味着任何开发人员都必须执行映射键代码等操作,因此您将失去 Vue 提供的一些便利。
我要提到的一件事是 Vue components
不一定要无限重复使用,它们应该提供特定的功能并封装复杂的逻辑,因此您可能会更好地实现最可能的用例,如果组件不适合,您可以扩展它或为该特定事件编写一个新组件。
您可以使用 slots 来实现这一点。如果您的 <styled-input>
模板如下所示:
<div class="hasIcon">
<slot><input></slot>
<i class="someIcon"></i>
<div>
那么你可以这样使用它:
<styled-input>
<input @keyup.enter="doTheThing">
</styled-input>
或者,在您不关心输入事件的情况下,如下所示:
<styled-input></styled-input>
并且将使用默认插槽内容(裸 <input>
)。您可以使用 CSS 为组件内的 <input>
设置样式,但您不能向其添加自定义属性或 类,因此这种方法可能符合也可能不符合您的要求。
我正在尝试在 Vue 中创建一个可重复使用的样式输入字段。为了让它有样式(例如里面有一个图标)我需要把它包装在另一个 html-element.
让我们调用下面的例子StyledInput
<div class="hasIcon">
<input />
<i class="someIcon"></i>
<div>
如果我想使用 StyledInput
它可能看起来像这样:
<styled-input @keyup.enter="doSomething">
</styled-input>
但这行不通,因为事件侦听器附加到 <div>
而不是 <input>
。
一种解决方法是从输入字段发出所有按键事件:
<div class="hasIcon">
<input @keyup="$emit('keyup', $event) />
<i class="someIcon"></i>
<div>
但这不会很好地扩展,因为每次开发人员使用未映射的道具或事件时都必须重写它。
有没有办法只让内部元素暴露给使用它的人?
我不确定是否有 Vue
方法来实现这一点,因为据我所知,没有办法动态绑定 vue 事件,但是可以使用香草 javascript 通过将所有事件作为道具传递然后使用 addEventListener()
映射它们以添加您的自定义事件:
Vue.component('my-input', {
template: "#my-input",
props: ['events'],
mounted() {
// get the input element
let input = document.getElementById('styled-input');
// map events
this.events.forEach((event) => {
let key = Object.keys(event);
input.addEventListener(key, event[key]);
});
}
})
然后你就可以像这样把所有事件作为道具传递:
<my-input :events="events"></my-input>
查看模型:
var app = new Vue({
el: "#app",
data: {
events: [{
focus: () => {
console.log('focus')
}
}, {
keyup: (e) => {
console.log(e.which)
}
}]
}
})
这是 JSFiddle:https://jsfiddle.net/h1dnk40v/
当然,这意味着任何开发人员都必须执行映射键代码等操作,因此您将失去 Vue 提供的一些便利。
我要提到的一件事是 Vue components
不一定要无限重复使用,它们应该提供特定的功能并封装复杂的逻辑,因此您可能会更好地实现最可能的用例,如果组件不适合,您可以扩展它或为该特定事件编写一个新组件。
您可以使用 slots 来实现这一点。如果您的 <styled-input>
模板如下所示:
<div class="hasIcon">
<slot><input></slot>
<i class="someIcon"></i>
<div>
那么你可以这样使用它:
<styled-input>
<input @keyup.enter="doTheThing">
</styled-input>
或者,在您不关心输入事件的情况下,如下所示:
<styled-input></styled-input>
并且将使用默认插槽内容(裸 <input>
)。您可以使用 CSS 为组件内的 <input>
设置样式,但您不能向其添加自定义属性或 类,因此这种方法可能符合也可能不符合您的要求。