カスタムイベントを発行することは可能ですかfromディレクティブinこのディレクティブがアタッチされるコンポーネント。
例で説明したように動作することを期待していましたが、動作しません。
例:
_//Basic Directive
<script>
Vue.directive('foo', {
bind(el, binding, vnode) {
setTimeout(() => {
//vnode.context.$emit('bar'); <- this will trigger in parent
vnode.$emit('bar');
}, 3000);
}
});
</script>
//Basic Component
<template>
<button v-foo @bar="change">{{label}}</button>
</template>
<script>
export default{
data() {
return {
label: 'i dont work'
}
},
methods: {
change() {
this.label = 'I DO WORK!';
}
}
}
</script>
_
この件について何か考えはありますか?何か不足していますか?
JSFiddle: https://jsfiddle.net/0aum3osq/4/
更新1:
さて、ディレクティブでvnode.data.on.bar.fn();
(またはfns()
in latest Vue versions)を呼び出すと、bar
イベントハンドラーがトリガーされることがわかりました。
更新2:
一時的な解決策:
_ /*temp. solution*/
var emit = (vnode, name, data) => {
var handlers = vnode.data.on;
if (handlers && handlers.hasOwnProperty(name)) {
var handler = handlers[name];
var fn = handler.fns || handler.fn;
if (typeof fn === 'function') {
fn(data);
}
}
}
//Basic Directive
<script>
Vue.directive('foo', {
bind(el, binding, vnode) {
setTimeout(() => {
emit(vnode, 'bar');
}, 3000);
}
});
</script>
_
したがって、Vue 2+)で使用している解決策(これまでに回答がなかった場合):
ディレクティブのaddメソッド:
var emit = (vnode, name, data) => {
var handlers = (vnode.data && vnode.data.on) ||
(vnode.componentOptions && vnode.componentOptions.listeners);
if (handlers && handlers[name]) {
handlers[name].fns(data);
}
}
そしてそれをこのように呼びます:
bind(el, binding, vnode) {
emit(vnode, 'bar' , {some: 'event', data: 'here'});
}
アプローチの利点:
1プロジェクトで同じコードスタイルを維持します。つまり、すべてのハンドラーを次のように宣言できます。v-on:handler_name
および(開発者にとって)意味のある方法で処理されます。パラメータとしてコールバックを送信するなど、他の解決策は時々混乱し、ドキュメント/コードを掘り下げない限り明白ではありません。
2組み込みのイベントシステムを使用すると、イベントオブジェクトを適切に処理することもできます。たとえば、次のコードは完全に正常に動作します。
<button v-foo @bar="bar(1, $event, 2)">{{label}}</button>
...
methods: {
bar(one, event, two) { console.log(one, event, two); }
}
編集:
V2.1 +では、この内部ディレクティブバインディングを使用できます。
vnode.context.$emit(eventname)
あなたの解決策は私のために働いていませんでした。実際、vnode.data.onは常に未定義でした
イベントをトリガーするために機能したのは
vnode.child.$emit('myevent');
お役に立てれば。
上記の回答はすばらしいですが、一部は古くなっています。これらを実行可能なPOCに統合して問題を解決する方法は次のとおりです。
_// src/directives/ClickOutside.js
export default {
stopProp(e) {
e.stopPropagation();
},
bind(el, binding, vnode) {
el._clickOutside = e => {
vnode.context.$emit(binding.expression, e);
};
el.addEventListener('click', binding.def.stopProp);
document.body.addEventListener('click', el._clickOutside);
},
unbind() {
if (!el._clickOutside) {
return;
}
el.removeEventListener('click', binding.def.stopProp);
document.body.removeEventListener('click', el._clickOutside);
delete el._clickOutside;
}
};
// src/directives/index.js
import Vue from 'vue';
import ClickOutside from './ClickOutside';
Vue.directive('ClickOutside', ClickOutside);
_
Main.jsにディレクティブをインポートします。
_// src/main.js
import './directives';
_
Vueコンポーネントでイベント発行をリッスンしてディレクティブを使用します:
_// src/components/Component.vue
<template>
<!-- Please fill in sensible context. This example doesn't really care about the DOM presentation -->
<div @click="showElement" v-click-outside="hideElement">
<div v-if="shouldShow">Hello</div>
</div>
</template>
<script>
export default {
data() {
return {
shouldShow: true
};
},
mounted() {
this.$on('hideElement', this.hideElement);
},
destroyed() {
this.$off('hideElement', this.hideElement);
},
methods: {
showElement() {
this.shouldShow = true;
},
hideElement() {
this.shouldShow = false;
}
}
};
</script>
_
基本的に、_vnode.context.$emit
_では、_binding.expression
_は、_v-close-outside
_で宣言した文字列(この例では「hideElement」)です。ディレクティブからエミッションを取得するには、this.$on('hideElement')
を使用してそれをリッスンします。
私はそれが古い問題であることを知っていますが、誰かがこれに問題があり、それが機能していない場合。 JavaScriptカスタムイベントイベントを使用できます。
vue.directive('click',{bind(el, binding, vnode) {
el.addEventListener('click', (e)=>{
const event = new CustomEvent('customevent', {detail: {
custom: "data",
can: "be",
in: "detail property"}, bubbles: true});
el.dispatchEvent(event);
})
}
})
今、私はそれを次のように使うことができます
<div v-click @customevent="func">hello world</div>
デフォルトは最後のパラメータとして発行される標準であるため、$event
を設定する必要はありません。このイベントにはdetail
プロパティがあり、この場合、このオブジェクトのカスタムデータが含まれています。
{custom: "data",
can: "be",
in: "detail property"}
カスタムのネイティブJavaScriptイベントを発行できます。 node.dispatchEventを使用して、ノードからイベントをディスパッチするディレクティブを作成します
let handleOutsideClick;
Vue.directive('out-click', {
bind (el, binding, vnode) {
handleOutsideClick = (e) => {
e.stopPropagation()
const handler = binding.value
if (el.contains(e.target)) {
el.dispatchEvent(new Event('out-click')) <-- HERE
}
}
document.addEventListener('click', handleOutsideClick)
document.addEventListener('touchstart', handleOutsideClick)
},
unbind () {
document.removeEventListener('click', handleOutsideClick)
document.removeEventListener('touchstart', handleOutsideClick)
}
})
このように使用できます
h3( v-out-click @click="$emit('show')" @out-click="$emit('hide')" )