Vuejs2 在外部单击“不工作”时关闭的VueJs 2自定义指令

Vuejs2 在外部单击“不工作”时关闭的VueJs 2自定义指令,vuejs2,Vuejs2,我正在开发一个vuejs组件,如果在单击组合框后单击它的外部,它应该会关闭 我的问题是自定义指令不起作用,程序会编译,但在浏览器中出现以下错误: [Vue warn]: Error in directive click-outside bind hook: "TypeError: Cannot set property 'event' of undefined" 这是我的组件的代码: <template> <div class="form-group" v-click-o

我正在开发一个vuejs组件,如果在单击组合框后单击它的外部,它应该会关闭

我的问题是自定义指令不起作用,程序会编译,但在浏览器中出现以下错误:

[Vue warn]: Error in directive click-outside bind hook: "TypeError: Cannot set property 'event' of undefined"
这是我的组件的代码:

<template>
  <div class="form-group" v-click-outside="hide">
  <label v-if="label" for="combobox" class="control-label" v-tack>{{ label }}:</label>
    <input id="combobox"
    class="form-control combo-box-control"
    v-on:keyup="filter(searchText,options)"
    v-model="searchText"
    :placeholder="placeholder"
    v-on:click="showAllOptions()" :disabled="isDisabled">
        <template v-if="showAutocomplete">
        <div class="combobox-list">
            <p class="combobox-options" :key="item.id" v-for="item in listFiltered" v-on:click="optionSelected(item)">{{item.text}}</p>
        </div>
        </template>
  </div>
</template>
<script>
export default {
  data () {
    return {
      listFiltered: [],
      searchText: '',
      showAutocomplete: false
    }
  },
  props: {
    name: { type: String, required: true },
    options: Array,
    label: String,
    isDisabled: { type: Boolean, default: false },
    selectedOption: Object,
    placeholder: String
  },
  methods: {
    filter (word, array) {
      if (word === undefined) {
        this.showAutocomplete = false
        this.listFiltered = []
        return
      }
      this.showAutocomplete = true
      this.listFiltered = array.filter(function (item) {
        return item.text.toLowerCase().includes(word.toLowerCase())
      })
    },
    optionSelected (item) {
      this.searchText = item.text
      this.showAutocomplete = false
      if (item !== undefined) {
        this.$emit('change', { name: this.name, item: item })
      }
    },
    showAllOptions () {
      this.listFiltered = this.options
      this.showAutocomplete = !this.showAutocomplete
    },
    hide () {
      this.showAutocomplete = false
    }
  }
}
</script>
<style>
.form-group{
    position:relative;
}
.form-group input{
    width:100%;
}

input.combo-box-control:active{
  border-style: solid;
  border-width: 1px 1px 0 1px;
  border-radius: 5px 5px 0px 0px;
  border-color: #96c8da;
}

.form-control.combo-box-control:focus{
  border-color: #96c8da;
}

.combobox-list{
    position:relative;
    height:154px;
    width:100%;
    background-color:white;
    overflow-y:auto;
    text-align:justify;
    z-index: 5;
    border-style: solid;
    border-color: #96c8da;
    border-width: 0 1px 1px 1px;
    border-radius: 0px 0px 5px 5px;
    top: -3px;
}

.combobox-options{
    padding:6px 0;
    margin:0;
}
.combobox-options:hover{
    background-color:#d9d9d9;
}
</style>
问题出在
this.event=function(event){
行中,因为错误说明
无法设置未定义的属性“event”,所以这是未定义的。
不知道如何在指令中定义它

<template>
  <div class="form-group" v-click-outside="hide">
  <label v-if="label" for="combobox" class="control-label" v-tack>{{ label }}:</label>
    <input id="combobox"
    class="form-control combo-box-control"
    v-on:keyup="filter(searchText,options)"
    v-model="searchText"
    :placeholder="placeholder"
    v-on:click="showAllOptions()" :disabled="isDisabled">
        <template v-if="showAutocomplete">
        <div class="combobox-list">
            <p class="combobox-options" :key="item.id" v-for="item in listFiltered" v-on:click="optionSelected(item)">{{item.text}}</p>
        </div>
        </template>
  </div>
</template>
<script>
import clickOutside from '../directive';
export default {
  data () {
    return {
      listFiltered: [],
      searchText: '',
      showAutocomplete: false
    }
  },
  props: {
    name: { type: String, required: true },
    options: Array,
    label: String,
    isDisabled: { type: Boolean, default: false },
    selectedOption: Object,
    placeholder: String
  },
  methods: {
    filter (word, array) {
      if (word === undefined) {
        this.showAutocomplete = false
        this.listFiltered = []
        return
      }
      this.showAutocomplete = true
      this.listFiltered = array.filter(function (item) {
        return item.text.toLowerCase().includes(word.toLowerCase())
      })
    },
    optionSelected (item) {
      this.searchText = item.text
      this.showAutocomplete = false
      if (item !== undefined) {
        this.$emit('change', { name: this.name, item: item })
      }
    },
    showAllOptions () {
      this.listFiltered = this.options
      this.showAutocomplete = !this.showAutocomplete
    },
    hide () {
      this.showAutocomplete = false
    }
  }
}
</script>
<style>
.form-group{
    position:relative;
}
.form-group input{
    width:100%;
}

input.combo-box-control:active{
  border-style: solid;
  border-width: 1px 1px 0 1px;
  border-radius: 5px 5px 0px 0px;
  border-color: #96c8da;
}

.form-control.combo-box-control:focus{
  border-color: #96c8da;
}

.combobox-list{
    position:relative;
    height:154px;
    width:100%;
    background-color:white;
    overflow-y:auto;
    text-align:justify;
    z-index: 5;
    border-style: solid;
    border-color: #96c8da;
    border-width: 0 1px 1px 1px;
    border-radius: 0px 0px 5px 5px;
    top: -3px;
}

.combobox-options{
    padding:6px 0;
    margin:0;
}
.combobox-options:hover{
    background-color:#d9d9d9;
}
</style>
我使用此示例使其与我的自定义组件一起工作: 我错过什么了吗?
更新:发现示例中的代码来自vuejs 1.x,虽然我在vuejs 2.1中发现了类似的示例,但仍然会出现相同的错误。

您可能已经找到了答案。希望有人觉得它有用

我最近在我的侧项目中测试了clickoutside指令。 只需在指令代码中将this.event替换为window.event,它就能完美工作

指令.js

import Vue from 'vue';

Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
        window.event = function (event) {
            if (!(el == event.target || el.contains(event.target))) {
                vnode.context[binding.expression](event);
            }
        };
        document.body.addEventListener('click', window.event)
    },
    unbind: function (el) {
        document.body.removeEventListener('click', window.event)
    },
});
要在组件中使用:只需导入指令

<template>
  <div class="form-group" v-click-outside="hide">
  <label v-if="label" for="combobox" class="control-label" v-tack>{{ label }}:</label>
    <input id="combobox"
    class="form-control combo-box-control"
    v-on:keyup="filter(searchText,options)"
    v-model="searchText"
    :placeholder="placeholder"
    v-on:click="showAllOptions()" :disabled="isDisabled">
        <template v-if="showAutocomplete">
        <div class="combobox-list">
            <p class="combobox-options" :key="item.id" v-for="item in listFiltered" v-on:click="optionSelected(item)">{{item.text}}</p>
        </div>
        </template>
  </div>
</template>
<script>
import clickOutside from '../directive';
export default {
  data () {
    return {
      listFiltered: [],
      searchText: '',
      showAutocomplete: false
    }
  },
  props: {
    name: { type: String, required: true },
    options: Array,
    label: String,
    isDisabled: { type: Boolean, default: false },
    selectedOption: Object,
    placeholder: String
  },
  methods: {
    filter (word, array) {
      if (word === undefined) {
        this.showAutocomplete = false
        this.listFiltered = []
        return
      }
      this.showAutocomplete = true
      this.listFiltered = array.filter(function (item) {
        return item.text.toLowerCase().includes(word.toLowerCase())
      })
    },
    optionSelected (item) {
      this.searchText = item.text
      this.showAutocomplete = false
      if (item !== undefined) {
        this.$emit('change', { name: this.name, item: item })
      }
    },
    showAllOptions () {
      this.listFiltered = this.options
      this.showAutocomplete = !this.showAutocomplete
    },
    hide () {
      this.showAutocomplete = false
    }
  }
}
</script>
<style>
.form-group{
    position:relative;
}
.form-group input{
    width:100%;
}

input.combo-box-control:active{
  border-style: solid;
  border-width: 1px 1px 0 1px;
  border-radius: 5px 5px 0px 0px;
  border-color: #96c8da;
}

.form-control.combo-box-control:focus{
  border-color: #96c8da;
}

.combobox-list{
    position:relative;
    height:154px;
    width:100%;
    background-color:white;
    overflow-y:auto;
    text-align:justify;
    z-index: 5;
    border-style: solid;
    border-color: #96c8da;
    border-width: 0 1px 1px 1px;
    border-radius: 0px 0px 5px 5px;
    top: -3px;
}

.combobox-options{
    padding:6px 0;
    margin:0;
}
.combobox-options:hover{
    background-color:#d9d9d9;
}
</style>

{{label}}:

{{item.text}

从“../directive”导入clickOutside; 导出默认值{ 数据(){ 返回{ listFiltered:[], 搜索文本:“”, showAutocomplete:错误 } }, 道具:{ 名称:{type:String,必需:true}, 选项:阵列, 标签:字符串, isDisabled:{type:Boolean,默认值:false}, selectedOption:Object, 占位符:字符串 }, 方法:{ 过滤器(字、数组){ 如果(单词===未定义){ this.showAutocomplete=false this.listFiltered=[] 返回 } this.showAutocomplete=true this.listFiltered=array.filter(函数(项){ return item.text.toLowerCase().includes(word.toLowerCase()) }) }, 选择的选项(项目){ this.searchText=item.text this.showAutocomplete=false 如果(项目!==未定义){ this.$emit('change',{name:this.name,item:item}) } }, showAllOptions(){ this.listFiltered=this.options this.showAutocomplete=!this.showAutocomplete }, 隐藏(){ this.showAutocomplete=false } } } .表格组{ 位置:相对位置; } .表格组输入{ 宽度:100%; } 输入。组合框控件:活动{ 边框样式:实心; 边框宽度:1px 1px 0 1px; 边界半径:5px 5px 0px 0px; 边框颜色:#96c8da; } .窗体控件.组合框控件:焦点{ 边框颜色:#96c8da; } .组合框列表{ 位置:相对位置; 高度:154px; 宽度:100%; 背景色:白色; 溢出y:自动; 文本对齐:对齐; z指数:5; 边框样式:实心; 边框颜色:#96c8da; 边框宽度:0 1px 1px 1px; 边界半径:0px 0px 5px 5px; 顶部:-3px; } .组合框选项{ 填充:6px0; 保证金:0; } .组合框选项:悬停{ 背景色:#d9d9d9; }
如果要在多个组件中重复使用此指令(可能这就是为什么要将其作为指令的原因),您可能希望有一个单独的事件处理程序,而不是每个组件都有一个单独的处理程序。在这种情况下,您可以将对处理程序的引用存储为静态变量。@StephenThomas当然,我只是想测试该指令,而不必为其创建另一个文件并在组件中导入该指令。好吧,正如您已经scovered,指令不能访问组件,只能访问DOM元素。这是指令的主要目的。因此,在指令挂钩中确实没有定义
这个
。为了进行测试,您可以在模块中定义一个静态全局变量,并用它来存储对处理程序的引用。@StephenThomas How is possiblee对于我发布的示例是否有效?因为在Vue2示例
中,这是一个全局
窗口
伟大而干净的解决方案!