Vue не регистрирует обработчик событий для объектов, внедренных в HTML. Как мне сделать это вручную или как лучше обойти мою проблему?
В частности, я отправляю запрос на свой сервер, чтобы найти токен в тексте и вернуть контекст (окружающий текст) этого токена в том виде, в каком он существует на неструктурированном естественном языке. Сервер также просматривает контекст и находит список тех слов, которые также встречаются в моем наборе токенов.
Когда я отображаю свою страницу, я хочу, чтобы все эти найденные токены в списке можно было щелкнуть, чтобы я мог отправить текст этого токена в качестве нового поискового запроса. Большая проблема, с которой я сталкиваюсь, заключается в том, что моя проблема не соответствует шаблону. Кликабельный текст различается по количеству и расположению.
Пример того, о чем я говорю, это то, что мое возвращение может выглядеть так:
{
"context": "When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected",
"chunks": ['human events', 'one people', 'political bands']
}
И результат, который я ищу, выглядит примерно так в псевдокоде:
When in the Course of <a @click='search("human events")'>human events</a>, it becomes necessary for <a @click='search("one people")'>one people</a> to dissolve the <a @click='search("political bands")'>political bands</a> which have connected
Это то, что я пробовал до сих пор, хотя обработчик кликов не зарегистрирован, и функция никогда не вызывается:
<v-flex xs10 v-html = "addlink(context.context, context.chunks)"></v-flex>
и в разделе моих методов:
addlink: function(words, matchterms){
for(var index in matchterms){
var regquery = matchterms[index].replace(this.regEscape, '\\$&');
var query = matchterms[index];
var regEx = new RegExp(regquery, "ig");
words = words.replace(regEx, '<a href=\'#\' v-on:click.prevent=\'doSearch("'+ query +'")\'>' + query + '</a>');
}
return words;
}
Как я уже сказал, это не работает, и я знаю, почему. Это просто показывает, что из-за характера проблемы кажется, что регулярное выражение является правильным решением, но это приводит меня к ситуации с внедрением v-html. Есть ли что-то, что я могу сделать в Vue, чтобы зарегистрировать обработчики событий, или кто-нибудь может сказать мне лучший способ загрузки этих данных, чтобы я сохранял свои ссылки в соответствии с предложением и делал их функциональными?
Вот один из способов, которым вы могли бы подойти к этому:
<template>
<div>
<template v-for = "segment in textSegments">
<a v-if = "segment.link" href = "#" @click.prevent = "search(segment.text)">
{{ segment.text }}
</a>
<template v-else>
{{ segment.text }}
</template>
</template>
</div>
</template>
<script>
export default {
data () {
return {
"context": "When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected",
"chunks": ['human events', 'one people', 'political bands']
}
},
computed: {
textSegments () {
const chunks = this.chunks
// This needs escaping correctly
const re = new RegExp('(' + chunks.join('|') + ')', 'gi')
// The filter removes empty strings
const segments = this.context.split(re).filter(text => text)
return segments.map(segment => {
return {
link: segment.match(re),
text: segment
}
})
}
},
methods: {
search (chunk) {
console.info(chunk)
}
}
}
</script>
Я проанализировал текст контекста в массив сегментов, которые затем можно аккуратно обработать, используя синтаксис шаблона Vue.
Я использовал одно регулярное выражение и split
, которые не будут отбрасывать совпадения, если вы поместите их в группу захвата, (...)
.
Возвращаясь к вашему исходному примеру, v-html
поддерживает только собственный HTML, а не синтаксис шаблона Vue. Таким образом, вы можете добавлять события, используя атрибуты onclick
, но не @click
или v-on:click
. Однако использование onclick
не обеспечит легкого доступа к вашему методу search
, область действия которого ограничена вашим компонентом.
Я уже опубликовал один ответ, но только что понял, что есть совершенно другой подход, который может работать в зависимости от ваших обстоятельств.
Вы можете использовать делегирование событий. Таким образом, вместо того, чтобы помещать прослушиватели кликов на каждый элемент <a>
, вы можете поместить один прослушиватель на элемент-оболочку. Затем в слушателе вы можете проверить, был ли щелкнутый элемент <a>
(используя event.target
), и действовать соответствующим образом.
Мне очень нравится, как это было решено. Я сделал это немного по-другому в своей реализации из-за моей структуры кода, но это определенно послужило источником вдохновения для решения, которое я в конечном итоге реализовал. Я решил сделать немного больше обработки данных, когда я получаю данные, и сохранил v-if/v-else на странице html (я не настраиваю настоящее приложение Vue). Спасибо за решение!