Я не могу понять, как испустить событие из директивы
Это мой шаблон, где я пытаюсь вызвать метод:
<tooltip v-click-outside="clickEvent" v-on:emitedEvent="clickEvent"></tooltip>
Из v-click-outside="clickEvent" я получаю:
Property or method "clickEvent" is not defined on the instance but referenced during render.
Код:
export default {
data() {
return {
}
},
methods: {
clickEvent: function () {
console.log('click')
}
},
}
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.event = function (event) {
if (!(el.contains(event.target))) {
vnode.context.$emit('emitedEvent')
}
}
document.addEventListener('click', el.event)
},
unbind: function (el) {
document.removeEventListener('click', el.event)
},
})
Из v-on:emitedEvent я получаю:
Invalid handler for event "emitedEvent": got undefined
Давайте по-порядку. Насколько я понял, вы пытаетесь реализовать что-то наподобие всплывающих подсказок. А конкретно - их скрытие при клике где угодно, но не на них самих.
Подсказка у вас представлена компонентом <tooltip>
, что уже является ошибкой №1. Название компонента должно обязательно содержать дефис и, следовательно, состоять как минимум из двух слов, этим дефисом разделенных. На время представим, что ваш компонент называется <my-tooltip>
и пойдем дальше.
Property or method "clickEvent" is not defined on the instance but referenced during render.
Очевидно, что метод clickEvent
не определен. Но исходя из того куска кода, что прикрепили Вы, видно обратное. А из всего этого следует, что определен-то он определен, да определен не там, где надо. В процессе написания этого ответа выяснилось (в комментариях к вопросу), что так оно и есть. Вместо того, чтобы clickEvent
был методом того компонента, в котором <my-tooltip>
используется, вы сделали его методом самого <my-tooltip>
, что, собственно, и явилось ошибкой №2.
Ошибка №3 - архитектурная. Не столько ошибка даже, скорее просто излишество - код, который ошибку сам по себе не вызывает, но и смысловой нагрузки никакой не несет. Я говорю о вот этой части
<my-tooltip v-click-outside="clickEvent" ...>
Конкретно в Вашем случае нет абсолютно никакой необходимости передавать функцию обратного вызова директиве в качестве аргумента. Обычно эта возможность используется для какой-то настройки, передачи каких-то параметров. В вашем же случае можно обойтись без нее.
4-ой ошибкой и, я бы сказал, решающей, является то, что вы пытаетесь выбросить событие на root
элементе приложения. Обращаясь к vNode.context
вы обращаетесь не к самому компоненту <my-tooltip>
, а к главному инстансу приложения (скорее всего, не факт на самом деле), который обычно имеет id app
(или что-то в этом духе). Вместо этого событие должно выбрасываться на том компоненте, на котором оно ловится. Поэтому если у вас написано <my-tooltip @myEvent="hideMe">
, то и $emit
должен вызываться именно на инстансе компонента <my-tooltip>
.
Логичным будет вопрос "а как?". Спасибо Эвану, он предусмотрел возможную необходимость поиска компонента и услужливо добавил объекту vNode
свойство componentInstance
. Исходя из вышесказанного выброс события должен выглядеть как vNode.componentInstance.$emit("myEvent")
.
Все ваши ошибки я исправил и создал для вас JSFiddle. Ниже то же самое (возможно даже когда-нибудь будет с комментариями), но в виде сниппета.
Vue.directive("click-outside", {
bind(el, binding, vNode) {
document.addEventListener("click", (event) => {
if (event.target !== el) {
vNode.componentInstance.$emit("clickedout");
}
});
}
});
Vue.component("my-tooltip", {
template: "<div><slot></slot></div>"
});
new Vue({
el: "#app",
data: {},
methods: {
hide() {
console.log("Hiding the toooltip...");
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-tooltip id="tooltip" v-click-outside @clickedout="hide">Click outside!</my-tooltip>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit dolor placeat, exercitationem earum voluptatem labore. Ducimus repellendus incidunt eum at, accusantium dolor, aperiam ea rerum amet inventore numquam vel illum.
</div>
Важно: обратите внимание, что @clickedout
здесь нечувствителен к регистру (как и все остальное в HTML, собственно). Поэтому, выбрасывая в своем коде myEvent
вы на самом деле, согласно договоренностям Vue, должны ловить не @myEvent
, а @my-event
, если я правильно помню все их соглашения. Возможно, это даже явилось 5-ой ошибкой, но жирным выделять не буду, поскольку неуверен. Общее правило таково, что имя выбрасываемого события в идеале должно быть написано в одно слово и только маленькими буквами (типа как нативные mouseout
, mousedown
и т.п.).
И в конце хотелось бы добавить, что данная логика в целом будет является относительно жизнеспособной только при том условии, что сама подсказка у вас периодически на странице то появляется, то исчезает, но уж никак не находится на ней постоянно. Потому как в этом случае на документе будет постоянно висеть обработчик события, реагирующий на любой клик на этом документе, что уже само по себе является далеко не лучшей практикой.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Всем привет! Сначала были проблемы с фоном, но после множества попыток, я смог зафиксировать фон, чтобы он не сменялся после обновления или...
Помогите найти пожалуйста доступное определение термина pattern
Я использую вот такой код для ограничения вращения камеры