Vuejs2 在外部单击“不工作”时关闭的VueJs 2自定义指令
我正在开发一个vuejs组件,如果在单击组合框后单击它的外部,它应该会关闭 我的问题是自定义指令不起作用,程序会编译,但在浏览器中出现以下错误: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
[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示例中,这是一个全局窗口
伟大而干净的解决方案!