如何在Vue中公开包装的<input />?

时间:2016-11-25 10:02:26

标签: vue-component vue.js

我试图在Vue中创建可重用的样式输入字段。为了使它风格化(例如,里面有一个图标)我需要将它包装在另一个html元素中。

让我们调用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>

但是这不会很好地扩展,因为每次开发人员使用未映射的道具或事件时都必须重写。

有没有办法只让内部元素暴露给任何使用它的人?

2 个答案:

答案 0 :(得分:4)

我不确定是否有Vue方法可以实现这一点,因为据我所知,没有办法动态绑定vue事件,但是可以使用vanilla 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不一定是无限可重用的,它们应该提供特定的功能并封装复杂的逻辑,所以你可能会更好地实现最可能的用途如果组件不适合,您可以扩展它或为该特定事件写一个新组件。

答案 1 :(得分:0)

您可以使用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>的样式,但不能向其添加自定义属性或类,因此这种方法可能符合您的要求,也可能不符合您的要求。