Работа с фронтендом
В первую очередь нам нужна страница, на которую будет выводиться список постов. Для этого создадим новый вид – index.blade.php (папка resources/views). Его содержимое должно быть следующим:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/css/app.css">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
<div id="app" class="container">
<h1 class="text-center mt-3">Рейтинг постов</h1>
<div class="row">
<article v-for="post in sortedPosts"
:key="post.id"
class="col-sm-8 offset-sm-2 mb-3">
<voting
:post="post"
:posts="posts"
:class="{ 'border border-success': post.votes >= 30 }"
action="/api/@{{ post.id }}/vote">
</voting>
</article>
</div>
</div>
<script src="/js/app.js"></script>
</body>
</html>
В строчке
<article v-for="post in sortedPosts"
через цикл выводятся все посты. Цикл осуществляется с помощью Vue.js.
В следующей строчке в качестве ключа указываем поле id каждого поста. Ключ рекомендуется всегда использовать с v-for, но в данном примере можно обойтись и без него.
Далее у нас идет компонент с именем voting.
<voting
:post="post"
:posts="posts"
:class="{ 'border border-success': post.votes >= 30 }">
</voting>
Здесь есть 2 входящих параметра: post и posts, а также директива :class для автоматического добавления css-классов рамки вокруг поста (border и border-success). Как уже говорилось в самом начале, рамка будет появляться, если пост наберет 30 голосов.
Теперь нам нужно установить шрифты fontawesome, vue и bootstrap. Для этого воспользуемся следующими командами:
npm install --save-dev @fortawesome/fontawesome-free
composer require laravel/ui --dev
php artisan ui vue
npm install
Теперь отредактируем файл resources/js/app.js.
Найдем строчку:
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
и заменим ее на следующую:
Vue.component('voting', require('./components/Voting.vue').default);
В этой строчке мы регистрируем свой компонент из файла Voting.vue. Этот файл мы создадим позже.
Далее в файле app.js расположен блок кода:
const app = new Vue({
el: '#app',
});
В этом блоке создается новое Vue-приложение и привязывается к веб-странице. В этот блок мы должны добавить дополнительный код и в результате должно получиться следующее:
const app = new Vue({
el: '#app',
data: {
posts: [],
},
created: function() {
this.read();
},
methods: {
read() {
axios.get('/api/posts').then(({ data }) => {
this.posts = data;
});
},
},
computed: {
sortedPosts() {
return this.posts.sort((a, b) => {
return b.votes - a.votes
});
}
}
});
Здесь в методе read() мы получаем посты с сервера, с помощью axios, сразу после создания экземпляра Vue (хук created). В вычисляемом свойстве sortedPosts мы сортируем посты по количеству голосов. Напоминаю, что свойство sortedPosts используется в ранее созданном виде index.blade.php (папка resources/views) для вывода списка постов на страницу.
Осталось создать файл Voting.vue для компонента voting.
В папке resources/js/components создадим новый файл Voting.vue. Его содержимое должно быть следующим:
<template>
<div class="card">
<div class="card-header">
<a href="">
{{ post.title }}
</a>
<span style="cursor: pointer" class="float-right"
@click="vote(post.id)">
<i class="fas fa-angle-up"></i>
<strong style="color: #3273dc">{{ post.votes }}</strong>
</span>
</div>
<div class="card-body">
{{ post.body}}
</div>
</div>
</template>
<script>
export default {
props: ['post', 'posts'],
methods: {
vote(id) {
axios.post("/api/"+id+"/vote");
const post = this.posts.find(
post => post.id === id
);
post.votes++;
}
}
}
</script>
Здесь в шаблоне по нажатию на span осуществляется вызов функции vote(id). В которой происходит инкрементация количества голосов поста как на сервере (с помощью axios) так и у клиента (Vue-свойство post).
На этом все. Осталось запустить команду для компиляции изменений:
npm run dev