使用 Laravel Blade 模板与 Vue JS 和事件监听器

3

我正在使用Laravel自定义组件,例如,我有:

components/input.blade.php

<input type="text" class="rounded">

注意:这只是一个简单的例子,关键部分在于我想要重复使用由blade模板生成的HTML。

现在,我可以创建一个具有范围插槽的Vue组件:

js/components/Search.vue

<template>
  <div>
    <slot name="search-input" />
  </div>
</template>
<script>
  export default {
    methods: {
      focus() {
        console.log('focus input');
      }
    }
  }
</script>

// ... and registering the component
// among others 

Vue.component('search', require('js/components/Search'));
new Vue({
  el: '#vue_app'
});


现在很好,我可以按以下方式使用我的组件:
views/somepage.blade.php
<search>
  <template v-slot:search>
    <x-input>
  </template>
</search>

所有的工作都如预期一样, 然而正如你所看到的, 我有一个focus方法, 当焦点在刀片输入上时我希望触发它.

现在我无法做到这一点:

js/components/Search.vue

<template>
  <div>
    <slot name="search-input" @focus="focus" />
  </div>
</template>
<script>
  export default {
    methods: {
      focus() {
        console.log('focus input');
      }
    }
  }
</script>

但我可以做到这一点:

js/components/Search.vue

<template>
  <div>
    <div ref="search-container"><slot name="search-input" /></div>
  </div>
</template>
<script>
  export default {
    methods: {
      mounted() {
          this.$refs['search-container'].querySelector('input').addEventListener('focus', this.focus)
      },
      focus() {
        console.log('focus input');
      }
    }
  }
</script>

但我不确定在Vue组件中使用addEventListener是否是最佳方法。

是否有更好的方法来实现我想要做的事情?


所以在第二部分中,您正在挂载它并直接访问输入字段,这实际上是组件的一部分,因此它会起作用。那么您是要在页面呈现本身上获得焦点吗? - Adi
@Adi,它按预期工作,但是我只是在质疑这是否是最佳实践。对我来说,它感觉有点像一个变通方法。通常我会通过<a @click="doSomething()">绑定点击监听器,如果能有一种类似的方式来绑定包含在插槽中的元素就好了。 - Ian Jamieson
如果您不希望函数在初始渲染时运行,请使用<a @click="doSomething"> - kissu
2个回答

0

我的首选解决方案是利用作用域插槽及其插槽属性来传递方法。最终的解决方案将如下所示:

views/somepage.blade.php

<search>
  <template v-slot:default>
    <x-input @focus="slot.methods.focus">
  </template>
</search>

你可以看到我在引用插槽属性变量slot来访问我下面定义的变量。请注意,我传递了一个methods对象。将对象命名为methods只是我的个人偏好。必要时我决定同时添加methodsprops

js/components/Search.vue

<template>
  <div>
    <slot :methods="{ focus }" />
  </div>
</template>
<script>
  export default {
    methods: {
      focus() {
        console.log('focus input');
      }
    }
  }
</script>

0

不确定问题的具体情况,也许

this.$refs['search-container'].querySelector('input').addEventListener('focus', this.focus)

这个程序在生命周期方面有点异步,你可能需要将它包装在nextTick中。

this.$nextTick(() => {
  this.$refs['search-container'].querySelector('input').addEventListener('focus', this.focus)
})

顺便说一下,我认为这种添加监听器的方式没有问题。

此外,也可以尝试在这里建议使用@focus.native="focus"https://v2.vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components 因为可能由于hydration,需要一些时间才能将元素作为Vue节点可用,因此将其粘贴到本机焦点可能是解决方案。

不确定这些是否有效,但这是我拥有的两个想法。


感谢您的回复。我想大家的共识是以这种方式添加事件监听器是可以的。我的示例代码按预期工作。我只是在质疑添加事件监听器的风格。我相信这一定是一个常见的问题,因为我们想在Vue模板中使用样式化的Blade组件并将事件绑定到它们上面。 - Ian Jamieson
1
如上所述,对我来说看起来很好。 :D - kissu
我不确定我是否在正确的轨道上,但是你不能使用属性包将事件处理程序@click传递给刀片组件吗? - futureweb
@futureweb 我想那可能是正确的方向,但我不知道组件是否具有正确的上下文来触发正确的方法。 - Ian Jamieson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接