Помогите разобраться со vue.js, не срабатывает выделение текста
Подскажите почему не работает выделение. По клику на иконку like стоит обработчик события, который меняет like_status: с false на true. Но, ничего не происходит. При этом если вручную поставить true - все работает. Не могу понять, почему не срабатывает функция.
Vue.component('anegdotes', {
props: ['data'],
methods: {},
template: `
<ul class="list-jokes__list">
<li class="list-jokes__list-item">{{ data.joke }}<img class="like" src="https://img.icons8.com/ios/50/000000/thumb-up--v1.png" height="20px" @click="like_active()"></li>
</ul>
`,
});
const vue = new Vue({
el: '#app',
data: {
joke: '',
urlAnegdotes: 'https://v2.jokeapi.dev/joke/Any?type=single&amount=10',
anegdotes: [],
search: '',
like_status: false,
},
async mounted() {
try {
const response = await fetch(this.urlAnegdotes);
const content = await response.json();
const result = content.jokes;
this.anegdotes.push(...result);
} catch (error) {
console.error(error);
}
},
methods: {
like_active() {
if (!this.like_status) {
this.like_status = this.like_status = 'true';
}
}
},
computed: {
searchHandler() {
return this.anegdotes.filter(elem => {
return elem.joke.includes(this.search);
})
}
}
});
.list-jokes{
border: 1px solid black;
width: 400px;
margin: 50px auto;
background-color: rgb(247, 213, 175);
word-break: break-word;
position: relative;
}
.list-jokes__title{
background-color: rgb(255, 136, 0);
padding: 5px 10px;
margin-top: auto;
}
.list-jokes__list{
margin: 0;
padding: 0 0 10px 25px;
}
.list-jokes__list-item{
margin-bottom: 10px;
padding: 0 10px 0 10px;
}
.input-search{
font-size: 16px;
padding: 5px;
outline: none;
}
.button-search{
background-color: rgb(255, 136, 0);
border: none;
padding: 8px;
min-width: 100px;
cursor: pointer;
transition: .4s ease-in;
}
.like{
cursor: pointer;
}
.like-active {
background-color: green;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anegdotes</title>
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id='app' class="list-jokes">
<input class="input-search" type="search" placeholder="search for anecdote" v-model="search"
@search='searchHandler()'>
<h3 class="list-jokes__title">List of jokes</h3>
<anegdotes :data="data" v-for="(data, index) in searchHandler" :key="index"
:class="{ 'like-active' : like_status}" />
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="main.js"></script>
</body>
</html>
Ответы (1 шт):
Исправил все самые очевидные ошибки, добавил правильную связь с родительским компонентом (через событие), оставил странный вывод кучи <ul> с одним дочерним элементом, стили и грамматика тоже без изменений:
Vue.component('anegdotes', {
props: ['data'],
template: `
<ul class="list-jokes__list">
<li class="list-jokes__list-item">
{{ data.joke }}
<img class="like" src="https://img.icons8.com/ios/50/000000/thumb-up--v1.png" height="20px" @click="$emit('like', data.id)">
</li>
</ul>
`,
});
const vue = new Vue({
el: '#app',
data: {
urlAnegdotes: 'https://v2.jokeapi.dev/joke/Any?type=single&amount=10',
anegdotes: [],
search: '',
like_status: {},
},
computed: {
searchResults() {
return this.anegdotes.filter(elem => elem.joke.includes(this.search));
},
},
methods: {
onLike(id) {
if (!isFinite(+id)) return;
this.$set(this.like_status, id, !this.like_status[id]);
},
},
async mounted() {
try {
const response = await fetch(this.urlAnegdotes).then(r => r.json());
this.anegdotes = response.jokes.map(({ flags, ...rest }) => ({ ...rest }));
} catch (error) {
console.error(error);
}
},
});
.list-jokes {
border: 1px solid black;
width: 400px;
margin: 50px auto;
background-color: rgb(247, 213, 175);
word-break: break-word;
position: relative;
}
.list-jokes__title {
background-color: rgb(255, 136, 0);
padding: 5px 10px;
margin-top: auto;
}
.list-jokes__list { margin: 0; padding: 0 0 10px 25px; }
.list-jokes__list-item { margin-bottom: 10px; padding: 0 10px 0 10px; }
.input-search { font-size: 16px; padding: 5px; outline: none; }
.button-search {
background-color: rgb(255, 136, 0);
border: none;
padding: 8px;
min-width: 100px;
cursor: pointer;
transition: .4s ease-in;
}
.like { cursor: pointer; }
.like-active { background-color: green; }
<div id="app" class="list-jokes">
<input v-model="search" class="input-search" type="search" placeholder="search for anecdote">
<h3 class="list-jokes__title">List of jokes</h3>
<anegdotes v-for="item in searchResults" :key="item.id" :data="item" :class="{ 'like-active' : like_status[item.id] }" @like="onLike"></anegdotes>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
К сожалению, здесь в спиппете переносы внутри тегов ломают выполнение, так что атрибуты пришлось записать в одну строку.
Описание каждого из сделанных изменений не прикладываю, т.к. все они исправляют ошибки совершенные из-за нежелания внимательно читать/понимать оф.документацию Vue (ошибки от недостаточного усвоения теорчасти - не воспроизводятся, поэтому их подробный разбор будет бесполезным для сообщества). Но оставшийся после "чистки" код вполне минимален, и в нем не так трудно разобраться самостоятельно.