我正在研究一个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>
和main.js:
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
this.event = function (event) {
if (!(el === event.target || el.contains(event.target))) {
vnode.context[binding.expression](event)
}
}
document.body.addEventListener('click', this.event)
},
unbind: function (el) {
document.body.removeEventListener('click', this.event)
}
})
问题出在this.event = function (event) {
行中,因为错误显示Cannot set property 'event' of undefined
,所以未定义。
不知道如何在指令内部定义它。
我正在使用此示例来使其与我的自定义组件一起使用:https://jsfiddle.net/Linusborg/yzm8t8jq/ 我错过了什么吗? 更新:尽管我在vuejs 2.1 https://jsfiddle.net/y0rpfecd/中找到了一个类似的示例,但该示例中的代码来自vuejs 1.x,仍然出现相同的错误。
答案 0 :(得分:1)
您可能已经找到答案。希望有人觉得它有用。
我最近在辅助项目中测试了click-outside指令。 只需在指令代码中用window.event替换this.event即可。而且效果很好!
directive.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>